anydi 0.60.1__tar.gz → 0.61.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {anydi-0.60.1 → anydi-0.61.0}/PKG-INFO +1 -1
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_container.py +48 -20
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/typer.py +7 -6
- {anydi-0.60.1 → anydi-0.61.0}/pyproject.toml +1 -1
- {anydi-0.60.1 → anydi-0.61.0}/README.md +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/__init__.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_async_lock.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_context.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_decorators.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_injector.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_module.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_provider.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_resolver.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_scanner.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/_types.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/__init__.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/django/__init__.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/fastapi.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/faststream.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/pydantic_settings.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/pytest_plugin.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/starlette/__init__.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/ext/starlette/middleware.py +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/py.typed +0 -0
- {anydi-0.60.1 → anydi-0.61.0}/anydi/testing.py +0 -0
|
@@ -58,6 +58,13 @@ class Container:
|
|
|
58
58
|
# Register default scopes
|
|
59
59
|
self.register_scope("request")
|
|
60
60
|
|
|
61
|
+
# Register self as provider
|
|
62
|
+
self._register_provider(
|
|
63
|
+
lambda: self,
|
|
64
|
+
"singleton",
|
|
65
|
+
Container,
|
|
66
|
+
)
|
|
67
|
+
|
|
61
68
|
# Register providers
|
|
62
69
|
providers = providers or []
|
|
63
70
|
for provider in providers:
|
|
@@ -257,31 +264,52 @@ class Container:
|
|
|
257
264
|
# Register the scope
|
|
258
265
|
self._scopes[scope] = tuple({scope, "singleton"} | set(parents))
|
|
259
266
|
|
|
260
|
-
def
|
|
261
|
-
"""
|
|
262
|
-
#
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
def get_context_scopes(self, scopes: set[Scope] | None = None) -> list[str]: # noqa: C901
|
|
268
|
+
"""Return scopes that require context management in dependency order."""
|
|
269
|
+
# Build execution order: singleton -> request -> custom (by depth)
|
|
270
|
+
ordered = ["singleton"]
|
|
271
|
+
custom_scopes: list[tuple[int, str]] = []
|
|
272
|
+
has_request = False
|
|
273
|
+
|
|
274
|
+
for scope, parents in self._scopes.items():
|
|
275
|
+
if scope == "singleton":
|
|
276
|
+
continue
|
|
277
|
+
if scope == "request":
|
|
278
|
+
has_request = True
|
|
279
|
+
continue
|
|
265
280
|
if scope == "transient":
|
|
266
281
|
continue
|
|
267
|
-
|
|
268
|
-
expanded_scopes.add("singleton")
|
|
269
|
-
else:
|
|
270
|
-
# Add the scope and all its parents from container._scopes
|
|
271
|
-
expanded_scopes.update(self._scopes[scope])
|
|
282
|
+
custom_scopes.append((len(parents), scope))
|
|
272
283
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
other_scopes = expanded_scopes - {"singleton"}
|
|
284
|
+
if has_request:
|
|
285
|
+
ordered.append("request")
|
|
276
286
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
287
|
+
custom_scopes.sort(key=lambda item: item[0])
|
|
288
|
+
ordered.extend(scope for _, scope in custom_scopes)
|
|
289
|
+
|
|
290
|
+
# If no filter, return all scopes with contexts (transient excluded)
|
|
291
|
+
if scopes is None:
|
|
292
|
+
return ordered
|
|
293
|
+
|
|
294
|
+
# Helper to add scope with its parents to needed set
|
|
295
|
+
def add_scope_tree(needed: set[str], scope: str) -> None:
|
|
296
|
+
if scope == "singleton":
|
|
297
|
+
needed.add("singleton")
|
|
298
|
+
elif scope != "transient":
|
|
299
|
+
needed.update(self._scopes[scope])
|
|
300
|
+
|
|
301
|
+
needed_scopes: set[str] = set()
|
|
302
|
+
|
|
303
|
+
# Add injected scopes and their parents
|
|
304
|
+
for scope in scopes:
|
|
305
|
+
add_scope_tree(needed_scopes, scope)
|
|
306
|
+
|
|
307
|
+
# Add scopes with resource providers and their parents
|
|
308
|
+
for scope in ordered:
|
|
309
|
+
if self._resources.get(scope):
|
|
310
|
+
add_scope_tree(needed_scopes, scope)
|
|
282
311
|
|
|
283
|
-
|
|
284
|
-
return ["singleton", *ordered_scopes] if has_singleton else ordered_scopes
|
|
312
|
+
return [scope for scope in ordered if scope in needed_scopes]
|
|
285
313
|
|
|
286
314
|
# == Provider Registry ==
|
|
287
315
|
|
|
@@ -12,11 +12,10 @@ import anyio
|
|
|
12
12
|
from typer import Typer
|
|
13
13
|
|
|
14
14
|
from anydi import Container, Scope
|
|
15
|
+
from anydi._decorators import is_provided
|
|
15
16
|
|
|
16
17
|
__all__ = ["install"]
|
|
17
18
|
|
|
18
|
-
from anydi._decorators import is_provided
|
|
19
|
-
|
|
20
19
|
|
|
21
20
|
def _wrap_async_callback_no_injection(callback: Callable[..., Any]) -> Any:
|
|
22
21
|
"""Wrap async callback without injection in anyio.run()."""
|
|
@@ -40,11 +39,12 @@ def _wrap_async_callback_with_injection(
|
|
|
40
39
|
@functools.wraps(callback)
|
|
41
40
|
def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
42
41
|
async def _run() -> Any:
|
|
43
|
-
|
|
42
|
+
# Get scopes for execution (injected OR have resources)
|
|
43
|
+
needed_scopes = container.get_context_scopes(scopes)
|
|
44
44
|
|
|
45
45
|
async with contextlib.AsyncExitStack() as stack:
|
|
46
46
|
# Start scoped contexts in dependency order
|
|
47
|
-
for scope in
|
|
47
|
+
for scope in needed_scopes:
|
|
48
48
|
if scope == "singleton":
|
|
49
49
|
await stack.enter_async_context(container)
|
|
50
50
|
else:
|
|
@@ -100,11 +100,12 @@ def _process_callback(callback: Callable[..., Any], container: Container) -> Any
|
|
|
100
100
|
|
|
101
101
|
@functools.wraps(callback)
|
|
102
102
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
103
|
-
|
|
103
|
+
# Get scopes for execution (injected OR have resources)
|
|
104
|
+
needed_scopes = container.get_context_scopes(scopes)
|
|
104
105
|
|
|
105
106
|
with contextlib.ExitStack() as stack:
|
|
106
107
|
# Start scoped contexts in dependency order
|
|
107
|
-
for scope in
|
|
108
|
+
for scope in needed_scopes:
|
|
108
109
|
if scope == "singleton":
|
|
109
110
|
stack.enter_context(container)
|
|
110
111
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|