From: Mike Bayer Date: Sat, 26 Jun 2021 20:40:09 +0000 (-0400) Subject: ensure with poly entities are also reconstituted for GC'ed AC X-Git-Tag: rel_1_4_20~5^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4e7438e0acac2f7c9d24c73d36cdcdb74551f903;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git ensure with poly entities are also reconstituted for GC'ed AC Fixed regression in ORM regarding an internal reconstitution step for the func:`_orm.with_polymorphic` construct, when the user-facing object is garbage collected as the query is processed. The reconstitution was not ensuring the sub-entities for the "polymorphic" case were handled, leading to an ``AttributeError``. Fixes: #6680 Change-Id: Id35b16d0f2aadb50b5a7385a21fa81b9d8a8325f --- diff --git a/doc/build/changelog/unreleased_14/6680.rst b/doc/build/changelog/unreleased_14/6680.rst new file mode 100644 index 0000000000..c433ed6100 --- /dev/null +++ b/doc/build/changelog/unreleased_14/6680.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, regression, orm + :tickets: 6680 + + Fixed regression in ORM regarding an internal reconstitution step for the + func:`_orm.with_polymorphic` construct, when the user-facing object is + garbage collected as the query is processed. The reconstitution was not + ensuring the sub-entities for the "polymorphic" case were handled, leading + to an ``AttributeError``. diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index 856afabb0f..15f584c1ff 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -524,6 +524,15 @@ class AliasedClass(object): obj = cls.__new__(cls) obj.__name__ = "AliasedClass_%s" % aliased_insp.mapper.class_.__name__ obj._aliased_insp = aliased_insp + + if aliased_insp._is_with_polymorphic: + for sub_aliased_insp in aliased_insp._with_polymorphic_entities: + if sub_aliased_insp is not aliased_insp: + ent = AliasedClass._reconstitute_from_aliased_insp( + sub_aliased_insp + ) + setattr(obj, sub_aliased_insp.class_.__name__, ent) + return obj def __getattr__(self, key): diff --git a/test/orm/inheritance/test_with_poly.py b/test/orm/inheritance/test_with_poly.py index 2492e593c8..264e3ae3f0 100644 --- a/test/orm/inheritance/test_with_poly.py +++ b/test/orm/inheritance/test_with_poly.py @@ -1,6 +1,7 @@ from sqlalchemy import and_ from sqlalchemy import exc from sqlalchemy import or_ +from sqlalchemy import select from sqlalchemy import testing from sqlalchemy.orm import with_polymorphic from sqlalchemy.testing import eq_ @@ -50,9 +51,14 @@ class _WithPolymorphicBase(_PolymorphicFixtureBase): self.assert_sql_count(testing.db, go, 1) - def test_col_expression_base_plus_two_subs(self): + @testing.combinations((True,), (False,), argnames="use_star") + def test_col_expression_base_plus_two_subs(self, use_star): sess = fixture_session() - pa = with_polymorphic(Person, [Engineer, Manager]) + + if use_star: + pa = with_polymorphic(Person, "*") + else: + pa = with_polymorphic(Person, [Engineer, Manager]) eq_( sess.query( @@ -69,6 +75,14 @@ class _WithPolymorphicBase(_PolymorphicFixtureBase): [("dilbert", "java", None), ("dogbert", None, "dogbert")], ) + def test_orm_entity_w_gc(self): + """test #6680""" + sess = fixture_session() + + stmt = select(with_polymorphic(Person, "*")) + + eq_(len(sess.execute(stmt).all()), 5) + def test_join_to_join_entities(self): sess = fixture_session() pa = with_polymorphic(Person, [Engineer])