modern-di 0.16.3__py3-none-any.whl → 0.17.0__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.
Potentially problematic release.
This version of modern-di might be problematic. Click here for more details.
- modern_di/__init__.py +6 -4
- modern_di/containers/__init__.py +0 -0
- modern_di/containers/abstract.py +110 -0
- modern_di/containers/async_container.py +104 -0
- modern_di/containers/sync_container.py +105 -0
- modern_di/group.py +26 -0
- modern_di/helpers/type_helpers.py +33 -0
- modern_di/providers/__init__.py +2 -4
- modern_di/providers/abstract.py +62 -74
- modern_di/providers/async_factory.py +9 -11
- modern_di/providers/async_singleton.py +14 -26
- modern_di/providers/container_provider.py +4 -8
- modern_di/providers/context_provider.py +16 -0
- modern_di/providers/dict.py +20 -13
- modern_di/providers/factory.py +17 -23
- modern_di/providers/list.py +20 -13
- modern_di/providers/object.py +6 -11
- modern_di/providers/resource.py +38 -66
- modern_di/providers/singleton.py +23 -43
- modern_di/registries/__init__.py +0 -0
- modern_di/registries/context_registry.py +16 -0
- modern_di/registries/overrides_registry.py +22 -0
- modern_di/registries/providers_registry.py +38 -0
- modern_di/registries/state_registry/__init__.py +0 -0
- modern_di/{provider_state.py → registries/state_registry/state.py} +15 -11
- modern_di/registries/state_registry/state_registry.py +52 -0
- {modern_di-0.16.3.dist-info → modern_di-0.17.0.dist-info}/METADATA +1 -1
- modern_di-0.17.0.dist-info/RECORD +33 -0
- modern_di/container.py +0 -171
- modern_di/graph.py +0 -39
- modern_di/providers/context_adapter.py +0 -27
- modern_di/providers/injected_factory.py +0 -45
- modern_di/providers/selector.py +0 -39
- modern_di-0.16.3.dist-info/RECORD +0 -25
- {modern_di-0.16.3.dist-info → modern_di-0.17.0.dist-info}/WHEEL +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
-
from modern_di import Container
|
|
5
4
|
from modern_di.providers.abstract import AbstractCreatorProvider
|
|
5
|
+
from modern_di.registries.state_registry.state import AsyncState
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
T_co = typing.TypeVar("T_co", covariant=True)
|
|
@@ -11,6 +11,7 @@ P = typing.ParamSpec("P")
|
|
|
11
11
|
|
|
12
12
|
class AsyncSingleton(AbstractCreatorProvider[T_co]):
|
|
13
13
|
__slots__ = AbstractCreatorProvider.BASE_SLOTS
|
|
14
|
+
HAS_STATE = True
|
|
14
15
|
|
|
15
16
|
def __init__(
|
|
16
17
|
self,
|
|
@@ -20,30 +21,17 @@ class AsyncSingleton(AbstractCreatorProvider[T_co]):
|
|
|
20
21
|
**kwargs: P.kwargs,
|
|
21
22
|
) -> None:
|
|
22
23
|
super().__init__(scope, creator, *args, **kwargs)
|
|
24
|
+
self.is_async = True
|
|
23
25
|
|
|
24
|
-
async def async_resolve(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
provider_state
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
await
|
|
35
|
-
|
|
36
|
-
try:
|
|
37
|
-
if provider_state.instance is not None:
|
|
38
|
-
return typing.cast(T_co, provider_state.instance)
|
|
39
|
-
|
|
40
|
-
coroutine: typing.Awaitable[T_co] = await self._async_build_creator(container)
|
|
41
|
-
provider_state.instance = await coroutine
|
|
42
|
-
finally:
|
|
43
|
-
provider_state.asyncio_lock.release()
|
|
44
|
-
|
|
26
|
+
async def async_resolve(
|
|
27
|
+
self,
|
|
28
|
+
*,
|
|
29
|
+
args: list[typing.Any],
|
|
30
|
+
kwargs: dict[str, typing.Any],
|
|
31
|
+
provider_state: AsyncState[T_co] | None,
|
|
32
|
+
**__: object,
|
|
33
|
+
) -> T_co:
|
|
34
|
+
assert provider_state
|
|
35
|
+
coroutine: typing.Awaitable[T_co] = self._creator(*args, **kwargs)
|
|
36
|
+
provider_state.instance = await coroutine
|
|
45
37
|
return provider_state.instance
|
|
46
|
-
|
|
47
|
-
def sync_resolve(self, _: Container) -> typing.NoReturn:
|
|
48
|
-
msg = "AsyncSingleton cannot be resolved synchronously"
|
|
49
|
-
raise RuntimeError(msg)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import enum
|
|
1
2
|
import typing
|
|
2
3
|
|
|
3
|
-
import modern_di
|
|
4
|
-
from modern_di import Container
|
|
5
4
|
from modern_di.providers import AbstractProvider
|
|
6
5
|
|
|
7
6
|
|
|
@@ -9,11 +8,8 @@ T_co = typing.TypeVar("T_co", covariant=True)
|
|
|
9
8
|
P = typing.ParamSpec("P")
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class ContainerProvider(AbstractProvider[
|
|
11
|
+
class ContainerProvider(AbstractProvider[typing.Any]):
|
|
13
12
|
__slots__ = AbstractProvider.BASE_SLOTS
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def sync_resolve(self, container: Container) -> modern_di.Container:
|
|
19
|
-
return container.find_container(self.scope)
|
|
14
|
+
def __init__(self, scope: enum.IntEnum) -> None:
|
|
15
|
+
super().__init__(scope)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from modern_di.providers import AbstractProvider
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
T_co = typing.TypeVar("T_co", covariant=True)
|
|
8
|
+
P = typing.ParamSpec("P")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ContextProvider(AbstractProvider[T_co]):
|
|
12
|
+
__slots__ = [*AbstractProvider.BASE_SLOTS, "context_type", "required"]
|
|
13
|
+
|
|
14
|
+
def __init__(self, scope: enum.IntEnum, context_type: type[T_co]) -> None:
|
|
15
|
+
super().__init__(scope)
|
|
16
|
+
self.context_type = context_type
|
modern_di/providers/dict.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
-
from modern_di import Container
|
|
5
4
|
from modern_di.providers.abstract import AbstractProvider
|
|
6
5
|
|
|
7
6
|
|
|
@@ -9,15 +8,23 @@ T_co = typing.TypeVar("T_co", covariant=True)
|
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class Dict(AbstractProvider[dict[str, T_co]]):
|
|
12
|
-
__slots__ =
|
|
13
|
-
|
|
14
|
-
def __init__(self, scope: enum.IntEnum, **
|
|
15
|
-
super().__init__(scope)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
11
|
+
__slots__ = AbstractProvider.BASE_SLOTS
|
|
12
|
+
|
|
13
|
+
def __init__(self, scope: enum.IntEnum, **kwargs: AbstractProvider[T_co]) -> None:
|
|
14
|
+
super().__init__(scope, kwargs=kwargs)
|
|
15
|
+
|
|
16
|
+
async def async_resolve(
|
|
17
|
+
self,
|
|
18
|
+
*,
|
|
19
|
+
kwargs: dict[str, typing.Any] | None,
|
|
20
|
+
**__: object,
|
|
21
|
+
) -> dict[str, T_co]:
|
|
22
|
+
return kwargs or {}
|
|
23
|
+
|
|
24
|
+
def sync_resolve(
|
|
25
|
+
self,
|
|
26
|
+
*,
|
|
27
|
+
kwargs: dict[str, typing.Any] | None,
|
|
28
|
+
**__: object,
|
|
29
|
+
) -> dict[str, T_co]:
|
|
30
|
+
return kwargs or {}
|
modern_di/providers/factory.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
-
from modern_di import Container
|
|
5
4
|
from modern_di.providers.abstract import AbstractCreatorProvider
|
|
6
|
-
from modern_di.providers.injected_factory import AsyncInjectedFactory, SyncInjectedFactory
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
T_co = typing.TypeVar("T_co", covariant=True)
|
|
@@ -22,24 +20,20 @@ class Factory(AbstractCreatorProvider[T_co]):
|
|
|
22
20
|
) -> None:
|
|
23
21
|
super().__init__(scope, creator, *args, **kwargs)
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (override := container.fetch_override(self.provider_id)) is not None:
|
|
43
|
-
return typing.cast(T_co, override)
|
|
44
|
-
|
|
45
|
-
return typing.cast(T_co, self._sync_build_creator(container))
|
|
23
|
+
async def async_resolve(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
args: list[typing.Any],
|
|
27
|
+
kwargs: dict[str, typing.Any],
|
|
28
|
+
**__: object,
|
|
29
|
+
) -> T_co:
|
|
30
|
+
return typing.cast(T_co, self._creator(*args, **kwargs))
|
|
31
|
+
|
|
32
|
+
def sync_resolve(
|
|
33
|
+
self,
|
|
34
|
+
*,
|
|
35
|
+
args: list[typing.Any],
|
|
36
|
+
kwargs: dict[str, typing.Any],
|
|
37
|
+
**__: object,
|
|
38
|
+
) -> T_co:
|
|
39
|
+
return typing.cast(T_co, self._creator(*args, **kwargs))
|
modern_di/providers/list.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
-
from modern_di import Container
|
|
5
4
|
from modern_di.providers.abstract import AbstractProvider
|
|
6
5
|
|
|
7
6
|
|
|
@@ -9,15 +8,23 @@ T_co = typing.TypeVar("T_co", covariant=True)
|
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class List(AbstractProvider[list[T_co]]):
|
|
12
|
-
__slots__ =
|
|
13
|
-
|
|
14
|
-
def __init__(self, scope: enum.IntEnum, *
|
|
15
|
-
super().__init__(scope)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
11
|
+
__slots__ = AbstractProvider.BASE_SLOTS
|
|
12
|
+
|
|
13
|
+
def __init__(self, scope: enum.IntEnum, *args: AbstractProvider[T_co]) -> None:
|
|
14
|
+
super().__init__(scope, args=list(args))
|
|
15
|
+
|
|
16
|
+
async def async_resolve(
|
|
17
|
+
self,
|
|
18
|
+
*,
|
|
19
|
+
args: list[typing.Any] | None,
|
|
20
|
+
**__: object,
|
|
21
|
+
) -> list[T_co]:
|
|
22
|
+
return args or []
|
|
23
|
+
|
|
24
|
+
def sync_resolve(
|
|
25
|
+
self,
|
|
26
|
+
*,
|
|
27
|
+
args: list[typing.Any] | None,
|
|
28
|
+
**__: object,
|
|
29
|
+
) -> list[T_co]:
|
|
30
|
+
return args or []
|
modern_di/providers/object.py
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
-
from modern_di import
|
|
5
|
-
from modern_di.providers.abstract import AbstractOverrideProvider
|
|
4
|
+
from modern_di.providers.abstract import AbstractProvider
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
T_co = typing.TypeVar("T_co", covariant=True)
|
|
9
8
|
P = typing.ParamSpec("P")
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class Object(
|
|
13
|
-
__slots__ = [*
|
|
11
|
+
class Object(AbstractProvider[T_co]):
|
|
12
|
+
__slots__ = [*AbstractProvider.BASE_SLOTS, "_obj"]
|
|
14
13
|
|
|
15
14
|
def __init__(self, scope: enum.IntEnum, obj: T_co) -> None:
|
|
16
15
|
super().__init__(scope)
|
|
17
16
|
self._obj: typing.Final = obj
|
|
18
17
|
|
|
19
|
-
async def async_resolve(self,
|
|
20
|
-
return self.
|
|
21
|
-
|
|
22
|
-
def sync_resolve(self, container: Container) -> T_co:
|
|
23
|
-
container = container.find_container(self.scope)
|
|
24
|
-
if (override := container.fetch_override(self.provider_id)) is not None:
|
|
25
|
-
return typing.cast(T_co, override)
|
|
18
|
+
async def async_resolve(self, *_: object, **__: object) -> T_co:
|
|
19
|
+
return self._obj
|
|
26
20
|
|
|
21
|
+
def sync_resolve(self, *_: object, **__: object) -> T_co:
|
|
27
22
|
return self._obj
|
modern_di/providers/resource.py
CHANGED
|
@@ -3,8 +3,8 @@ import enum
|
|
|
3
3
|
import inspect
|
|
4
4
|
import typing
|
|
5
5
|
|
|
6
|
-
from modern_di import Container
|
|
7
6
|
from modern_di.providers.abstract import AbstractCreatorProvider
|
|
7
|
+
from modern_di.registries.state_registry.state import AsyncState, SyncState
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
T_co = typing.TypeVar("T_co", covariant=True)
|
|
@@ -12,13 +12,14 @@ P = typing.ParamSpec("P")
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class Resource(AbstractCreatorProvider[T_co]):
|
|
15
|
-
__slots__ =
|
|
15
|
+
__slots__ = AbstractCreatorProvider.BASE_SLOTS
|
|
16
|
+
HAS_STATE = True
|
|
16
17
|
|
|
17
18
|
def _is_creator_async(
|
|
18
19
|
self,
|
|
19
20
|
_: contextlib.AbstractContextManager[T_co] | contextlib.AbstractAsyncContextManager[T_co],
|
|
20
21
|
) -> typing.TypeGuard[contextlib.AbstractAsyncContextManager[T_co]]:
|
|
21
|
-
return self.
|
|
22
|
+
return self.is_async
|
|
22
23
|
|
|
23
24
|
def __init__(
|
|
24
25
|
self,
|
|
@@ -35,85 +36,56 @@ class Resource(AbstractCreatorProvider[T_co]):
|
|
|
35
36
|
) -> None:
|
|
36
37
|
new_creator: typing.Any
|
|
37
38
|
if inspect.isasyncgenfunction(creator):
|
|
38
|
-
|
|
39
|
+
is_async = True
|
|
39
40
|
new_creator = contextlib.asynccontextmanager(creator)
|
|
40
41
|
elif inspect.isgeneratorfunction(creator):
|
|
41
|
-
|
|
42
|
+
is_async = False
|
|
42
43
|
new_creator = contextlib.contextmanager(creator)
|
|
43
44
|
elif isinstance(creator, type) and issubclass(creator, typing.AsyncContextManager):
|
|
44
|
-
|
|
45
|
+
is_async = True
|
|
45
46
|
new_creator = creator
|
|
46
47
|
elif isinstance(creator, type) and issubclass(creator, typing.ContextManager):
|
|
47
|
-
|
|
48
|
+
is_async = False
|
|
48
49
|
new_creator = creator
|
|
49
50
|
else:
|
|
50
51
|
msg = "Unsupported resource type"
|
|
51
52
|
raise TypeError(msg)
|
|
52
53
|
|
|
53
54
|
super().__init__(scope, new_creator, *args, **kwargs)
|
|
55
|
+
self.is_async = is_async
|
|
54
56
|
|
|
55
|
-
async def async_resolve(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
provider_state
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
await provider_state.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return typing.cast(T_co, provider_state.instance)
|
|
72
|
-
|
|
73
|
-
_intermediate_ = await self._async_build_creator(container)
|
|
74
|
-
|
|
75
|
-
if self._is_creator_async(self._creator): # type: ignore[arg-type]
|
|
76
|
-
provider_state.context_stack = contextlib.AsyncExitStack()
|
|
77
|
-
provider_state.instance = await provider_state.context_stack.enter_async_context(_intermediate_)
|
|
78
|
-
else:
|
|
79
|
-
provider_state.context_stack = contextlib.ExitStack()
|
|
80
|
-
provider_state.instance = provider_state.context_stack.enter_context(_intermediate_)
|
|
81
|
-
finally:
|
|
82
|
-
if provider_state.asyncio_lock:
|
|
83
|
-
provider_state.asyncio_lock.release()
|
|
57
|
+
async def async_resolve(
|
|
58
|
+
self,
|
|
59
|
+
*,
|
|
60
|
+
args: list[typing.Any],
|
|
61
|
+
kwargs: dict[str, typing.Any],
|
|
62
|
+
provider_state: AsyncState[T_co] | None,
|
|
63
|
+
**_: object,
|
|
64
|
+
) -> T_co:
|
|
65
|
+
assert provider_state
|
|
66
|
+
_intermediate_ = self._creator(*args, **kwargs)
|
|
67
|
+
if self._is_creator_async(self._creator): # type: ignore[arg-type]
|
|
68
|
+
provider_state.context_stack = contextlib.AsyncExitStack()
|
|
69
|
+
provider_state.instance = await provider_state.context_stack.enter_async_context(_intermediate_)
|
|
70
|
+
else:
|
|
71
|
+
provider_state.context_stack = contextlib.ExitStack()
|
|
72
|
+
provider_state.instance = provider_state.context_stack.enter_context(_intermediate_)
|
|
84
73
|
|
|
85
74
|
return typing.cast(T_co, provider_state.instance)
|
|
86
75
|
|
|
87
|
-
def sync_resolve(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
provider_state
|
|
93
|
-
|
|
76
|
+
def sync_resolve(
|
|
77
|
+
self,
|
|
78
|
+
*,
|
|
79
|
+
args: list[typing.Any],
|
|
80
|
+
kwargs: dict[str, typing.Any],
|
|
81
|
+
provider_state: SyncState[T_co] | None,
|
|
82
|
+
**_: object,
|
|
83
|
+
) -> T_co:
|
|
84
|
+
assert provider_state
|
|
85
|
+
_intermediate_ = self._creator(*args, **kwargs)
|
|
86
|
+
provider_state.context_stack = contextlib.ExitStack()
|
|
87
|
+
provider_state.instance = provider_state.context_stack.enter_context(
|
|
88
|
+
typing.cast(contextlib.AbstractContextManager[typing.Any], _intermediate_)
|
|
94
89
|
)
|
|
95
|
-
if provider_state.instance is not None:
|
|
96
|
-
return typing.cast(T_co, provider_state.instance)
|
|
97
|
-
|
|
98
|
-
if self._is_async:
|
|
99
|
-
msg = "Async resource cannot be resolved synchronously"
|
|
100
|
-
raise RuntimeError(msg)
|
|
101
|
-
|
|
102
|
-
if provider_state.threading_lock:
|
|
103
|
-
provider_state.threading_lock.acquire()
|
|
104
|
-
|
|
105
|
-
try:
|
|
106
|
-
if provider_state.instance is not None:
|
|
107
|
-
return typing.cast(T_co, provider_state.instance)
|
|
108
|
-
|
|
109
|
-
_intermediate_ = self._sync_build_creator(container)
|
|
110
|
-
|
|
111
|
-
provider_state.context_stack = contextlib.ExitStack()
|
|
112
|
-
provider_state.instance = provider_state.context_stack.enter_context(
|
|
113
|
-
typing.cast(contextlib.AbstractContextManager[typing.Any], _intermediate_)
|
|
114
|
-
)
|
|
115
|
-
finally:
|
|
116
|
-
if provider_state.threading_lock:
|
|
117
|
-
provider_state.threading_lock.release()
|
|
118
90
|
|
|
119
91
|
return typing.cast(T_co, provider_state.instance)
|
modern_di/providers/singleton.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
-
from modern_di import Container
|
|
5
4
|
from modern_di.providers.abstract import AbstractCreatorProvider
|
|
5
|
+
from modern_di.registries.state_registry.state import AsyncState, SyncState
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
T_co = typing.TypeVar("T_co", covariant=True)
|
|
@@ -11,6 +11,7 @@ P = typing.ParamSpec("P")
|
|
|
11
11
|
|
|
12
12
|
class Singleton(AbstractCreatorProvider[T_co]):
|
|
13
13
|
__slots__ = AbstractCreatorProvider.BASE_SLOTS
|
|
14
|
+
HAS_STATE = True
|
|
14
15
|
|
|
15
16
|
def __init__(
|
|
16
17
|
self,
|
|
@@ -21,47 +22,26 @@ class Singleton(AbstractCreatorProvider[T_co]):
|
|
|
21
22
|
) -> None:
|
|
22
23
|
super().__init__(scope, creator, *args, **kwargs)
|
|
23
24
|
|
|
24
|
-
async def async_resolve(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
provider_state
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
await provider_state.asyncio_lock.acquire()
|
|
35
|
-
|
|
36
|
-
try:
|
|
37
|
-
if provider_state.instance is not None:
|
|
38
|
-
return typing.cast(T_co, provider_state.instance)
|
|
39
|
-
|
|
40
|
-
provider_state.instance = typing.cast(T_co, await self._async_build_creator(container))
|
|
41
|
-
finally:
|
|
42
|
-
provider_state.asyncio_lock.release()
|
|
43
|
-
|
|
25
|
+
async def async_resolve(
|
|
26
|
+
self,
|
|
27
|
+
*,
|
|
28
|
+
args: list[typing.Any],
|
|
29
|
+
kwargs: dict[str, typing.Any],
|
|
30
|
+
provider_state: AsyncState[T_co] | None,
|
|
31
|
+
**__: object,
|
|
32
|
+
) -> T_co:
|
|
33
|
+
assert provider_state
|
|
34
|
+
provider_state.instance = self._creator(*args, **kwargs)
|
|
44
35
|
return provider_state.instance
|
|
45
36
|
|
|
46
|
-
def sync_resolve(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
provider_state
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
if provider_state.instance is not None:
|
|
60
|
-
return typing.cast(T_co, provider_state.instance)
|
|
61
|
-
|
|
62
|
-
provider_state.instance = self._sync_build_creator(container)
|
|
63
|
-
finally:
|
|
64
|
-
if provider_state.threading_lock:
|
|
65
|
-
provider_state.threading_lock.release()
|
|
66
|
-
|
|
67
|
-
return typing.cast(T_co, provider_state.instance)
|
|
37
|
+
def sync_resolve(
|
|
38
|
+
self,
|
|
39
|
+
*,
|
|
40
|
+
args: list[typing.Any],
|
|
41
|
+
kwargs: dict[str, typing.Any],
|
|
42
|
+
provider_state: SyncState[T_co] | None,
|
|
43
|
+
**__: object,
|
|
44
|
+
) -> T_co:
|
|
45
|
+
assert provider_state
|
|
46
|
+
provider_state.instance = self._creator(*args, **kwargs)
|
|
47
|
+
return provider_state.instance
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
T_co = typing.TypeVar("T_co", covariant=True)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclasses.dataclass(slots=True, frozen=True)
|
|
9
|
+
class ContextRegistry:
|
|
10
|
+
context: dict[type[typing.Any], typing.Any]
|
|
11
|
+
|
|
12
|
+
def find_context(self, context_type: type[T_co]) -> T_co | None:
|
|
13
|
+
if context_type and (context := self.context.get(context_type)):
|
|
14
|
+
return typing.cast(T_co, context)
|
|
15
|
+
|
|
16
|
+
return None
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
T_co = typing.TypeVar("T_co", covariant=True)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
|
|
9
|
+
class OverridesRegistry:
|
|
10
|
+
overrides: dict[str, typing.Any] = dataclasses.field(init=False, default_factory=dict)
|
|
11
|
+
|
|
12
|
+
def override(self, provider_id: str, override_object: object) -> None:
|
|
13
|
+
self.overrides[provider_id] = override_object
|
|
14
|
+
|
|
15
|
+
def reset_override(self, provider_id: str | None = None) -> None:
|
|
16
|
+
if provider_id is None:
|
|
17
|
+
self.overrides.clear()
|
|
18
|
+
else:
|
|
19
|
+
self.overrides.pop(provider_id, None)
|
|
20
|
+
|
|
21
|
+
def fetch_override(self, provider_id: str) -> object | None:
|
|
22
|
+
return self.overrides.get(provider_id)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
from modern_di.providers.abstract import AbstractProvider
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
T_co = typing.TypeVar("T_co", covariant=True)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclasses.dataclass(slots=True, frozen=True)
|
|
12
|
+
class ProvidersRegistry:
|
|
13
|
+
providers_by_name: dict[str, AbstractProvider[typing.Any]] = dataclasses.field(init=False, default_factory=dict)
|
|
14
|
+
providers_by_type: dict[type, AbstractProvider[typing.Any]] = dataclasses.field(init=False, default_factory=dict)
|
|
15
|
+
|
|
16
|
+
def find_provider(
|
|
17
|
+
self, dependency_name: str | None = None, dependency_type: type[T_co] | None = None
|
|
18
|
+
) -> AbstractProvider[T_co] | None:
|
|
19
|
+
if dependency_name and (provider := self.providers_by_name.get(dependency_name)):
|
|
20
|
+
return provider
|
|
21
|
+
|
|
22
|
+
if dependency_type and (provider := self.providers_by_type.get(dependency_type)):
|
|
23
|
+
return provider
|
|
24
|
+
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
def add_providers(self, **kwargs: AbstractProvider[typing.Any]) -> None:
|
|
28
|
+
if duplicates_by_name := set(self.providers_by_name.keys()) & set(kwargs.keys()):
|
|
29
|
+
warnings.warn(f"Duplicated by name providers {duplicates_by_name}", RuntimeWarning, stacklevel=2)
|
|
30
|
+
|
|
31
|
+
self.providers_by_name.update(kwargs)
|
|
32
|
+
|
|
33
|
+
if duplicates_by_type := set(self.providers_by_type.keys()) & {
|
|
34
|
+
x.bound_type for x in kwargs.values() if x.bound_type
|
|
35
|
+
}:
|
|
36
|
+
warnings.warn(f"Duplicated by type providers {duplicates_by_type}", RuntimeWarning, stacklevel=2)
|
|
37
|
+
|
|
38
|
+
self.providers_by_type.update({x.bound_type: x for x in kwargs.values() if x.bound_type})
|
|
File without changes
|
|
@@ -7,16 +7,15 @@ import typing
|
|
|
7
7
|
T_co = typing.TypeVar("T_co", covariant=True)
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class
|
|
11
|
-
__slots__ = "
|
|
10
|
+
class AsyncState(typing.Generic[T_co]):
|
|
11
|
+
__slots__ = "context_stack", "instance", "lock", "use_lock"
|
|
12
12
|
|
|
13
|
-
def __init__(self,
|
|
13
|
+
def __init__(self, use_lock: bool = True) -> None:
|
|
14
|
+
self.lock: typing.Final = asyncio.Lock() if use_lock else None
|
|
14
15
|
self.context_stack: contextlib.AsyncExitStack | contextlib.ExitStack | None = None
|
|
15
16
|
self.instance: T_co | None = None
|
|
16
|
-
self.asyncio_lock: typing.Final = asyncio.Lock() if use_asyncio_lock else None
|
|
17
|
-
self.threading_lock: typing.Final = threading.Lock() if use_threading_lock else None
|
|
18
17
|
|
|
19
|
-
async def
|
|
18
|
+
async def tear_down(self) -> None:
|
|
20
19
|
if self.context_stack is None:
|
|
21
20
|
return
|
|
22
21
|
|
|
@@ -27,14 +26,19 @@ class ProviderState(typing.Generic[T_co]):
|
|
|
27
26
|
self.context_stack = None
|
|
28
27
|
self.instance = None
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
|
|
30
|
+
class SyncState(typing.Generic[T_co]):
|
|
31
|
+
__slots__ = "context_stack", "instance", "lock", "use_lock"
|
|
32
|
+
|
|
33
|
+
def __init__(self, use_lock: bool = True) -> None:
|
|
34
|
+
self.lock: typing.Final = threading.Lock() if use_lock else None
|
|
35
|
+
self.context_stack: contextlib.ExitStack | None = None
|
|
36
|
+
self.instance: T_co | None = None
|
|
37
|
+
|
|
38
|
+
def tear_down(self) -> None:
|
|
31
39
|
if self.context_stack is None:
|
|
32
40
|
return
|
|
33
41
|
|
|
34
|
-
if isinstance(self.context_stack, contextlib.AsyncExitStack):
|
|
35
|
-
msg = "Cannot tear down async context in `sync_tear_down`"
|
|
36
|
-
raise RuntimeError(msg) # noqa: TRY004
|
|
37
|
-
|
|
38
42
|
self.context_stack.close()
|
|
39
43
|
self.context_stack = None
|
|
40
44
|
self.instance = None
|