Coverage for fastapi_restly / db / _globals.py: 97%
56 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-10-09 18:41 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-10-09 18:41 +0000
1from collections.abc import AsyncIterator, Callable, Iterator
2from contextvars import ContextVar, Token
3from typing import Any
5from sqlalchemy.ext.asyncio import AsyncSession as SA_AsyncSession
6from sqlalchemy.ext.asyncio import async_sessionmaker
7from sqlalchemy.orm import Session as SA_Session
8from sqlalchemy.orm import sessionmaker
11class RestlyContext:
12 """Private container for Restly runtime state used by tests and internals."""
14 __slots__ = (
15 "async_database_url",
16 "async_make_session",
17 "database_configuration_locked",
18 "registered_session_dependencies",
19 "test_async_make_session",
20 "test_make_session",
21 "database_url",
22 "make_session",
23 "session_generator",
24 "sync_session_generator",
25 "warn_on_misuse",
26 "warn_on_uncommitted",
27 )
29 async_database_url: str | None
30 async_make_session: async_sessionmaker[Any] | None
31 database_configuration_locked: bool
32 registered_session_dependencies: set[str]
33 #: Set by the test fixtures for the duration of a test. The app's dependency
34 #: overrides and open_session() use these factories before application sources.
35 test_make_session: sessionmaker[Any] | None
36 test_async_make_session: async_sessionmaker[Any] | None
37 database_url: str | None
38 make_session: sessionmaker[Any] | None
39 session_generator: Callable[..., AsyncIterator[SA_AsyncSession]] | None
40 sync_session_generator: Callable[..., Iterator[SA_Session]] | None
41 warn_on_misuse: bool
42 warn_on_uncommitted: bool
44 def __init__(self) -> None:
45 self.async_database_url = None
46 self.async_make_session = None
47 self.database_configuration_locked = False
48 self.registered_session_dependencies = set()
49 self.test_make_session = None
50 self.test_async_make_session = None
51 self.database_url = None
52 self.make_session = None
53 self.session_generator = None
54 self.sync_session_generator = None
55 self.warn_on_misuse = False
56 self.warn_on_uncommitted = True
58 def __enter__(self) -> "RestlyContext":
59 token = _restly_context_ctx.set(self)
60 _restly_context_token_stack.set(_restly_context_token_stack.get() + (token,))
61 return self
63 def __exit__(self, *exc_info: object) -> None:
64 token_stack = _restly_context_token_stack.get()
65 if not token_stack: 65 ↛ 66line 65 didn't jump to line 66 because the condition on line 65 was never true
66 raise RuntimeError("RestlyContext was exited without being entered.")
67 token = token_stack[-1]
68 _restly_context_token_stack.set(token_stack[:-1])
69 _restly_context_ctx.reset(token)
72_default_context = RestlyContext()
73_restly_context_ctx: ContextVar[RestlyContext | None] = ContextVar(
74 "fastapi_restly_context", default=None
75)
76_restly_context_token_stack: ContextVar[tuple[Token[RestlyContext | None], ...]] = (
77 ContextVar("fastapi_restly_context_token_stack", default=())
78)
81def _get_restly_context() -> RestlyContext:
82 return _restly_context_ctx.get() or _default_context
85class _FRGlobalsProxy:
86 def __getattr__(self, name: str):
87 return getattr(_get_restly_context(), name)
89 def __setattr__(self, name: str, value):
90 setattr(_get_restly_context(), name, value)
93_fr_globals = _FRGlobalsProxy()