anydi 0.36.1a5__py3-none-any.whl → 0.37.1__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 +20 -4
- anydi/_provider.py +7 -0
- anydi/_types.py +12 -12
- anydi/_utils.py +10 -0
- {anydi-0.36.1a5.dist-info → anydi-0.37.1.dist-info}/METADATA +2 -1
- {anydi-0.36.1a5.dist-info → anydi-0.37.1.dist-info}/RECORD +9 -9
- {anydi-0.36.1a5.dist-info → anydi-0.37.1.dist-info}/LICENSE +0 -0
- {anydi-0.36.1a5.dist-info → anydi-0.37.1.dist-info}/WHEEL +0 -0
- {anydi-0.36.1a5.dist-info → anydi-0.37.1.dist-info}/entry_points.txt +0 -0
anydi/_container.py
CHANGED
|
@@ -36,7 +36,9 @@ from ._utils import (
|
|
|
36
36
|
get_full_qualname,
|
|
37
37
|
get_typed_parameters,
|
|
38
38
|
import_string,
|
|
39
|
+
is_async_context_manager,
|
|
39
40
|
is_builtin_type,
|
|
41
|
+
is_context_manager,
|
|
40
42
|
run_async,
|
|
41
43
|
)
|
|
42
44
|
|
|
@@ -553,7 +555,10 @@ class Container:
|
|
|
553
555
|
cm = contextlib.contextmanager(provider.call)(**provider_kwargs)
|
|
554
556
|
return context.enter(cm)
|
|
555
557
|
|
|
556
|
-
|
|
558
|
+
instance = provider.call(**provider_kwargs)
|
|
559
|
+
if context is not None and provider.is_class and is_context_manager(instance):
|
|
560
|
+
context.enter(instance)
|
|
561
|
+
return instance
|
|
557
562
|
|
|
558
563
|
async def _acreate_instance(
|
|
559
564
|
self, provider: Provider, context: InstanceContext | None, /, **defaults: Any
|
|
@@ -584,7 +589,14 @@ class Container:
|
|
|
584
589
|
|
|
585
590
|
return await run_async(_create)
|
|
586
591
|
|
|
587
|
-
|
|
592
|
+
instance = await run_async(provider.call, **provider_kwargs)
|
|
593
|
+
if (
|
|
594
|
+
context is not None
|
|
595
|
+
and provider.is_class
|
|
596
|
+
and is_async_context_manager(instance)
|
|
597
|
+
):
|
|
598
|
+
await context.aenter(instance)
|
|
599
|
+
return instance
|
|
588
600
|
|
|
589
601
|
def _get_provided_kwargs(
|
|
590
602
|
self, provider: Provider, context: InstanceContext | None, /, **defaults: Any
|
|
@@ -627,7 +639,7 @@ class Container:
|
|
|
627
639
|
|
|
628
640
|
# Wrap the instance in a proxy for testing
|
|
629
641
|
if self.testing:
|
|
630
|
-
return InstanceProxy(interface=parameter.annotation
|
|
642
|
+
return InstanceProxy(instance, interface=parameter.annotation)
|
|
631
643
|
return instance
|
|
632
644
|
|
|
633
645
|
async def _aget_provided_kwargs(
|
|
@@ -671,7 +683,7 @@ class Container:
|
|
|
671
683
|
|
|
672
684
|
# Wrap the instance in a proxy for testing
|
|
673
685
|
if self.testing:
|
|
674
|
-
return InstanceProxy(interface=parameter.annotation
|
|
686
|
+
return InstanceProxy(instance, interface=parameter.annotation)
|
|
675
687
|
return instance
|
|
676
688
|
|
|
677
689
|
def _resolve_parameter(
|
|
@@ -776,6 +788,10 @@ class Container:
|
|
|
776
788
|
"""
|
|
777
789
|
Override the provider for the specified interface with a specific instance.
|
|
778
790
|
"""
|
|
791
|
+
if not self.testing:
|
|
792
|
+
raise RuntimeError(
|
|
793
|
+
"The `override` method can only be used in testing mode."
|
|
794
|
+
)
|
|
779
795
|
if not self.is_registered(interface) and self.strict:
|
|
780
796
|
raise LookupError(
|
|
781
797
|
f"The provider interface `{get_full_qualname(interface)}` "
|
anydi/_provider.py
CHANGED
|
@@ -38,6 +38,7 @@ class Provider:
|
|
|
38
38
|
"_kind",
|
|
39
39
|
"_interface",
|
|
40
40
|
"_parameters",
|
|
41
|
+
"_is_class",
|
|
41
42
|
"_is_coroutine",
|
|
42
43
|
"_is_generator",
|
|
43
44
|
"_is_async_generator",
|
|
@@ -57,6 +58,7 @@ class Provider:
|
|
|
57
58
|
# Detect the kind of callable provider
|
|
58
59
|
self._detect_kind()
|
|
59
60
|
|
|
61
|
+
self._is_class = self._kind == CallableKind.CLASS
|
|
60
62
|
self._is_coroutine = self._kind == CallableKind.COROUTINE
|
|
61
63
|
self._is_generator = self._kind == CallableKind.GENERATOR
|
|
62
64
|
self._is_async_generator = self._kind == CallableKind.ASYNC_GENERATOR
|
|
@@ -107,6 +109,11 @@ class Provider:
|
|
|
107
109
|
def parameters(self) -> list[inspect.Parameter]:
|
|
108
110
|
return self._parameters
|
|
109
111
|
|
|
112
|
+
@property
|
|
113
|
+
def is_class(self) -> bool:
|
|
114
|
+
"""Check if the provider is a class."""
|
|
115
|
+
return self._is_class
|
|
116
|
+
|
|
110
117
|
@property
|
|
111
118
|
def is_coroutine(self) -> bool:
|
|
112
119
|
"""Check if the provider is a coroutine."""
|
anydi/_types.py
CHANGED
|
@@ -5,6 +5,7 @@ from collections.abc import Iterable
|
|
|
5
5
|
from types import ModuleType
|
|
6
6
|
from typing import Annotated, Any, NamedTuple, Union
|
|
7
7
|
|
|
8
|
+
import wrapt
|
|
8
9
|
from typing_extensions import Literal, Self, TypeAlias
|
|
9
10
|
|
|
10
11
|
Scope = Literal["transient", "singleton", "request"]
|
|
@@ -37,20 +38,19 @@ def is_event_type(obj: Any) -> bool:
|
|
|
37
38
|
return inspect.isclass(obj) and issubclass(obj, Event)
|
|
38
39
|
|
|
39
40
|
|
|
40
|
-
class InstanceProxy:
|
|
41
|
-
|
|
41
|
+
class InstanceProxy(wrapt.ObjectProxy): # type: ignore[misc]
|
|
42
|
+
def __init__(self, wrapped: Any, *, interface: type[Any]) -> None:
|
|
43
|
+
super().__init__(wrapped)
|
|
44
|
+
self._self_interface = interface
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
self.
|
|
46
|
+
@property
|
|
47
|
+
def interface(self) -> type[Any]:
|
|
48
|
+
return self._self_interface
|
|
46
49
|
|
|
47
|
-
def __getattribute__(self,
|
|
48
|
-
if
|
|
49
|
-
return object.__getattribute__(self,
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
def __repr__(self) -> str:
|
|
53
|
-
return f"InstanceProxy({self.interface!r})"
|
|
50
|
+
def __getattribute__(self, item: str) -> Any:
|
|
51
|
+
if item in "interface":
|
|
52
|
+
return object.__getattribute__(self, item)
|
|
53
|
+
return object.__getattribute__(self, item)
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
class ProviderDecoratorArgs(NamedTuple):
|
anydi/_utils.py
CHANGED
|
@@ -44,6 +44,16 @@ def is_builtin_type(tp: type[Any]) -> bool:
|
|
|
44
44
|
return tp.__module__ == builtins.__name__
|
|
45
45
|
|
|
46
46
|
|
|
47
|
+
def is_context_manager(obj: Any) -> bool:
|
|
48
|
+
"""Check if the given object is a context manager."""
|
|
49
|
+
return hasattr(obj, "__enter__") and hasattr(obj, "__exit__")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def is_async_context_manager(obj: Any) -> bool:
|
|
53
|
+
"""Check if the given object is an async context manager."""
|
|
54
|
+
return hasattr(obj, "__aenter__") and hasattr(obj, "__aexit__")
|
|
55
|
+
|
|
56
|
+
|
|
47
57
|
def get_typed_annotation(
|
|
48
58
|
annotation: Any, globalns: dict[str, Any], module: Any = None
|
|
49
59
|
) -> Any:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anydi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.37.1
|
|
4
4
|
Summary: Dependency Injection library
|
|
5
5
|
Home-page: https://github.com/antonrh/anydi
|
|
6
6
|
License: MIT
|
|
@@ -33,6 +33,7 @@ Requires-Dist: anyio (>=3.7.1)
|
|
|
33
33
|
Requires-Dist: mkdocs (>=1.4.2,<2.0.0) ; extra == "docs"
|
|
34
34
|
Requires-Dist: mkdocs-material (>=9.5.29,<10.0.0) ; extra == "docs"
|
|
35
35
|
Requires-Dist: typing-extensions (>=4.12.1,<5.0.0)
|
|
36
|
+
Requires-Dist: wrapt (>=1.17.0,<2.0.0)
|
|
36
37
|
Project-URL: Repository, https://github.com/antonrh/anydi
|
|
37
38
|
Description-Content-Type: text/markdown
|
|
38
39
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
anydi/__init__.py,sha256=OfRg2EfXD65pHTGQKhfkABMwUhw5LvsuTQV_Tv4V4wk,501
|
|
2
|
-
anydi/_container.py,sha256=
|
|
2
|
+
anydi/_container.py,sha256=6dr2sOSkx8GRdqzlokHB5McfBNOWp_9ozyyiS5dpxoE,38320
|
|
3
3
|
anydi/_context.py,sha256=7LV_SL4QWkJeiG7_4D9PZ5lmU-MPzhofxC95zCgY9Gc,2651
|
|
4
|
-
anydi/_provider.py,sha256=
|
|
5
|
-
anydi/_types.py,sha256=
|
|
6
|
-
anydi/_utils.py,sha256=
|
|
4
|
+
anydi/_provider.py,sha256=1IyxHO83NHjsPDHLDIZtW1pJ7i8VpWD3EM4T6duw9zA,7661
|
|
5
|
+
anydi/_types.py,sha256=fdO4xNXtGMxVArmlfDkFYbyR895ixkBTW6V8lMceN7Q,1562
|
|
6
|
+
anydi/_utils.py,sha256=INI0jNIXrJ6LS4zqJymMO2yUEobpxmBGASf4G_vR6AU,4378
|
|
7
7
|
anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
anydi/ext/_utils.py,sha256=U6sRqWzccWUu7eMhbXX1NrwcaxitQF9cO1KxnKF37gw,2566
|
|
9
9
|
anydi/ext/django/__init__.py,sha256=QI1IABCVgSDTUoh7M9WMECKXwB3xvh04HfQ9TOWw1Mk,223
|
|
@@ -22,8 +22,8 @@ anydi/ext/pytest_plugin.py,sha256=ShGhiZnP1KyMHhnc9Ci1RKAuHVhw628OTS2P2BLEOfc,50
|
|
|
22
22
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
anydi/ext/starlette/middleware.py,sha256=9CQtGg5ZzUz2gFSzJr8U4BWzwNjK8XMctm3n52M77Z0,792
|
|
24
24
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
anydi-0.
|
|
26
|
-
anydi-0.
|
|
27
|
-
anydi-0.
|
|
28
|
-
anydi-0.
|
|
29
|
-
anydi-0.
|
|
25
|
+
anydi-0.37.1.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
26
|
+
anydi-0.37.1.dist-info/METADATA,sha256=9pkB0M7YtPuvIXxskF0h7roe7FY_R90rHZ6772w2LSI,5103
|
|
27
|
+
anydi-0.37.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
28
|
+
anydi-0.37.1.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
|
|
29
|
+
anydi-0.37.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|