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-Tag: rel_2_0_32~3^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6a457923b80497cf3deaa5a47a9a834498f4b055;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 (cherry picked from commit 0a8bf50422a4c5ce1945aee6d6d37d9467ebf1c1) --- 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 00c6fcb6c1..c6b9a4c7fa 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -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 " diff --git a/test/orm/test_query.py b/test/orm/test_query.py index ea108c345b..9dc26bc1e2 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -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