]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
skip in eager row processors for enable_eagerloads=False
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 1 Aug 2024 19:58:57 +0000 (15:58 -0400)
committerMichael Bayer <mike_mp@zzzcomputing.com>
Thu, 1 Aug 2024 23:16:53 +0000 (23:16 +0000)
Fixed issue where using the :meth:`_orm.Query.enable_eagerloads` and
:meth:`_orm.Query.yield_per` methods at the same time, in order to disable
eager loading that's configured on the mapper directly, would be silently
ignored, leading to errors or unexpected eager population of attributes.

Fixes: #10834
Change-Id: I6a20bdedf23f6dd4e98ffb49ad784117fe4afdd3
(cherry picked from commit 0a8bf50422a4c5ce1945aee6d6d37d9467ebf1c1)

doc/build/changelog/unreleased_20/10834.rst [new file with mode: 0644]
lib/sqlalchemy/orm/strategies.py
test/orm/test_query.py

diff --git a/doc/build/changelog/unreleased_20/10834.rst b/doc/build/changelog/unreleased_20/10834.rst
new file mode 100644 (file)
index 0000000..7670f57
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, orm
+    :tickets: 10834
+
+    Fixed issue where using the :meth:`_orm.Query.enable_eagerloads` and
+    :meth:`_orm.Query.yield_per` methods at the same time, in order to disable
+    eager loading that's configured on the mapper directly, would be silently
+    ignored, leading to errors or unexpected eager population of attributes.
index 00c6fcb6c1aa12ec89aee02350aa5597c8b66269..c6b9a4c7fa96ac53be0c21f7da4be6fb3c7af827 100644 (file)
@@ -1373,12 +1373,16 @@ class ImmediateLoader(PostLoader):
         adapter,
         populators,
     ):
+        if not context.compile_state.compile_options._enable_eagerloads:
+            return
+
         (
             effective_path,
             run_loader,
             execution_options,
             recursion_depth,
         ) = self._setup_for_recursion(context, path, loadopt, self.join_depth)
+
         if not run_loader:
             # this will not emit SQL and will only emit for a many-to-one
             # "use get" load.   the "_RELATED" part means it may return
@@ -2705,6 +2709,10 @@ class JoinedLoader(AbstractRelationshipLoader):
         adapter,
         populators,
     ):
+
+        if not context.compile_state.compile_options._enable_eagerloads:
+            return
+
         if not self.parent.class_manager[self.key].impl.supports_population:
             raise sa_exc.InvalidRequestError(
                 "'%s' does not support object "
@@ -2984,6 +2992,9 @@ class SelectInLoader(PostLoader, util.MemoizedSlots):
         if not run_loader:
             return
 
+        if not context.compile_state.compile_options._enable_eagerloads:
+            return
+
         if not self.parent.class_manager[self.key].impl.supports_population:
             raise sa_exc.InvalidRequestError(
                 "'%s' does not support object "
index ea108c345b033bacb65bbd127b18537fe96ea2db..9dc26bc1e276c5f0f885f7cf87fd42afac5f49ee 100644 (file)
@@ -5537,6 +5537,25 @@ class YieldTest(_fixtures.FixtureTest):
         )
         eq_(len(q.all()), 4)
 
+    @testing.combinations(
+        "joined",
+        "subquery",
+        "selectin",
+        "select",
+        "immediate",
+        argnames="lazy",
+    )
+    def test_eagerload_config_disable(self, lazy):
+        self._eagerload_mappings(addresses_lazy=lazy)
+
+        User = self.classes.User
+        sess = fixture_session()
+        q = sess.query(User).enable_eagerloads(False).yield_per(1)
+        objs = q.all()
+        eq_(len(objs), 4)
+        for obj in objs:
+            assert "addresses" not in obj.__dict__
+
     def test_m2o_joinedload_not_others(self):
         self._eagerload_mappings(addresses_lazy="joined")
         Address = self.classes.Address