From: Mike Bayer Date: Thu, 1 Aug 2024 19:58:57 +0000 (-0400) Subject: skip in eager row processors for enable_eagerloads=False X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a8bf50422a4c5ce1945aee6d6d37d9467ebf1c1;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git skip in eager row processors for enable_eagerloads=False 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 --- diff --git a/doc/build/changelog/unreleased_20/10834.rst b/doc/build/changelog/unreleased_20/10834.rst new file mode 100644 index 0000000000..7670f57ad1 --- /dev/null +++ b/doc/build/changelog/unreleased_20/10834.rst @@ -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. diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index e5eff56f3b..5adbc5f125 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -1377,12 +1377,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 @@ -2768,6 +2772,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 " @@ -3047,6 +3055,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 " diff --git a/test/orm/test_query.py b/test/orm/test_query.py index c5fa993d01..e86283de30 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -5540,6 +5540,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