can you please provide a working fixture of this form:
user = User()
occupations = [Occupation(title='o1'), Occupation(title='o2'),
Occupation(title='o3')]
interests = [Interest(name='i1'), Interest(name='i2'), Interest(name='i3')]
user.interests['i1'] = interests[0]
occupations[0].interests['i1'] = interests[0]
def get_distance(occupation, user):
d_max = Decimal(math.sqrt(6 ** 3))
d_squared = 0
for i in interests:
d_squared += (user.interests[i.name] - occupation.interests[i.name]) **
2
d = Decimal(math.sqrt(d_squared))
return (d_max - d) / d_max
distances = [
dict(
name=o.title,
distance=get_distance(o, user),
) for o in occupations
]
it seems that user.interests is meant to refer to Interest objects but these do
not implement the __sub__() operator so I can't get as far as your example. I
have no idea what the issue is without being able to run / pdb into it. No
database connection is needed unless that's required to reproduce the issue,
thanks.
On Mar 11, 2014, at 3:45 PM, Brian Findlay <[email protected]> wrote:
> Hi,
>
> Running python 3.3.4, pyramid 1.5b1, sqlalchemy 0.9.3.
>
> A couple of months ago Mike helped to set up composite association proxies in
> my model
> (https://groups.google.com/forum/#!searchin/sqlalchemy/composite$20association$20object/sqlalchemy/kxU-FaDGO2Q/b8ScnTXvPyIJ).
> I'm applying this pattern to a different project now, but running into
> problems when using a list comprehension to create a list of dict objects
> from the results of a query. I suspect the problem stems from (a) two
> association proxies using the same attribute mapped collection or (b) garbage
> collection creating stale association proxies...
>
> The basic model looks something like this:
>
> class User(Base):
> __tablename__ = 'users'
>
> # Columns
> id = Column(Integer, primary_key=True)
> name = Column(VARCHAR(50), nullable=False)
>
> # Relationships
> interests = association_proxy(
> 'user_interests',
> 'value',
> creator=lambda k, v: UserInterest(interest_name=k, value=v)
> )
> ...
>
> class Occupation(Base):
> __tablename__ = 'occupations'
>
> # Columns
> id = Column(Numeric(8, 2), primary_key=True)
> title = Column(VARCHAR(150), nullable=False)
>
> # Relationships
> interests = association_proxy(
> 'occupation_interests',
> 'value',
> creator=lambda k, v: OccupationInterest(interest_name=k, value=v)
> )
> ...
>
> class Interest(Base):
> __tablename__ = 'interests'
>
> # Columns
> id = Column(Integer, primary_key=True)
> name = Column(String, unique=True)
>
>
> # Composite association proxies linking the tables
>
> class UserInterest(Base):
> __tablename__ = 'user_interests'
>
> # Columns
> user_id = Column(ForeignKey('users.id'), primary_key=True)
> interest_id = Column(ForeignKey('interests.id'), primary_key=True)
> value = Column(Numeric(3, 2))
>
> # Relationships
> user = relationship(
> 'User',
> backref=backref(
> 'user_interests',
> collection_class=attribute_mapped_collection('interest_name'),
> cascade='all, delete-orphan'
> )
> )
> interest = relationship('Interest')
>
> def __init__(self, interest_name, value):
> self._interest_name = interest_name
> self.value = value
>
> @property
> def interest_name(self):
> if self.interest is not None:
> return self.interest.name
> else:
> return self._interest_name
> ...
>
> class OccupationInterest(Base):
> __tablename__ = 'occupation_interests'
>
> # Columns
> occupation_id = Column(ForeignKey('occupations.id'), primary_key=True)
> interest_id = Column(ForeignKey('interests.id'), primary_key=True)
> value = Column(Numeric(3, 2))
>
> # Relationships
> occupation = relationship(
> 'Occupation',
> backref=backref(
> 'occupation_interests',
> collection_class=attribute_mapped_collection('interest_name'),
> cascade='all, delete-orphan'
> )
> )
> interest = relationship('Interest')
>
> def __init__(self, interest_name, value):
> self._interest_name = interest_name
> self.value = value
>
> @property
> def interest_name(self):
> if self.interest is not None:
> return self.interest.name
> else:
> return self._interest_name
> ...
>
>
> This works fine. Objects of the Occupation class are rated against the same
> interest scale as objects of the User class, and I can get the objects'
> interest values with user.interests['Social'] or
> occupation.interests['Social']. If I query my database for a list of
> Occupation objects, I can use a list comprehension to create a list of dict
> objects without issues.
>
> However, when I added a method to calculate the euclidean distance between a
> User object and an Occupation object, I ran into KeyErrors.
>
> user = User.from_request(request)
> interests = DBSession.query(Interest).order_by(Interest.id).all()
> occupations = DBSession.query(Occupation).limit(10)
>
> def get_distance(occupation, user):
> d_max = Decimal(math.sqrt(6 ** 3))
> d_squared = 0
> for i in interests:
> d_squared += (user.interests[i.name] - occupation.interests[i.name])
> ** 2
> d = Decimal(math.sqrt(d_squared))
> return (d_max - d) / d_max
>
> distances = [
> dict(
> name=o.title,
> distance=get_distance(o, user),
> ) for o in occupations
>
>
> Traceback (most recent call last):
> File "/lib/python3.3/site-packages/pyramid_debugtoolbar/toolbar.py", line
> 172, in toolbar_tween
> response = _handler(request)
> File
> "/lib/python3.3/site-packages/pyramid_debugtoolbar/panels/performance.py",
> line 55, in resource_timer_handler
> result = handler(request)
> File "/lib/python3.3/site-packages/pyramid/tweens.py", line 21, in
> excview_tween
> response = handler(request)
> File "/lib/python3.3/site-packages/pyramid_tm/__init__.py", line 82, in
> tm_tween
> reraise(*exc_info)
> File "/lib/python3.3/site-packages/pyramid_tm/compat.py", line 13, in
> reraise
> raise value
> File "/lib/python3.3/site-packages/pyramid_tm/__init__.py", line 63, in
> tm_tween
> response = handler(request)
> File "/lib/python3.3/site-packages/pyramid/router.py", line 163, in
> handle_request
> response = view_callable(context, request)
> File "/lib/python3.3/site-packages/pyramid/config/views.py", line 329, in
> attr_view
> return view(context, request)
> File "/lib/python3.3/site-packages/pyramid/config/views.py", line 305, in
> predicate_wrapper
> return view(context, request)
> File "/lib/python3.3/site-packages/pyramid/config/views.py", line 245, in
> _secured_view
> return view(context, request)
> File "/lib/python3.3/site-packages/pyramid/config/views.py", line 355, in
> rendered_view
> result = view(context, request)
> File "/lib/python3.3/site-packages/pyramid/config/views.py", line 501, in
> _requestonly_view
> response = view(request)
> File "/projects/App/app/views.py", line 252, in results
> ) for o in occupations
> File "/projects/App/app/views.py", line 252, in <listcomp>
> ) for o in occupations
> File "/projects/App/app/views.py", line 240, in get_distance
> d_squared += (user.interests[i.name] - occupation.interests[i.name]) ** 2
> File "/lib/python3.3/site-packages/sqlalchemy/ext/associationproxy.py",
> line 722, in __getitem__
> return self._get(self.col[key])
> KeyError: 'Social'
>
> Now, when I would previously get the interest values for an Occupation object
> (via o.interests where 'o' is an Occupation object) the result would look
> like this:
> {'Artistic': Decimal('4.33'), 'Enterprising': Decimal('1.67'), 'Social':
> Decimal('1.00'), 'Realistic': Decimal('5.00'), 'Investigative':
> Decimal('7.00'), 'Conventional': Decimal('4.33')}
>
> But when I open an interactive python shell in the Pyramid DebugToolbar,
> o.interests yields an empty object:
> {}.
>
> When I removed the list comprehension and calculated the 'distance' between a
> single User object and Occupation object, there were no issues.
>
> Is this error the result of both association proxies using the same attribute
> mapped collection ('interest_name')? Garbage collection during the
> get_distance method or list comprehension?
>
> I'd appreciate any suggestions -- thanks.
>
> -Brian
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.