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.

Reply via email to