anydi 0.25.2__py3-none-any.whl → 0.26.0a0__py3-none-any.whl
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/_container.py +46 -7
- anydi/_context.py +22 -2
- {anydi-0.25.2.dist-info → anydi-0.26.0a0.dist-info}/METADATA +1 -1
- {anydi-0.25.2.dist-info → anydi-0.26.0a0.dist-info}/RECORD +7 -7
- {anydi-0.25.2.dist-info → anydi-0.26.0a0.dist-info}/LICENSE +0 -0
- {anydi-0.25.2.dist-info → anydi-0.26.0a0.dist-info}/WHEEL +0 -0
- {anydi-0.25.2.dist-info → anydi-0.26.0a0.dist-info}/entry_points.txt +0 -0
anydi/_container.py
CHANGED
|
@@ -6,6 +6,7 @@ import contextlib
|
|
|
6
6
|
import inspect
|
|
7
7
|
import types
|
|
8
8
|
import uuid
|
|
9
|
+
from collections import defaultdict
|
|
9
10
|
from contextvars import ContextVar
|
|
10
11
|
from functools import wraps
|
|
11
12
|
from typing import (
|
|
@@ -24,7 +25,7 @@ from typing import (
|
|
|
24
25
|
overload,
|
|
25
26
|
)
|
|
26
27
|
|
|
27
|
-
from typing_extensions import ParamSpec, final, get_args, get_origin
|
|
28
|
+
from typing_extensions import ParamSpec, Self, final, get_args, get_origin
|
|
28
29
|
|
|
29
30
|
try:
|
|
30
31
|
from types import NoneType
|
|
@@ -85,6 +86,7 @@ class Container:
|
|
|
85
86
|
strict: Whether to enable strict mode. Defaults to False.
|
|
86
87
|
"""
|
|
87
88
|
self._providers: dict[type[Any], Provider] = {}
|
|
89
|
+
self._providers_cache: dict[Scope, list[type[Any]]] = defaultdict(list)
|
|
88
90
|
self._singleton_context = SingletonContext(self)
|
|
89
91
|
self._transient_context = TransientContext(self)
|
|
90
92
|
self._request_context_var: ContextVar[RequestContext | None] = ContextVar(
|
|
@@ -170,11 +172,11 @@ class Container:
|
|
|
170
172
|
|
|
171
173
|
# Create Event type
|
|
172
174
|
if provider.is_resource and (interface is NoneType or interface is None):
|
|
173
|
-
interface = type(f"
|
|
175
|
+
interface = type(f"Event_{uuid.uuid4().hex}", (), {})
|
|
174
176
|
|
|
175
177
|
if interface in self._providers:
|
|
176
178
|
if override:
|
|
177
|
-
self.
|
|
179
|
+
self._set_provider(interface, provider)
|
|
178
180
|
return provider
|
|
179
181
|
|
|
180
182
|
raise LookupError(
|
|
@@ -187,7 +189,7 @@ class Container:
|
|
|
187
189
|
self._validate_provider_type(provider)
|
|
188
190
|
self._validate_provider_match_scopes(interface, provider)
|
|
189
191
|
|
|
190
|
-
self.
|
|
192
|
+
self._set_provider(interface, provider)
|
|
191
193
|
return provider
|
|
192
194
|
|
|
193
195
|
def unregister(self, interface: AnyInterface) -> None:
|
|
@@ -275,6 +277,17 @@ class Container:
|
|
|
275
277
|
return self.register(interface, interface, scope=scope or "transient")
|
|
276
278
|
raise
|
|
277
279
|
|
|
280
|
+
def _set_provider(self, interface: AnyInterface, provider: Provider) -> None:
|
|
281
|
+
"""Set a provider by interface.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
interface: The interface for which to set the provider.
|
|
285
|
+
provider: The provider object to set.
|
|
286
|
+
"""
|
|
287
|
+
self._providers[interface] = provider
|
|
288
|
+
if provider.is_resource:
|
|
289
|
+
self._providers_cache[provider.scope].append(interface)
|
|
290
|
+
|
|
278
291
|
def _validate_provider_scope(self, provider: Provider) -> None:
|
|
279
292
|
"""Validate the scope of a provider.
|
|
280
293
|
|
|
@@ -398,11 +411,23 @@ class Container:
|
|
|
398
411
|
"""
|
|
399
412
|
self._modules.register(module)
|
|
400
413
|
|
|
414
|
+
def __enter__(self) -> Self:
|
|
415
|
+
"""Enter the singleton context."""
|
|
416
|
+
self.start()
|
|
417
|
+
return self
|
|
418
|
+
|
|
419
|
+
def __exit__(
|
|
420
|
+
self,
|
|
421
|
+
exc_type: type[BaseException] | None,
|
|
422
|
+
exc_val: BaseException | None,
|
|
423
|
+
exc_tb: types.TracebackType | None,
|
|
424
|
+
) -> None:
|
|
425
|
+
"""Exit the singleton context."""
|
|
426
|
+
self.close()
|
|
427
|
+
|
|
401
428
|
def start(self) -> None:
|
|
402
429
|
"""Start the singleton context."""
|
|
403
|
-
|
|
404
|
-
if provider.scope == "singleton":
|
|
405
|
-
self.resolve(interface) # noqa
|
|
430
|
+
self._singleton_context.start()
|
|
406
431
|
|
|
407
432
|
def close(self) -> None:
|
|
408
433
|
"""Close the singleton context."""
|
|
@@ -428,6 +453,20 @@ class Container:
|
|
|
428
453
|
yield
|
|
429
454
|
self._request_context_var.reset(token)
|
|
430
455
|
|
|
456
|
+
async def __aenter__(self) -> Self:
|
|
457
|
+
"""Enter the singleton context."""
|
|
458
|
+
await self.astart()
|
|
459
|
+
return self
|
|
460
|
+
|
|
461
|
+
async def __aexit__(
|
|
462
|
+
self,
|
|
463
|
+
exc_type: type[BaseException] | None,
|
|
464
|
+
exc_val: BaseException | None,
|
|
465
|
+
exc_tb: types.TracebackType | None,
|
|
466
|
+
) -> None:
|
|
467
|
+
"""Exit the singleton context."""
|
|
468
|
+
await self.aclose()
|
|
469
|
+
|
|
431
470
|
async def astart(self) -> None:
|
|
432
471
|
"""Start the singleton context asynchronously."""
|
|
433
472
|
for interface, provider in self._providers.items():
|
anydi/_context.py
CHANGED
|
@@ -3,11 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
import abc
|
|
4
4
|
import contextlib
|
|
5
5
|
from types import TracebackType
|
|
6
|
-
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar, cast
|
|
7
7
|
|
|
8
8
|
from typing_extensions import Self, final
|
|
9
9
|
|
|
10
|
-
from ._types import AnyInterface, Interface, Provider
|
|
10
|
+
from ._types import AnyInterface, Interface, Provider, Scope
|
|
11
11
|
from ._utils import run_async
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
@@ -19,6 +19,8 @@ T = TypeVar("T")
|
|
|
19
19
|
class ScopedContext(abc.ABC):
|
|
20
20
|
"""ScopedContext base class."""
|
|
21
21
|
|
|
22
|
+
scope: ClassVar[Scope]
|
|
23
|
+
|
|
22
24
|
def __init__(self, container: Container) -> None:
|
|
23
25
|
self.container = container
|
|
24
26
|
|
|
@@ -233,6 +235,7 @@ class ResourceScopedContext(ScopedContext):
|
|
|
233
235
|
Returns:
|
|
234
236
|
The scoped context.
|
|
235
237
|
"""
|
|
238
|
+
self.start()
|
|
236
239
|
return self
|
|
237
240
|
|
|
238
241
|
def __exit__(
|
|
@@ -251,6 +254,11 @@ class ResourceScopedContext(ScopedContext):
|
|
|
251
254
|
self.close()
|
|
252
255
|
return
|
|
253
256
|
|
|
257
|
+
def start(self) -> None:
|
|
258
|
+
"""Start the scoped context."""
|
|
259
|
+
for interface in self.container._providers_cache.get(self.scope, []): # noqa
|
|
260
|
+
self.container.resolve(interface)
|
|
261
|
+
|
|
254
262
|
def close(self) -> None:
|
|
255
263
|
"""Close the scoped context."""
|
|
256
264
|
self._stack.close()
|
|
@@ -261,6 +269,7 @@ class ResourceScopedContext(ScopedContext):
|
|
|
261
269
|
Returns:
|
|
262
270
|
The scoped context.
|
|
263
271
|
"""
|
|
272
|
+
await self.astart()
|
|
264
273
|
return self
|
|
265
274
|
|
|
266
275
|
async def __aexit__(
|
|
@@ -279,6 +288,11 @@ class ResourceScopedContext(ScopedContext):
|
|
|
279
288
|
await self.aclose()
|
|
280
289
|
return
|
|
281
290
|
|
|
291
|
+
async def astart(self) -> None:
|
|
292
|
+
"""Start the scoped context asynchronously."""
|
|
293
|
+
for interface in self.container._providers_cache.get(self.scope, []): # noqa
|
|
294
|
+
await self.container.aresolve(interface)
|
|
295
|
+
|
|
282
296
|
async def aclose(self) -> None:
|
|
283
297
|
"""Close the scoped context asynchronously."""
|
|
284
298
|
await run_async(self._stack.close)
|
|
@@ -289,16 +303,22 @@ class ResourceScopedContext(ScopedContext):
|
|
|
289
303
|
class SingletonContext(ResourceScopedContext):
|
|
290
304
|
"""A scoped context representing the "singleton" scope."""
|
|
291
305
|
|
|
306
|
+
scope = "singleton"
|
|
307
|
+
|
|
292
308
|
|
|
293
309
|
@final
|
|
294
310
|
class RequestContext(ResourceScopedContext):
|
|
295
311
|
"""A scoped context representing the "request" scope."""
|
|
296
312
|
|
|
313
|
+
scope = "request"
|
|
314
|
+
|
|
297
315
|
|
|
298
316
|
@final
|
|
299
317
|
class TransientContext(ScopedContext):
|
|
300
318
|
"""A scoped context representing the "transient" scope."""
|
|
301
319
|
|
|
320
|
+
scope = "transient"
|
|
321
|
+
|
|
302
322
|
def get(self, interface: Interface[T], provider: Provider) -> T:
|
|
303
323
|
"""Get an instance of a dependency from the transient context.
|
|
304
324
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
|
|
2
|
-
anydi/_container.py,sha256=
|
|
3
|
-
anydi/_context.py,sha256=
|
|
2
|
+
anydi/_container.py,sha256=7G0z8NkVzwZA_kXhyPymuGN-xGPWoCoXccIT4brGWLQ,29168
|
|
3
|
+
anydi/_context.py,sha256=e0VX0fiflzW_2O9w3HvUH3YRCwXHsruQjf3Lu-zXgDw,10815
|
|
4
4
|
anydi/_logger.py,sha256=UpubJUnW83kffFxkhUlObm2DmZX1Pjqoz9YFKS-JOPg,52
|
|
5
5
|
anydi/_module.py,sha256=E1TfLud_Af-MPB83PxIzHVA1jlDW2FGaRP_il1a6y3Y,3675
|
|
6
6
|
anydi/_scanner.py,sha256=cyEk-K2Q8ssZStq8GrxMeEcCuAZMw-RXrjlgWEevKCs,6667
|
|
@@ -21,8 +21,8 @@ anydi/ext/pytest_plugin.py,sha256=nDNqjblVQufLha6P8J8hZw4Q0EuwC71bOI_bdaGm-OQ,40
|
|
|
21
21
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
|
|
23
23
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
-
anydi-0.
|
|
25
|
-
anydi-0.
|
|
26
|
-
anydi-0.
|
|
27
|
-
anydi-0.
|
|
28
|
-
anydi-0.
|
|
24
|
+
anydi-0.26.0a0.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
25
|
+
anydi-0.26.0a0.dist-info/METADATA,sha256=54eUUCdk0kU_oVFlTWh6IGeCNWCCzihHKoKJapNomPw,5162
|
|
26
|
+
anydi-0.26.0a0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
27
|
+
anydi-0.26.0a0.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
|
|
28
|
+
anydi-0.26.0a0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|