and len(statement._compile_options._current_path) > 10
and execution_options.get("compiled_cache", True) is not None
):
- util.warn(
- "Loader depth for query is excessively deep; caching will "
- "be disabled for additional loaders. For recursive eager "
- "loaders consider using the recursion_depth feature. "
- "Use the compiled_cache=None execution option to "
- "skip this warning."
- )
- execution_options = execution_options.union(
- {"compiled_cache": None}
+ execution_options: util.immutabledict[
+ str, Any
+ ] = execution_options.union(
+ {
+ "compiled_cache": None,
+ "_cache_disable_reason": "excess depth for "
+ "ORM loader options",
+ }
)
bind_arguments["clause"] = statement
+import logging.handlers
+
import sqlalchemy as sa
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy.orm import Session
from sqlalchemy.testing import eq_
from sqlalchemy.testing import expect_raises_message
-from sqlalchemy.testing import expect_warnings
from sqlalchemy.testing import fixtures
from sqlalchemy.testing.fixtures import fixture_session
from sqlalchemy.testing.schema import Column
result = s.scalars(stmt)
self._assert_depth(result.one(), 200)
+ @testing.fixture
+ def capture_log(self, testing_engine):
+ existing_level = logging.getLogger("sqlalchemy.engine").level
+
+ buf = logging.handlers.BufferingHandler(100)
+ logging.getLogger("sqlalchemy.engine").addHandler(buf)
+ logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
+ yield buf
+ logging.getLogger("sqlalchemy.engine").setLevel(existing_level)
+ logging.getLogger("sqlalchemy.engine").removeHandler(buf)
+
@testing.combinations(selectinload, immediateload, argnames="loader_fn")
@testing.combinations(4, 9, 12, 25, 41, 55, argnames="depth")
@testing.variation("disable_cache", [True, False])
def test_warning_w_no_recursive_opt(
- self, loader_fn, depth, limited_cache_conn, disable_cache
+ self, loader_fn, depth, limited_cache_conn, disable_cache, capture_log
):
+ buf = capture_log
+
connection = limited_cache_conn(27)
+ connection._echo = True
Node = self.classes.Node
else:
exec_opts = {}
- # note this is a magic number, it's not important that it's exact,
- # just that when someone makes a huge recursive thing,
- # it warns
- if depth > 8 and not disable_cache:
- with expect_warnings(
- "Loader depth for query is excessively deep; "
- "caching will be disabled for additional loaders."
- ):
- with Session(connection) as s:
- result = s.scalars(stmt, execution_options=exec_opts)
- self._assert_depth(result.one(), depth)
- else:
- with Session(connection) as s:
- result = s.scalars(stmt, execution_options=exec_opts)
- self._assert_depth(result.one(), depth)
+ with Session(connection) as s:
+ result = s.scalars(stmt, execution_options=exec_opts)
+ self._assert_depth(result.one(), depth)
+
+ if not disable_cache:
+ # note this is a magic number, it's not important that it's
+ # exact, just that when someone makes a huge recursive thing,
+ # it disables caching and notes in the logs
+ if depth > 8:
+ eq_(
+ buf.buffer[-1].message[0:55],
+ "[caching disabled (excess depth for "
+ "ORM loader options)",
+ )
+ else:
+ assert buf.buffer[-1].message.startswith(
+ "[cached since" if i > 0 else "[generated in"
+ )
if disable_cache:
clen = len(connection.engine._compiled_cache)