]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
call iter() on detached/transient dynamic session
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 2 Jul 2024 17:57:47 +0000 (13:57 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 2 Jul 2024 19:05:33 +0000 (15:05 -0400)
Fixed regression going back to 1.4 where accessing a collection using the
"dynamic" strategy on a transient object and attempting to query would
raise an internal error rather than the expected :class:`.NoResultFound`
that occurred in 1.3.

Fixes: #11562
Change-Id: I650305963a17592413520d8d1049c601761a0acc

doc/build/changelog/unreleased_14/11562.rst [new file with mode: 0644]
lib/sqlalchemy/orm/dynamic.py
test/orm/test_dynamic.py

diff --git a/doc/build/changelog/unreleased_14/11562.rst b/doc/build/changelog/unreleased_14/11562.rst
new file mode 100644 (file)
index 0000000..15ccd0d
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, orm, regression
+    :tickets: 11562
+
+    Fixed regression going back to 1.4 where accessing a collection using the
+    "dynamic" strategy on a transient object and attempting to query would
+    raise an internal error rather than the expected :class:`.NoResultFound`
+    that occurred in 1.3.
index 7496e5c30dab7e5b09790ef3eede670c5a579483..ad1b239c13c25eccefc32d42d38747d92f1dd4bd 100644 (file)
@@ -161,10 +161,12 @@ class AppenderMixin(AbstractCollectionWriter[_T]):
 
             return result.IteratorResult(
                 result.SimpleResultMetaData([self.attr.class_.__name__]),
-                self.attr._get_collection_history(  # type: ignore[arg-type]
-                    attributes.instance_state(self.instance),
-                    PassiveFlag.PASSIVE_NO_INITIALIZE,
-                ).added_items,
+                iter(
+                    self.attr._get_collection_history(
+                        attributes.instance_state(self.instance),
+                        PassiveFlag.PASSIVE_NO_INITIALIZE,
+                    ).added_items
+                ),
                 _source_supports_scalars=True,
             ).scalars()
         else:
index cce3f8c18a8d20e960d2603f8d8f1f1ade2b20a8..465e29929e9e8c8b24a313dc0d1a8e95b3295f1d 100644 (file)
@@ -275,6 +275,33 @@ class DynamicTest(_DynamicFixture, _fixtures.FixtureTest, AssertsCompiledSQL):
             use_default_dialect=True,
         )
 
+    @testing.combinations(
+        ("all", []),
+        ("one", exc.NoResultFound),
+        ("one_or_none", None),
+        argnames="method, expected",
+    )
+    @testing.variation("add_to_session", [True, False])
+    def test_transient_raise(
+        self, user_address_fixture, method, expected, add_to_session
+    ):
+        """test 11562"""
+        User, Address = user_address_fixture()
+
+        u1 = User(name="u1")
+        if add_to_session:
+            sess = fixture_session()
+            sess.add(u1)
+
+        meth = getattr(u1.addresses, method)
+        if expected is exc.NoResultFound:
+            with expect_raises_message(
+                exc.NoResultFound, "No row was found when one was required"
+            ):
+                meth()
+        else:
+            eq_(meth(), expected)
+
     def test_detached_raise(self, user_address_fixture):
         """so filtering on a detached dynamic list raises an error..."""