From: Mike Bayer Date: Tue, 20 Feb 2018 17:15:57 +0000 (-0500) Subject: Default to using current mapped class as owner if none found X-Git-Tag: rel_1_2_4~3^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66a246bd31730d53fb6b0e606d67ea4247f5e56c;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Default to using current mapped class as owner if none found Repaired regression caused in 1.2.3 and 1.1.16 regarding association proxy objects, revising the approach to :ticket:`4185` when calculating the "owning class" of an association proxy to default to choosing the current class if the proxy object is not directly associated with a mapped class, such as a mixin. Change-Id: I87d0ac09f695dc285bd4bbe0a547f1d5ce23e068 Fixes: #4185 --- diff --git a/doc/build/changelog/unreleased_11/4185.rst b/doc/build/changelog/unreleased_11/4185.rst new file mode 100644 index 0000000000..a6b6bfbcbd --- /dev/null +++ b/doc/build/changelog/unreleased_11/4185.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, ext + :tickets: 4185 + :versions: 1.2.4 + + Repaired regression caused in 1.2.3 and 1.1.16 regarding association proxy + objects, revising the approach to :ticket:`4185` when calculating the + "owning class" of an association proxy to default to choosing the current + class if the proxy object is not directly associated with a mapped class, + such as a mixin. diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 72200c5e21..1ebc7b4204 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -271,7 +271,12 @@ class AssociationProxy(interfaces.InspectionAttrInfo): # note we can get our real .key here too owner = insp.mapper.class_manager._locate_owning_manager(self) - self.owning_class = owner.class_ + if owner is not None: + self.owning_class = owner.class_ + else: + # the proxy is attached to a class that is not mapped + # (like a mixin), we are mapped, so, it's us. + self.owning_class = target_cls def __get__(self, obj, class_): if self.owning_class is None: diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py index 111ba91a8f..34eeb15271 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -2044,6 +2044,33 @@ class AttributeAccessTest(fixtures.TestBase): sp.children = 'c' is_(SubParent.children.owning_class, Parent) + def test_resolved_to_correct_class_five(self): + Base = declarative_base() + + class Mixin(object): + children = association_proxy('_children', 'value') + + class Parent(Mixin, Base): + __tablename__ = 'parent' + id = Column(Integer, primary_key=True) + _children = relationship("Child") + + class Child(Base): + __tablename__ = 'child' + parent_id = Column( + Integer, ForeignKey(Parent.id), primary_key=True) + value = Column(String) + + # this triggers the owning routine, doesn't fail + Mixin.children + + p1 = Parent() + + c1 = Child(value='c1') + p1._children.append(c1) + is_(Parent.children.owning_class, Parent) + eq_(p1.children, ["c1"]) + def test_never_assign_nonetype(self): foo = association_proxy('x', 'y') foo._calc_owner(None, None)