On 11/25/2015 01:32 PM, Christopher Lee wrote:
> Looks like the problem is that self.entity is the root node and contains
> the subclasses, so attempting to retrieve an attribute by class name
> only works if it is a subclass.  It also needs to handle the case where
> self.entity is the mapped class you want.

yup I've updated the issue thanks!



> 
> On Wed, Nov 25, 2015 at 10:26 AM, Christopher Lee <[email protected]
> <mailto:[email protected]>> wrote:
> 
>     Hmm, the patch seems to fix the case where the relationship is on
>     the subclass, but putting the relationship on the base class is
>     resulting in an AttributeError.
> 
>     Node.links = sa.orm.relationship(
>     Edge,
>     primaryjoin=NodeWithEdges.element_id == Edge.parent_id,
>     lazy=False,
>     cascade='all, delete-orphan',
>     single_parent=True,
>     passive_updates=False,
>     join_depth=8,
>     )
> 
>     Node.children = sa.ext.associationproxy.association_proxy(
>     'links', 'child',
>     creator=lambda child: Edge(child_id=child.element_id))
> 
>     Results in the stack trace:
> 
>     Traceback (most recent call last):
>       File "./sqlalchemy_todo_test.py", line 108, in <module>
>         new_n1 =
>     session.query(NodeWithEdges).filter(NodeWithEdges.element_id==1).first()
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/query.py",
>     line 2469, in first
>         ret = list(self[0:1])
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/query.py",
>     line 2292, in __getitem__
>         return list(res)
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/query.py",
>     line 2567, in __iter__
>         context = self._compile_context()
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/query.py",
>     line 3029, in _compile_context
>         strategy(*rec[1:])
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/strategies.py",
>     line 1329, in _create_eager_join
>         _entity_for_mapper(self.parent)
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/util.py",
>     line 540, in _entity_for_mapper
>         return getattr(self.entity, mapper.class_.__name__)._aliased_insp
>       File
>     
> "/home/chris/Documents/cozi/kits/output/site-packages/SQLAlchemy-1.0.9-py2.7-linux-x86_64.egg/sqlalchemy/orm/util.py",
>     line 398, in __getattr__
>         raise AttributeError(key)
>     AttributeError: Node
> 
> 
> 
>     On Wed, Nov 25, 2015 at 10:21 AM, Christopher Lee <[email protected]
>     <mailto:[email protected]>> wrote:
> 
>         Verified that the patch works.
> 
>         On Wed, Nov 25, 2015 at 10:16 AM, Christopher Lee
>         <[email protected] <mailto:[email protected]>> wrote:
> 
>             Great, I'll try it out.
> 
>             Thanks, Mike!
> 
> 
>             On Tue, Nov 24, 2015 at 10:15 PM, Mike Bayer
>             <[email protected] <mailto:[email protected]>>
>             wrote:
> 
> 
> 
>                 On 11/24/2015 08:19 PM, Mike Bayer wrote:
>                 > I've bisected it down and this one is going to be tough.
>                 > 
> https://bitbucket.org/zzzeek/sqlalchemy/issues/3593/eager-loading-single-inh-polymorphic-join
>                 > is added.
> 
> 
>                 I've figured out exactly where a simple thing was going
>                 wrong with this
>                 and produced a good patch that is safe to commit.   
>                 Even though this
>                 use case broke between 0.8.0 and 0.8.1, the new approach
>                 begun in 0.8.1
>                 on forward removes most of the guessing from how the ORM
>                 joins things
>                 together and this fix just closes up a loose end,
>                 whereas the use case
>                 working in 0.8.0 and previously was because the old
>                 approach of guessing
>                 how to join things just happened to make the right guess
>                 here.
> 
>                 I will try to add the necessary tests for this tomorrow
>                 so that it's
>                 good for 1.0.10 at least, feel free to try the patch
>                 ahead of time to
>                 confirm it resolves all your issues.
> 
> 
> 
> 
>                 >
>                 >
>                 >
>                 > On 11/24/2015 07:20 PM, Mike Bayer wrote:
>                 >>
>                 >>
>                 >> On 11/24/2015 07:16 PM, Christopher Lee wrote:
>                 >>> The test passes for me in 0.8.0.  (Yes, we have
>                 0.8.0 running in
>                 >>> production, and are finally getting around to
>                 upgrading... sigh...)
>                 >>
>                 >>
>                 >> agree.  and it then fails in 0.8.1, so this is
>                 something very immediate
>                 >> and old in the 0.8 series  I'll start looking to see
>                 the actual
>                 >> condition here.
>                 >>
>                 >>
>                 >>
>                 >>>
>                 >>>
>                 >>> On Tue, Nov 24, 2015 at 4:09 PM, Christopher Lee
>                 <[email protected] <mailto:[email protected]>
>                 >>> <mailto:[email protected] <mailto:[email protected]>>>
>                 wrote:
>                 >>>
>                 >>>     I'll see if I can nail down the repro; I had to
>                 abstract some
>                 >>>     production code that I am migrating between
>                 versions, and I may have
>                 >>>     lost some important detail.
>                 >>>
>                 >>>     Looking at the SQL it generates before and after
>                 moving the "links"
>                 >>>     relationship, it appears that it is outer
>                 joining against the wrong
>                 >>>     target, which explains why the identity map is
>                 getting confused.
>                 >>>      (e.g., it is joining against the innermost
>                 anon_1 subquery in the
>                 >>>     bad case, and against the todo_elements_1
>                 reference in the good
>                 >>>     case, which is why the good case is forming a
>                 nice tree.)
>                 >>>
>                 >>>     On Tue, Nov 24, 2015 at 3:49 PM, Mike Bayer
>                 >>>     <[email protected]
>                 <mailto:[email protected]>
>                 <mailto:[email protected]
>                 <mailto:[email protected]>>> wrote:
>                 >>>
>                 >>>
>                 >>>
>                 >>>         On 11/24/2015 06:14 PM, Christopher Lee wrote:
>                 >>>         >
>                 >>>         > I am having a problem with SQLAlchemy
>                 1.0.9 that cropped up when I
>                 >>>         > upgraded from 0.8.
>                 >>>
>                 >>>         this is a nicely written test but I get the
>                 same recursion overflow
>                 >>>         error when I run it in 0.8, 0.9, and 1.0,
>                 even back in 0.8.3.
>                 >>>         Can you
>                 >>>         provide a script that illustrates success in
>                 0.8 and not in 1.0
>                 >>>         ?  thanks.
>                 >>>
>                 >>>
>                 >>>
>                 >>>
>                 >>>
>                 >>>
>                 >>>         >
>                 >>>         > I have the following polymorphic
>                 relationship defined.  For
>                 >>>         some reason,
>                 >>>         > when I build a tree, and I try to access
>                 the children of the
>                 >>>         middle node
>                 >>>         > of the tree, it is picking up the wrong
>                 edge object and going
>                 >>>         into a
>                 >>>         > recursive loop.  (Querying for the
>                 children of n2 is picking
>                 >>>         up the edge
>                 >>>         > e12, instead of the edges e23, e24 and e25.)
>                 >>>         >
>                 >>>         > Looking at the identity map, it looks like
>                 the query isn't
>                 >>>         populating
>                 >>>         > the correct objects.
>                 >>>         >
>                 >>>         > If I move the "links" relationship from
>                 the NodesWithEdges
>                 >>>         class to the
>                 >>>         > base Node class, the query works fine. 
>                 Also, if I drop
>                 >>>         join_depth or
>                 >>>         > remove with with_polymorphic mapper arg,
>                 it forces multiple
>                 >>>         queries, and
>                 >>>         > the problem doesn't occur.  Is this a bug
>                 with the new
>                 >>>         release, or am I
>                 >>>         > doing something bad?
>                 >>>         >
>                 >>>         >
>                 >>>         > from __future__ import print_function,
>                 unicode_literals
>                 >>>         >
>                 >>>         > import sqlalchemy as sa
>                 >>>         > import sqlalchemy.orm
>                 >>>         > import sqlalchemy.ext.associationproxy
>                 >>>         > import sqlalchemy.ext.declarative
>                 >>>         > import sqlalchemy.ext.orderinglist
>                 >>>         >
>                 >>>         > Base =
>                 sqlalchemy.ext.declarative.declarative_base()
>                 >>>         >
>                 >>>         >
>                 >>>         > class Node(Base):
>                 >>>         > __tablename__ = 'todo_elements'
>                 >>>         >
>                 >>>         > element_id = sa.Column(sa.Integer,
>                 nullable=False,
>                 >>>         primary_key=True)
>                 >>>         >     element_type =
>                 sa.Column(sa.String(20), nullable=False)
>                 >>>         >
>                 >>>         >     __mapper_args__ = {
>                 >>>         >         'polymorphic_on': element_type,
>                 >>>         > 'with_polymorphic': ('*', None),
>                 >>>         > }
>                 >>>         >
>                 >>>         >
>                 >>>         > class NodeWithEdges(Node):
>                 >>>         > __mapper_args__ = {'polymorphic_identity':
>                 'todo.list'}
>                 >>>         >
>                 >>>         >
>                 >>>         > class LeafNode(Node):
>                 >>>         > __mapper_args__ = {'polymorphic_identity':
>                 'todo.item'}
>                 >>>         >
>                 >>>         >     my_flag = sa.Column(sa.Boolean,
>                 default=False)
>                 >>>         >
>                 >>>         >
>                 >>>         > class Edge(Base):
>                 >>>         > __tablename__ = 'todo_links'
>                 >>>         > __table_args__ = (
>                 >>>         >       
>                  sa.PrimaryKeyConstraint('parent_id', 'child_id'),
>                 >>>         > sa.ForeignKeyConstraint(['parent_id'],
>                 [Node.element_id]),
>                 >>>         > sa.ForeignKeyConstraint(['child_id'],
>                 [Node.element_id]),
>                 >>>         > )
>                 >>>         >
>                 >>>         >     parent_id = sa.Column(sa.Integer,
>                 nullable=False)
>                 >>>         >     child_id = sa.Column(sa.Integer,
>                 nullable=False)
>                 >>>         >
>                 >>>         >
>                 >>>         > Edge.child = sa.orm.relationship(
>                 >>>         >     Node,
>                 >>>         > uselist=False,
>                 >>>         > primaryjoin=Edge.child_id == Node.element_id,
>                 >>>         > lazy=False,
>                 >>>         > cascade='all',
>                 >>>         > passive_updates=False,
>                 >>>         > join_depth=8,
>                 >>>         > )
>                 >>>         >
>                 >>>         >
>                 >>>         > NodeWithEdges.links = sa.orm.relationship(
>                 >>>         >     Edge,
>                 >>>         > primaryjoin=NodeWithEdges.element_id ==
>                 Edge.parent_id,
>                 >>>         > lazy=False,
>                 >>>         > cascade='all, delete-orphan',
>                 >>>         > single_parent=True,
>                 >>>         > passive_updates=False,
>                 >>>         > join_depth=8,
>                 >>>         > )
>                 >>>         >
>                 >>>         > NodeWithEdges.children =
>                 >>>         sa.ext.associationproxy.association_proxy(
>                 >>>         >     'links', 'child',
>                 >>>         > creator=lambda child:
>                 Edge(child_id=child.element_id))
>                 >>>         >
>                 >>>         >
>                 >>>         >
>                 >>>         > engine =
>                 sa.create_engine('sqlite:///:memory:', echo=True)
>                 >>>         > Base.metadata.create_all(engine)
>                 >>>         >
>                 >>>         > Session = sa.orm.sessionmaker(bind=engine)
>                 >>>         > session = Session()
>                 >>>         >
>                 >>>         >
>                 >>>         > #
>                 >>>         > # 1 --> 2 --> 3
>                 >>>         > # --> 4
>                 >>>         > # --> 5
>                 >>>         > #
>                 >>>         >
>                 >>>         > n1 = NodeWithEdges(element_id=1)
>                 >>>         > n2 = NodeWithEdges(element_id=2)
>                 >>>         > n3 = LeafNode(element_id=3)
>                 >>>         > n4 = LeafNode(element_id=4, my_flag=True)
>                 >>>         > n5 = LeafNode(element_id=5)
>                 >>>         >
>                 >>>         > e12 = Edge(parent_id=n1.element_id,
>                 child_id=n2.element_id)
>                 >>>         > e23 = Edge(parent_id=n2.element_id,
>                 child_id=n3.element_id)
>                 >>>         > e24 = Edge(parent_id=n2.element_id,
>                 child_id=n4.element_id)
>                 >>>         > e25 = Edge(parent_id=n2.element_id,
>                 child_id=n5.element_id)
>                 >>>         >
>                 >>>         > session.add_all([n1, n2, n3, n4, n5, e12,
>                 e23, e24, e25])
>                 >>>         > session.commit()
>                 >>>         > session.expunge_all()
>                 >>>         >
>                 >>>         > new_n1 =
>                 >>>       
>                  
> session.query(NodeWithEdges).filter(NodeWithEdges.element_id==1).first()
>                 >>>         > print(session.identity_map.keys())
>                 >>>         >
>                 >>>         >
>                 >>>         > def traverse(node, f, depth=0):
>                 >>>         > f(node, depth)
>                 >>>         >     if hasattr(node, 'children'):
>                 >>>         > for c in node.children:
>                 >>>         > traverse(c, f, depth + 1)
>                 >>>         >
>                 >>>         > def indent_print(node, depth):
>                 >>>         > print(' ' * depth + str(node.element_id))
>                 >>>         >     if hasattr(node, 'my_flag'):
>                 >>>         > print(node.my_flag)
>                 >>>         >
>                 >>>         > traverse(new_n1, indent_print)
>                 >>>         >
>                 >>>         > --
>                 >>>         > 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]
>                 <mailto:sqlalchemy%[email protected]>
>                 >>>       
>                  <mailto:sqlalchemy%[email protected]
>                 <mailto:sqlalchemy%[email protected]>>
>                 >>>         >
>                 <mailto:[email protected]
>                 <mailto:sqlalchemy%[email protected]>
>                 >>>       
>                  <mailto:sqlalchemy%[email protected]
>                 <mailto:sqlalchemy%[email protected]>>>.
>                 >>>         > To post to this group, send email to
>                 [email protected]
>                 <mailto:[email protected]>
>                 <mailto:[email protected]
>                 <mailto:[email protected]>>
>                 >>>         > <mailto:[email protected]
>                 <mailto:[email protected]>
>                 <mailto:[email protected]
>                 <mailto:[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]
>                 <mailto:sqlalchemy%[email protected]>
>                 >>>       
>                  <mailto:sqlalchemy%[email protected]
>                 <mailto:sqlalchemy%[email protected]>>.
>                 >>>         To post to this group, send email to
>                 [email protected]
>                 <mailto:[email protected]>
>                 >>>         <mailto:[email protected]
>                 <mailto:[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]
>                 <mailto:sqlalchemy%[email protected]>
>                 >>> <mailto:[email protected]
>                 <mailto:sqlalchemy%[email protected]>>.
>                 >>> To post to this group, send email to
>                 [email protected]
>                 <mailto:[email protected]>
>                 >>> <mailto:[email protected]
>                 <mailto:[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]
>                 <mailto:sqlalchemy%[email protected]>.
>                 To post to this group, send email to
>                 [email protected]
>                 <mailto:[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]
> <mailto:[email protected]>.
> To post to this group, send email to [email protected]
> <mailto:[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