python-injection 0.8.5__py3-none-any.whl → 0.9.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 python-injection might be problematic. Click here for more details.
- injection/__init__.pyi +44 -38
- injection/common/event.py +3 -3
- injection/common/invertible.py +6 -8
- injection/common/lazy.py +9 -14
- injection/common/tools/threading.py +1 -3
- injection/common/tools/type.py +52 -27
- injection/core/module.py +113 -94
- injection/exceptions.py +4 -6
- injection/integrations/blacksheep.py +2 -4
- {python_injection-0.8.5.dist-info → python_injection-0.9.0.dist-info}/METADATA +2 -4
- python_injection-0.9.0.dist-info/RECORD +19 -0
- python_injection-0.8.5.dist-info/RECORD +0 -19
- {python_injection-0.8.5.dist-info → python_injection-0.9.0.dist-info}/WHEEL +0 -0
injection/__init__.pyi
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
-
from collections.abc import Callable
|
|
2
|
+
from collections.abc import Callable
|
|
3
3
|
from contextlib import ContextDecorator
|
|
4
|
-
from enum import
|
|
4
|
+
from enum import StrEnum
|
|
5
5
|
from types import UnionType
|
|
6
6
|
from typing import (
|
|
7
7
|
Any,
|
|
8
8
|
ContextManager,
|
|
9
9
|
Final,
|
|
10
|
-
Literal,
|
|
11
10
|
Protocol,
|
|
12
|
-
|
|
11
|
+
Self,
|
|
13
12
|
final,
|
|
14
13
|
runtime_checkable,
|
|
15
14
|
)
|
|
16
15
|
|
|
17
16
|
from .common.invertible import Invertible
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
from .common.tools.type import TypeInfo
|
|
18
|
+
from .core import InjectableFactory
|
|
19
|
+
from .core import ModeStr as InjectableModeStr
|
|
20
|
+
from .core import PriorityStr as ModulePriorityStr
|
|
21
21
|
|
|
22
22
|
default_module: Final[Module] = ...
|
|
23
23
|
|
|
@@ -41,6 +41,8 @@ class Module:
|
|
|
41
41
|
|
|
42
42
|
def __init__(self, name: str = ...): ...
|
|
43
43
|
def __contains__(self, cls: type | UnionType, /) -> bool: ...
|
|
44
|
+
@property
|
|
45
|
+
def is_locked(self) -> bool: ...
|
|
44
46
|
def inject(self, wrapped: Callable[..., Any] = ..., /):
|
|
45
47
|
"""
|
|
46
48
|
Decorator applicable to a class or function. Inject function dependencies using
|
|
@@ -48,15 +50,15 @@ class Module:
|
|
|
48
50
|
will be those of the `__init__` method.
|
|
49
51
|
"""
|
|
50
52
|
|
|
51
|
-
def injectable(
|
|
53
|
+
def injectable[T](
|
|
52
54
|
self,
|
|
53
|
-
wrapped: Callable[...,
|
|
55
|
+
wrapped: Callable[..., T] = ...,
|
|
54
56
|
/,
|
|
55
57
|
*,
|
|
56
|
-
cls:
|
|
58
|
+
cls: InjectableFactory[T] = ...,
|
|
57
59
|
inject: bool = ...,
|
|
58
|
-
on:
|
|
59
|
-
mode: InjectableMode |
|
|
60
|
+
on: TypeInfo[T] = ...,
|
|
61
|
+
mode: InjectableMode | InjectableModeStr = ...,
|
|
60
62
|
):
|
|
61
63
|
"""
|
|
62
64
|
Decorator applicable to a class or function. It is used to indicate how the
|
|
@@ -64,14 +66,14 @@ class Module:
|
|
|
64
66
|
injected each time.
|
|
65
67
|
"""
|
|
66
68
|
|
|
67
|
-
def singleton(
|
|
69
|
+
def singleton[T](
|
|
68
70
|
self,
|
|
69
|
-
wrapped: Callable[...,
|
|
71
|
+
wrapped: Callable[..., T] = ...,
|
|
70
72
|
/,
|
|
71
73
|
*,
|
|
72
74
|
inject: bool = ...,
|
|
73
|
-
on:
|
|
74
|
-
mode: InjectableMode |
|
|
75
|
+
on: TypeInfo[T] = ...,
|
|
76
|
+
mode: InjectableMode | InjectableModeStr = ...,
|
|
75
77
|
):
|
|
76
78
|
"""
|
|
77
79
|
Decorator applicable to a class or function. It is used to indicate how the
|
|
@@ -86,37 +88,37 @@ class Module:
|
|
|
86
88
|
registered.
|
|
87
89
|
"""
|
|
88
90
|
|
|
89
|
-
def set_constant(
|
|
91
|
+
def set_constant[T](
|
|
90
92
|
self,
|
|
91
|
-
instance:
|
|
92
|
-
on:
|
|
93
|
+
instance: T,
|
|
94
|
+
on: TypeInfo[T] = ...,
|
|
93
95
|
*,
|
|
94
|
-
mode: InjectableMode |
|
|
95
|
-
) ->
|
|
96
|
+
mode: InjectableMode | InjectableModeStr = ...,
|
|
97
|
+
) -> T:
|
|
96
98
|
"""
|
|
97
99
|
Function for registering a specific instance to be injected. This is useful for
|
|
98
100
|
registering global variables. The difference with the singleton decorator is
|
|
99
101
|
that no dependencies are resolved, so the module doesn't need to be locked.
|
|
100
102
|
"""
|
|
101
103
|
|
|
102
|
-
def resolve(self, cls: type[
|
|
104
|
+
def resolve[T](self, cls: type[T]) -> T:
|
|
103
105
|
"""
|
|
104
106
|
Function used to retrieve an instance associated with the type passed in
|
|
105
107
|
parameter or an exception will be raised.
|
|
106
108
|
"""
|
|
107
109
|
|
|
108
|
-
def get_instance(self, cls: type[
|
|
110
|
+
def get_instance[T](self, cls: type[T]) -> T | None:
|
|
109
111
|
"""
|
|
110
112
|
Function used to retrieve an instance associated with the type passed in
|
|
111
113
|
parameter or return `None`.
|
|
112
114
|
"""
|
|
113
115
|
|
|
114
|
-
def get_lazy_instance(
|
|
116
|
+
def get_lazy_instance[T](
|
|
115
117
|
self,
|
|
116
|
-
cls: type[
|
|
118
|
+
cls: type[T],
|
|
117
119
|
*,
|
|
118
120
|
cache: bool = ...,
|
|
119
|
-
) -> Invertible[
|
|
121
|
+
) -> Invertible[T | None]:
|
|
120
122
|
"""
|
|
121
123
|
Function used to retrieve an instance associated with the type passed in
|
|
122
124
|
parameter or `None`. Return a `Invertible` object. To access the instance
|
|
@@ -126,19 +128,24 @@ class Module:
|
|
|
126
128
|
Example: instance = ~lazy_instance
|
|
127
129
|
"""
|
|
128
130
|
|
|
131
|
+
def init_modules(self, *modules: Module) -> Self:
|
|
132
|
+
"""
|
|
133
|
+
Function to clean modules in use and to use those passed as parameters.
|
|
134
|
+
"""
|
|
135
|
+
|
|
129
136
|
def use(
|
|
130
137
|
self,
|
|
131
138
|
module: Module,
|
|
132
139
|
*,
|
|
133
|
-
priority: ModulePriority |
|
|
134
|
-
):
|
|
140
|
+
priority: ModulePriority | ModulePriorityStr = ...,
|
|
141
|
+
) -> Self:
|
|
135
142
|
"""
|
|
136
143
|
Function for using another module. Using another module replaces the module's
|
|
137
144
|
dependencies with those of the module used. If the dependency is not found, it
|
|
138
145
|
will be searched for in the module's dependency container.
|
|
139
146
|
"""
|
|
140
147
|
|
|
141
|
-
def stop_using(self, module: Module):
|
|
148
|
+
def stop_using(self, module: Module) -> Self:
|
|
142
149
|
"""
|
|
143
150
|
Function to remove a module in use.
|
|
144
151
|
"""
|
|
@@ -147,7 +154,7 @@ class Module:
|
|
|
147
154
|
self,
|
|
148
155
|
module: Module,
|
|
149
156
|
*,
|
|
150
|
-
priority: ModulePriority |
|
|
157
|
+
priority: ModulePriority | ModulePriorityStr = ...,
|
|
151
158
|
) -> ContextManager | ContextDecorator:
|
|
152
159
|
"""
|
|
153
160
|
Context manager or decorator for temporary use of a module.
|
|
@@ -156,8 +163,8 @@ class Module:
|
|
|
156
163
|
def change_priority(
|
|
157
164
|
self,
|
|
158
165
|
module: Module,
|
|
159
|
-
priority: ModulePriority |
|
|
160
|
-
):
|
|
166
|
+
priority: ModulePriority | ModulePriorityStr,
|
|
167
|
+
) -> Self:
|
|
161
168
|
"""
|
|
162
169
|
Function for changing the priority of a module in use.
|
|
163
170
|
There are two priority values:
|
|
@@ -166,27 +173,26 @@ class Module:
|
|
|
166
173
|
* **HIGH**: The module concerned becomes the most important of the modules used.
|
|
167
174
|
"""
|
|
168
175
|
|
|
169
|
-
def unlock(self):
|
|
176
|
+
def unlock(self) -> Self:
|
|
170
177
|
"""
|
|
171
178
|
Function to unlock the module by deleting cached instances of singletons.
|
|
172
179
|
"""
|
|
173
180
|
|
|
174
181
|
@final
|
|
175
|
-
class ModulePriority(
|
|
182
|
+
class ModulePriority(StrEnum):
|
|
176
183
|
LOW = ...
|
|
177
184
|
HIGH = ...
|
|
178
185
|
|
|
179
186
|
@runtime_checkable
|
|
180
|
-
class Injectable(Protocol
|
|
181
|
-
def __init__(self, factory: Callable[[], _T_co] = ..., /): ...
|
|
187
|
+
class Injectable[T](Protocol):
|
|
182
188
|
@property
|
|
183
189
|
def is_locked(self) -> bool: ...
|
|
184
190
|
def unlock(self): ...
|
|
185
191
|
@abstractmethod
|
|
186
|
-
def get_instance(self) ->
|
|
192
|
+
def get_instance(self) -> T: ...
|
|
187
193
|
|
|
188
194
|
@final
|
|
189
|
-
class InjectableMode(
|
|
195
|
+
class InjectableMode(StrEnum):
|
|
190
196
|
FALLBACK = ...
|
|
191
197
|
NORMAL = ...
|
|
192
198
|
OVERRIDE = ...
|
injection/common/event.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from contextlib import ExitStack, contextmanager, suppress
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import ContextManager
|
|
4
|
+
from typing import ContextManager, Self
|
|
5
5
|
from weakref import WeakSet
|
|
6
6
|
|
|
7
7
|
__all__ = ("Event", "EventChannel", "EventListener")
|
|
@@ -36,11 +36,11 @@ class EventChannel:
|
|
|
36
36
|
|
|
37
37
|
yield
|
|
38
38
|
|
|
39
|
-
def add_listener(self, listener: EventListener):
|
|
39
|
+
def add_listener(self, listener: EventListener) -> Self:
|
|
40
40
|
self.__listeners.add(listener)
|
|
41
41
|
return self
|
|
42
42
|
|
|
43
|
-
def remove_listener(self, listener: EventListener):
|
|
43
|
+
def remove_listener(self, listener: EventListener) -> Self:
|
|
44
44
|
with suppress(KeyError):
|
|
45
45
|
self.__listeners.remove(listener)
|
|
46
46
|
|
injection/common/invertible.py
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from collections.abc import Callable
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Protocol,
|
|
4
|
+
from typing import Protocol, runtime_checkable
|
|
5
5
|
|
|
6
6
|
__all__ = ("Invertible", "SimpleInvertible")
|
|
7
7
|
|
|
8
|
-
_T_co = TypeVar("_T_co", covariant=True)
|
|
9
|
-
|
|
10
8
|
|
|
11
9
|
@runtime_checkable
|
|
12
|
-
class Invertible(Protocol
|
|
10
|
+
class Invertible[T](Protocol):
|
|
13
11
|
@abstractmethod
|
|
14
|
-
def __invert__(self) ->
|
|
12
|
+
def __invert__(self) -> T:
|
|
15
13
|
raise NotImplementedError
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
19
|
-
class SimpleInvertible(Invertible[
|
|
20
|
-
callable: Callable[[],
|
|
17
|
+
class SimpleInvertible[T](Invertible[T]):
|
|
18
|
+
callable: Callable[[], T]
|
|
21
19
|
|
|
22
|
-
def __invert__(self) ->
|
|
20
|
+
def __invert__(self) -> T:
|
|
23
21
|
return self.callable()
|
injection/common/lazy.py
CHANGED
|
@@ -1,31 +1,26 @@
|
|
|
1
1
|
from collections.abc import Callable, Iterator, Mapping
|
|
2
2
|
from types import MappingProxyType
|
|
3
|
-
from typing import TypeVar
|
|
4
3
|
|
|
5
4
|
from injection.common.invertible import Invertible
|
|
6
5
|
|
|
7
6
|
__all__ = ("Lazy", "LazyMapping")
|
|
8
7
|
|
|
9
|
-
_T = TypeVar("_T")
|
|
10
|
-
_K = TypeVar("_K")
|
|
11
|
-
_V = TypeVar("_V")
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
class Lazy(Invertible[_T]):
|
|
9
|
+
class Lazy[T](Invertible[T]):
|
|
15
10
|
__slots__ = ("__cache", "__is_set")
|
|
16
11
|
|
|
17
|
-
def __init__(self, factory: Callable[[],
|
|
12
|
+
def __init__(self, factory: Callable[[], T]):
|
|
18
13
|
self.__setup_cache(factory)
|
|
19
14
|
|
|
20
|
-
def __invert__(self) ->
|
|
15
|
+
def __invert__(self) -> T:
|
|
21
16
|
return next(self.__cache)
|
|
22
17
|
|
|
23
18
|
@property
|
|
24
19
|
def is_set(self) -> bool:
|
|
25
20
|
return self.__is_set
|
|
26
21
|
|
|
27
|
-
def __setup_cache(self, factory: Callable[[],
|
|
28
|
-
def cache_generator() -> Iterator[
|
|
22
|
+
def __setup_cache(self, factory: Callable[[], T]):
|
|
23
|
+
def cache_generator() -> Iterator[T]:
|
|
29
24
|
nonlocal factory
|
|
30
25
|
cached = factory()
|
|
31
26
|
self.__is_set = True
|
|
@@ -38,16 +33,16 @@ class Lazy(Invertible[_T]):
|
|
|
38
33
|
self.__is_set = False
|
|
39
34
|
|
|
40
35
|
|
|
41
|
-
class LazyMapping(Mapping[
|
|
36
|
+
class LazyMapping[K, V](Mapping[K, V]):
|
|
42
37
|
__slots__ = ("__lazy",)
|
|
43
38
|
|
|
44
|
-
def __init__(self, iterator: Iterator[tuple[
|
|
39
|
+
def __init__(self, iterator: Iterator[tuple[K, V]]):
|
|
45
40
|
self.__lazy = Lazy(lambda: MappingProxyType(dict(iterator)))
|
|
46
41
|
|
|
47
|
-
def __getitem__(self, key:
|
|
42
|
+
def __getitem__(self, key: K, /) -> V:
|
|
48
43
|
return (~self.__lazy)[key]
|
|
49
44
|
|
|
50
|
-
def __iter__(self) -> Iterator[
|
|
45
|
+
def __iter__(self) -> Iterator[K]:
|
|
51
46
|
yield from ~self.__lazy
|
|
52
47
|
|
|
53
48
|
def __len__(self) -> int:
|
injection/common/tools/type.py
CHANGED
|
@@ -1,48 +1,73 @@
|
|
|
1
|
-
from collections.abc import Iterable, Iterator
|
|
1
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
2
2
|
from inspect import get_annotations, isfunction
|
|
3
|
-
from types import
|
|
4
|
-
from typing import
|
|
3
|
+
from types import UnionType
|
|
4
|
+
from typing import (
|
|
5
|
+
Annotated,
|
|
6
|
+
Any,
|
|
7
|
+
NamedTuple,
|
|
8
|
+
Self,
|
|
9
|
+
Union,
|
|
10
|
+
get_args,
|
|
11
|
+
get_origin,
|
|
12
|
+
)
|
|
5
13
|
|
|
6
|
-
__all__ = ("
|
|
14
|
+
__all__ = ("TypeInfo", "TypeReport", "analyze_types", "get_return_types")
|
|
7
15
|
|
|
16
|
+
type TypeInfo[T] = type[T] | Callable[..., T] | Iterable[TypeInfo[T]] | UnionType
|
|
8
17
|
|
|
9
|
-
def format_type(cls: type | Any) -> str:
|
|
10
|
-
try:
|
|
11
|
-
return f"{cls.__module__}.{cls.__qualname__}"
|
|
12
|
-
except AttributeError:
|
|
13
|
-
return str(cls)
|
|
14
18
|
|
|
19
|
+
class TypeReport[T](NamedTuple):
|
|
20
|
+
origin: type[T]
|
|
21
|
+
args: tuple[Any, ...]
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
@property
|
|
24
|
+
def cls(self) -> type[T]:
|
|
25
|
+
if self.args:
|
|
26
|
+
return self.origin[*self.args]
|
|
27
|
+
|
|
28
|
+
return self.origin
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def no_args(self) -> Self:
|
|
32
|
+
if self.args:
|
|
33
|
+
return type(self)(self.origin, ())
|
|
34
|
+
|
|
35
|
+
return self
|
|
19
36
|
|
|
20
|
-
|
|
37
|
+
|
|
38
|
+
def analyze_types(*types: type | Any) -> Iterator[TypeReport[Any]]:
|
|
39
|
+
for tp in types:
|
|
40
|
+
if tp is None:
|
|
21
41
|
continue
|
|
22
42
|
|
|
23
|
-
|
|
24
|
-
|
|
43
|
+
origin = get_origin(tp)
|
|
44
|
+
|
|
45
|
+
if origin is Union or isinstance(tp, UnionType):
|
|
46
|
+
inner_types = get_args(tp)
|
|
25
47
|
|
|
26
|
-
elif origin is Annotated
|
|
27
|
-
|
|
48
|
+
elif origin is Annotated:
|
|
49
|
+
inner_types = get_args(tp)[:1]
|
|
28
50
|
|
|
29
51
|
else:
|
|
30
|
-
yield origin
|
|
52
|
+
yield TypeReport(origin or tp, get_args(tp))
|
|
31
53
|
continue
|
|
32
54
|
|
|
33
|
-
yield from
|
|
55
|
+
yield from analyze_types(*inner_types)
|
|
34
56
|
|
|
35
57
|
|
|
36
|
-
def
|
|
37
|
-
for
|
|
38
|
-
if isinstance(
|
|
39
|
-
|
|
58
|
+
def get_return_types(*args: TypeInfo[Any]) -> Iterator[type | UnionType]:
|
|
59
|
+
for arg in args:
|
|
60
|
+
if isinstance(arg, Iterable) and not isinstance(
|
|
61
|
+
get_origin(arg) or arg,
|
|
62
|
+
type | str,
|
|
63
|
+
):
|
|
64
|
+
inner_args = arg
|
|
40
65
|
|
|
41
|
-
elif isfunction(
|
|
42
|
-
|
|
66
|
+
elif isfunction(arg):
|
|
67
|
+
inner_args = (get_annotations(arg, eval_str=True).get("return"),)
|
|
43
68
|
|
|
44
69
|
else:
|
|
45
|
-
yield
|
|
70
|
+
yield arg
|
|
46
71
|
continue
|
|
47
72
|
|
|
48
|
-
yield from
|
|
73
|
+
yield from get_return_types(*inner_args)
|
injection/core/module.py
CHANGED
|
@@ -14,7 +14,7 @@ from collections.abc import (
|
|
|
14
14
|
)
|
|
15
15
|
from contextlib import contextmanager, suppress
|
|
16
16
|
from dataclasses import dataclass, field
|
|
17
|
-
from enum import
|
|
17
|
+
from enum import StrEnum
|
|
18
18
|
from functools import partialmethod, singledispatchmethod, update_wrapper
|
|
19
19
|
from inspect import Signature, isclass
|
|
20
20
|
from queue import Queue
|
|
@@ -27,7 +27,7 @@ from typing import (
|
|
|
27
27
|
NamedTuple,
|
|
28
28
|
NoReturn,
|
|
29
29
|
Protocol,
|
|
30
|
-
|
|
30
|
+
Self,
|
|
31
31
|
runtime_checkable,
|
|
32
32
|
)
|
|
33
33
|
|
|
@@ -35,7 +35,12 @@ from injection.common.event import Event, EventChannel, EventListener
|
|
|
35
35
|
from injection.common.invertible import Invertible, SimpleInvertible
|
|
36
36
|
from injection.common.lazy import Lazy, LazyMapping
|
|
37
37
|
from injection.common.tools.threading import synchronized
|
|
38
|
-
from injection.common.tools.type import
|
|
38
|
+
from injection.common.tools.type import (
|
|
39
|
+
TypeInfo,
|
|
40
|
+
TypeReport,
|
|
41
|
+
analyze_types,
|
|
42
|
+
get_return_types,
|
|
43
|
+
)
|
|
39
44
|
from injection.exceptions import (
|
|
40
45
|
InjectionError,
|
|
41
46
|
ModuleError,
|
|
@@ -44,13 +49,18 @@ from injection.exceptions import (
|
|
|
44
49
|
NoInjectable,
|
|
45
50
|
)
|
|
46
51
|
|
|
47
|
-
__all__ = (
|
|
52
|
+
__all__ = (
|
|
53
|
+
"Injectable",
|
|
54
|
+
"InjectableFactory",
|
|
55
|
+
"Mode",
|
|
56
|
+
"ModeStr",
|
|
57
|
+
"Module",
|
|
58
|
+
"Priority",
|
|
59
|
+
"PriorityStr",
|
|
60
|
+
)
|
|
48
61
|
|
|
49
62
|
_logger = logging.getLogger(__name__)
|
|
50
63
|
|
|
51
|
-
_T = TypeVar("_T")
|
|
52
|
-
_T_co = TypeVar("_T_co", covariant=True)
|
|
53
|
-
|
|
54
64
|
"""
|
|
55
65
|
Events
|
|
56
66
|
"""
|
|
@@ -63,12 +73,12 @@ class ContainerEvent(Event, ABC):
|
|
|
63
73
|
|
|
64
74
|
@dataclass(frozen=True, slots=True)
|
|
65
75
|
class ContainerDependenciesUpdated(ContainerEvent):
|
|
66
|
-
|
|
76
|
+
reports: Collection[TypeReport]
|
|
67
77
|
mode: Mode
|
|
68
78
|
|
|
69
79
|
def __str__(self) -> str:
|
|
70
|
-
length = len(self.
|
|
71
|
-
formatted_classes = ", ".join(f"`{
|
|
80
|
+
length = len(self.reports)
|
|
81
|
+
formatted_classes = ", ".join(f"`{report.cls}`" for report in self.reports)
|
|
72
82
|
return (
|
|
73
83
|
f"{length} container dependenc{'ies' if length > 1 else 'y'} have been "
|
|
74
84
|
f"updated{f': {formatted_classes}' if formatted_classes else ''}."
|
|
@@ -134,12 +144,9 @@ Injectables
|
|
|
134
144
|
|
|
135
145
|
|
|
136
146
|
@runtime_checkable
|
|
137
|
-
class Injectable(Protocol
|
|
147
|
+
class Injectable[T](Protocol):
|
|
138
148
|
__slots__ = ()
|
|
139
149
|
|
|
140
|
-
def __init__(self, __factory: Callable[[], _T_co] = None, /):
|
|
141
|
-
pass
|
|
142
|
-
|
|
143
150
|
@property
|
|
144
151
|
def is_locked(self) -> bool:
|
|
145
152
|
return False
|
|
@@ -148,23 +155,23 @@ class Injectable(Protocol[_T_co]):
|
|
|
148
155
|
return
|
|
149
156
|
|
|
150
157
|
@abstractmethod
|
|
151
|
-
def get_instance(self) ->
|
|
158
|
+
def get_instance(self) -> T:
|
|
152
159
|
raise NotImplementedError
|
|
153
160
|
|
|
154
161
|
|
|
155
162
|
@dataclass(repr=False, frozen=True, slots=True)
|
|
156
|
-
class BaseInjectable(Injectable[
|
|
157
|
-
factory: Callable[[],
|
|
163
|
+
class BaseInjectable[T](Injectable[T], ABC):
|
|
164
|
+
factory: Callable[[], T]
|
|
158
165
|
|
|
159
166
|
|
|
160
|
-
class NewInjectable(BaseInjectable[
|
|
167
|
+
class NewInjectable[T](BaseInjectable[T]):
|
|
161
168
|
__slots__ = ()
|
|
162
169
|
|
|
163
|
-
def get_instance(self) ->
|
|
170
|
+
def get_instance(self) -> T:
|
|
164
171
|
return self.factory()
|
|
165
172
|
|
|
166
173
|
|
|
167
|
-
class SingletonInjectable(BaseInjectable[
|
|
174
|
+
class SingletonInjectable[T](BaseInjectable[T]):
|
|
168
175
|
__slots__ = ("__dict__",)
|
|
169
176
|
|
|
170
177
|
__INSTANCE_KEY: ClassVar[str] = "$instance"
|
|
@@ -180,7 +187,7 @@ class SingletonInjectable(BaseInjectable[_T]):
|
|
|
180
187
|
def unlock(self):
|
|
181
188
|
self.cache.clear()
|
|
182
189
|
|
|
183
|
-
def get_instance(self) ->
|
|
190
|
+
def get_instance(self) -> T:
|
|
184
191
|
with suppress(KeyError):
|
|
185
192
|
return self.cache[self.__INSTANCE_KEY]
|
|
186
193
|
|
|
@@ -192,11 +199,11 @@ class SingletonInjectable(BaseInjectable[_T]):
|
|
|
192
199
|
|
|
193
200
|
|
|
194
201
|
@dataclass(repr=False, frozen=True, slots=True)
|
|
195
|
-
class ShouldBeInjectable(Injectable[
|
|
196
|
-
cls: type[
|
|
202
|
+
class ShouldBeInjectable[T](Injectable[T]):
|
|
203
|
+
cls: type[T]
|
|
197
204
|
|
|
198
205
|
def get_instance(self) -> NoReturn:
|
|
199
|
-
raise InjectionError(f"`{
|
|
206
|
+
raise InjectionError(f"`{self.cls}` should be an injectable.")
|
|
200
207
|
|
|
201
208
|
|
|
202
209
|
"""
|
|
@@ -209,7 +216,7 @@ class Broker(Protocol):
|
|
|
209
216
|
__slots__ = ()
|
|
210
217
|
|
|
211
218
|
@abstractmethod
|
|
212
|
-
def __getitem__(self, cls: type[
|
|
219
|
+
def __getitem__[T](self, cls: type[T] | UnionType, /) -> Injectable[T]:
|
|
213
220
|
raise NotImplementedError
|
|
214
221
|
|
|
215
222
|
@abstractmethod
|
|
@@ -222,7 +229,7 @@ class Broker(Protocol):
|
|
|
222
229
|
raise NotImplementedError
|
|
223
230
|
|
|
224
231
|
@abstractmethod
|
|
225
|
-
def unlock(self):
|
|
232
|
+
def unlock(self) -> Self:
|
|
226
233
|
raise NotImplementedError
|
|
227
234
|
|
|
228
235
|
|
|
@@ -231,7 +238,7 @@ Container
|
|
|
231
238
|
"""
|
|
232
239
|
|
|
233
240
|
|
|
234
|
-
class Mode(
|
|
241
|
+
class Mode(StrEnum):
|
|
235
242
|
FALLBACK = "fallback"
|
|
236
243
|
NORMAL = "normal"
|
|
237
244
|
OVERRIDE = "override"
|
|
@@ -241,36 +248,37 @@ class Mode(str, Enum):
|
|
|
241
248
|
return tuple(type(self)).index(self)
|
|
242
249
|
|
|
243
250
|
@classmethod
|
|
244
|
-
def get_default(cls):
|
|
251
|
+
def get_default(cls) -> Mode:
|
|
245
252
|
return cls.NORMAL
|
|
246
253
|
|
|
247
254
|
|
|
248
|
-
ModeStr = Literal["fallback", "normal", "override"]
|
|
255
|
+
type ModeStr = Literal["fallback", "normal", "override"]
|
|
249
256
|
|
|
250
257
|
|
|
251
|
-
class Record(NamedTuple):
|
|
252
|
-
injectable: Injectable
|
|
258
|
+
class Record[T](NamedTuple):
|
|
259
|
+
injectable: Injectable[T]
|
|
253
260
|
mode: Mode
|
|
254
261
|
|
|
255
262
|
|
|
256
263
|
@dataclass(repr=False, frozen=True, slots=True)
|
|
257
264
|
class Container(Broker):
|
|
258
|
-
__records: dict[
|
|
265
|
+
__records: dict[TypeReport, Record] = field(default_factory=dict, init=False)
|
|
259
266
|
__channel: EventChannel = field(default_factory=EventChannel, init=False)
|
|
260
267
|
|
|
261
|
-
def __getitem__(self, cls: type[
|
|
262
|
-
for
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
268
|
+
def __getitem__[T](self, cls: type[T] | UnionType, /) -> Injectable[T]:
|
|
269
|
+
for report in analyze_types(cls):
|
|
270
|
+
for scoped_report in dict.fromkeys((report, report.no_args)):
|
|
271
|
+
try:
|
|
272
|
+
injectable, _ = self.__records[scoped_report]
|
|
273
|
+
except KeyError:
|
|
274
|
+
continue
|
|
267
275
|
|
|
268
|
-
|
|
276
|
+
return injectable
|
|
269
277
|
|
|
270
278
|
raise NoInjectable(cls)
|
|
271
279
|
|
|
272
280
|
def __contains__(self, cls: type | UnionType, /) -> bool:
|
|
273
|
-
return any(
|
|
281
|
+
return any(report in self.__records for report in analyze_types(cls))
|
|
274
282
|
|
|
275
283
|
@property
|
|
276
284
|
def is_locked(self) -> bool:
|
|
@@ -281,16 +289,16 @@ class Container(Broker):
|
|
|
281
289
|
return frozenset(injectable for injectable, _ in self.__records.values())
|
|
282
290
|
|
|
283
291
|
@synchronized()
|
|
284
|
-
def update(
|
|
292
|
+
def update[T](
|
|
285
293
|
self,
|
|
286
|
-
classes: Iterable[type | UnionType],
|
|
287
|
-
injectable: Injectable,
|
|
294
|
+
classes: Iterable[type[T] | UnionType],
|
|
295
|
+
injectable: Injectable[T],
|
|
288
296
|
mode: Mode | ModeStr,
|
|
289
|
-
):
|
|
297
|
+
) -> Self:
|
|
290
298
|
mode = Mode(mode)
|
|
291
299
|
records = {
|
|
292
|
-
|
|
293
|
-
for
|
|
300
|
+
report: Record(injectable, mode)
|
|
301
|
+
for report in self.__prepare_reports_for_updating(classes, mode)
|
|
294
302
|
}
|
|
295
303
|
|
|
296
304
|
if records:
|
|
@@ -302,43 +310,43 @@ class Container(Broker):
|
|
|
302
310
|
return self
|
|
303
311
|
|
|
304
312
|
@synchronized()
|
|
305
|
-
def unlock(self):
|
|
313
|
+
def unlock(self) -> Self:
|
|
306
314
|
for injectable in self.__injectables:
|
|
307
315
|
injectable.unlock()
|
|
308
316
|
|
|
309
317
|
return self
|
|
310
318
|
|
|
311
|
-
def add_listener(self, listener: EventListener):
|
|
319
|
+
def add_listener(self, listener: EventListener) -> Self:
|
|
312
320
|
self.__channel.add_listener(listener)
|
|
313
321
|
return self
|
|
314
322
|
|
|
315
|
-
def notify(self, event: Event):
|
|
323
|
+
def notify(self, event: Event) -> ContextManager:
|
|
316
324
|
return self.__channel.dispatch(event)
|
|
317
325
|
|
|
318
|
-
def
|
|
326
|
+
def __prepare_reports_for_updating(
|
|
319
327
|
self,
|
|
320
328
|
classes: Iterable[type | UnionType],
|
|
321
329
|
mode: Mode,
|
|
322
|
-
) -> Iterator[
|
|
330
|
+
) -> Iterator[TypeReport]:
|
|
323
331
|
rank = mode.rank
|
|
324
332
|
|
|
325
|
-
for
|
|
333
|
+
for report in frozenset(analyze_types(*classes)):
|
|
326
334
|
try:
|
|
327
|
-
_, current_mode = self.__records[
|
|
335
|
+
_, current_mode = self.__records[report]
|
|
328
336
|
|
|
329
337
|
except KeyError:
|
|
330
338
|
pass
|
|
331
339
|
|
|
332
340
|
else:
|
|
333
|
-
if mode == current_mode:
|
|
341
|
+
if mode == current_mode and mode != Mode.OVERRIDE:
|
|
334
342
|
raise RuntimeError(
|
|
335
|
-
f"An injectable already exists for the class `{
|
|
343
|
+
f"An injectable already exists for the class `{report.cls}`."
|
|
336
344
|
)
|
|
337
345
|
|
|
338
346
|
elif rank < current_mode.rank:
|
|
339
347
|
continue
|
|
340
348
|
|
|
341
|
-
yield
|
|
349
|
+
yield report
|
|
342
350
|
|
|
343
351
|
|
|
344
352
|
"""
|
|
@@ -346,16 +354,18 @@ Module
|
|
|
346
354
|
"""
|
|
347
355
|
|
|
348
356
|
|
|
349
|
-
class Priority(
|
|
357
|
+
class Priority(StrEnum):
|
|
350
358
|
LOW = "low"
|
|
351
359
|
HIGH = "high"
|
|
352
360
|
|
|
353
361
|
@classmethod
|
|
354
|
-
def get_default(cls):
|
|
362
|
+
def get_default(cls) -> Priority:
|
|
355
363
|
return cls.LOW
|
|
356
364
|
|
|
357
365
|
|
|
358
|
-
PriorityStr = Literal["low", "high"]
|
|
366
|
+
type PriorityStr = Literal["low", "high"]
|
|
367
|
+
|
|
368
|
+
type InjectableFactory[T] = Callable[[Callable[..., T]], Injectable[T]]
|
|
359
369
|
|
|
360
370
|
|
|
361
371
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
@@ -371,14 +381,14 @@ class Module(EventListener, Broker):
|
|
|
371
381
|
def __post_init__(self):
|
|
372
382
|
self.__container.add_listener(self)
|
|
373
383
|
|
|
374
|
-
def __getitem__(self, cls: type[
|
|
384
|
+
def __getitem__[T](self, cls: type[T] | UnionType, /) -> Injectable[T]:
|
|
375
385
|
for broker in self.__brokers:
|
|
376
386
|
with suppress(KeyError):
|
|
377
387
|
return broker[cls]
|
|
378
388
|
|
|
379
389
|
raise NoInjectable(cls)
|
|
380
390
|
|
|
381
|
-
def __setitem__(self, cls: type | UnionType, injectable: Injectable, /):
|
|
391
|
+
def __setitem__[T](self, cls: type[T] | UnionType, injectable: Injectable[T], /):
|
|
382
392
|
self.update((cls,), injectable)
|
|
383
393
|
|
|
384
394
|
def __contains__(self, cls: type | UnionType, /) -> bool:
|
|
@@ -396,20 +406,20 @@ class Module(EventListener, Broker):
|
|
|
396
406
|
yield from tuple(self.__modules)
|
|
397
407
|
yield self.__container
|
|
398
408
|
|
|
399
|
-
def injectable(
|
|
409
|
+
def injectable[T](
|
|
400
410
|
self,
|
|
401
|
-
wrapped: Callable[...,
|
|
411
|
+
wrapped: Callable[..., T] = None,
|
|
402
412
|
/,
|
|
403
413
|
*,
|
|
404
|
-
cls:
|
|
414
|
+
cls: InjectableFactory[T] = NewInjectable,
|
|
405
415
|
inject: bool = True,
|
|
406
|
-
on:
|
|
416
|
+
on: TypeInfo[T] = (),
|
|
407
417
|
mode: Mode | ModeStr = Mode.get_default(),
|
|
408
418
|
):
|
|
409
419
|
def decorator(wp):
|
|
410
420
|
factory = self.inject(wp, return_factory=True) if inject else wp
|
|
411
421
|
injectable = cls(factory)
|
|
412
|
-
classes =
|
|
422
|
+
classes = get_return_types(wp, on)
|
|
413
423
|
self.update(classes, injectable, mode)
|
|
414
424
|
return wp
|
|
415
425
|
|
|
@@ -428,18 +438,18 @@ class Module(EventListener, Broker):
|
|
|
428
438
|
|
|
429
439
|
return decorator(wrapped) if wrapped else decorator
|
|
430
440
|
|
|
431
|
-
def set_constant(
|
|
441
|
+
def set_constant[T](
|
|
432
442
|
self,
|
|
433
|
-
instance:
|
|
434
|
-
on:
|
|
443
|
+
instance: T,
|
|
444
|
+
on: TypeInfo[T] = (),
|
|
435
445
|
*,
|
|
436
446
|
mode: Mode | ModeStr = Mode.get_default(),
|
|
437
|
-
) ->
|
|
447
|
+
) -> T:
|
|
438
448
|
cls = type(instance)
|
|
439
449
|
self.injectable(
|
|
440
450
|
lambda: instance,
|
|
441
451
|
inject=False,
|
|
442
|
-
on=(cls, on),
|
|
452
|
+
on=(cls, on),
|
|
443
453
|
mode=mode,
|
|
444
454
|
)
|
|
445
455
|
return instance
|
|
@@ -467,22 +477,22 @@ class Module(EventListener, Broker):
|
|
|
467
477
|
|
|
468
478
|
return decorator(wrapped) if wrapped else decorator
|
|
469
479
|
|
|
470
|
-
def resolve(self, cls: type[
|
|
480
|
+
def resolve[T](self, cls: type[T]) -> T:
|
|
471
481
|
injectable = self[cls]
|
|
472
482
|
return injectable.get_instance()
|
|
473
483
|
|
|
474
|
-
def get_instance(self, cls: type[
|
|
484
|
+
def get_instance[T](self, cls: type[T]) -> T | None:
|
|
475
485
|
try:
|
|
476
486
|
return self.resolve(cls)
|
|
477
487
|
except KeyError:
|
|
478
488
|
return None
|
|
479
489
|
|
|
480
|
-
def get_lazy_instance(
|
|
490
|
+
def get_lazy_instance[T](
|
|
481
491
|
self,
|
|
482
|
-
cls: type[
|
|
492
|
+
cls: type[T],
|
|
483
493
|
*,
|
|
484
494
|
cache: bool = False,
|
|
485
|
-
) -> Invertible[
|
|
495
|
+
) -> Invertible[T | None]:
|
|
486
496
|
if cache:
|
|
487
497
|
return Lazy(lambda: self.get_instance(cls))
|
|
488
498
|
|
|
@@ -490,21 +500,30 @@ class Module(EventListener, Broker):
|
|
|
490
500
|
function.set_owner(cls)
|
|
491
501
|
return SimpleInvertible(function)
|
|
492
502
|
|
|
493
|
-
def update(
|
|
503
|
+
def update[T](
|
|
494
504
|
self,
|
|
495
|
-
classes: Iterable[type | UnionType],
|
|
496
|
-
injectable: Injectable,
|
|
505
|
+
classes: Iterable[type[T] | UnionType],
|
|
506
|
+
injectable: Injectable[T],
|
|
497
507
|
mode: Mode | ModeStr = Mode.get_default(),
|
|
498
|
-
):
|
|
508
|
+
) -> Self:
|
|
499
509
|
self.__container.update(classes, injectable, mode)
|
|
500
510
|
return self
|
|
501
511
|
|
|
512
|
+
def init_modules(self, *modules: Module) -> Self:
|
|
513
|
+
for module in tuple(self.__modules):
|
|
514
|
+
self.stop_using(module)
|
|
515
|
+
|
|
516
|
+
for module in modules:
|
|
517
|
+
self.use(module)
|
|
518
|
+
|
|
519
|
+
return self
|
|
520
|
+
|
|
502
521
|
def use(
|
|
503
522
|
self,
|
|
504
523
|
module: Module,
|
|
505
524
|
*,
|
|
506
525
|
priority: Priority | PriorityStr = Priority.get_default(),
|
|
507
|
-
):
|
|
526
|
+
) -> Self:
|
|
508
527
|
if module is self:
|
|
509
528
|
raise ModuleError("Module can't be used by itself.")
|
|
510
529
|
|
|
@@ -521,7 +540,7 @@ class Module(EventListener, Broker):
|
|
|
521
540
|
|
|
522
541
|
return self
|
|
523
542
|
|
|
524
|
-
def stop_using(self, module: Module):
|
|
543
|
+
def stop_using(self, module: Module) -> Self:
|
|
525
544
|
event = ModuleRemoved(self, module)
|
|
526
545
|
|
|
527
546
|
with suppress(KeyError):
|
|
@@ -542,7 +561,7 @@ class Module(EventListener, Broker):
|
|
|
542
561
|
yield
|
|
543
562
|
self.stop_using(module)
|
|
544
563
|
|
|
545
|
-
def change_priority(self, module: Module, priority: Priority | PriorityStr):
|
|
564
|
+
def change_priority(self, module: Module, priority: Priority | PriorityStr) -> Self:
|
|
546
565
|
priority = Priority(priority)
|
|
547
566
|
event = ModulePriorityUpdated(self, module, priority)
|
|
548
567
|
|
|
@@ -552,17 +571,17 @@ class Module(EventListener, Broker):
|
|
|
552
571
|
return self
|
|
553
572
|
|
|
554
573
|
@synchronized()
|
|
555
|
-
def unlock(self):
|
|
574
|
+
def unlock(self) -> Self:
|
|
556
575
|
for broker in self.__brokers:
|
|
557
576
|
broker.unlock()
|
|
558
577
|
|
|
559
578
|
return self
|
|
560
579
|
|
|
561
|
-
def add_listener(self, listener: EventListener):
|
|
580
|
+
def add_listener(self, listener: EventListener) -> Self:
|
|
562
581
|
self.__channel.add_listener(listener)
|
|
563
582
|
return self
|
|
564
583
|
|
|
565
|
-
def remove_listener(self, listener: EventListener):
|
|
584
|
+
def remove_listener(self, listener: EventListener) -> Self:
|
|
566
585
|
self.__channel.remove_listener(listener)
|
|
567
586
|
return self
|
|
568
587
|
|
|
@@ -621,15 +640,15 @@ class Dependencies:
|
|
|
621
640
|
return OrderedDict(self)
|
|
622
641
|
|
|
623
642
|
@classmethod
|
|
624
|
-
def from_mapping(cls, mapping: Mapping[str, Injectable]):
|
|
643
|
+
def from_mapping(cls, mapping: Mapping[str, Injectable]) -> Self:
|
|
625
644
|
return cls(mapping=mapping)
|
|
626
645
|
|
|
627
646
|
@classmethod
|
|
628
|
-
def empty(cls):
|
|
647
|
+
def empty(cls) -> Self:
|
|
629
648
|
return cls.from_mapping({})
|
|
630
649
|
|
|
631
650
|
@classmethod
|
|
632
|
-
def resolve(cls, signature: Signature, module: Module, owner: type = None):
|
|
651
|
+
def resolve(cls, signature: Signature, module: Module, owner: type = None) -> Self:
|
|
633
652
|
dependencies = LazyMapping(cls.__resolver(signature, module, owner))
|
|
634
653
|
return cls.from_mapping(dependencies)
|
|
635
654
|
|
|
@@ -705,7 +724,7 @@ class InjectedFunction(EventListener):
|
|
|
705
724
|
arguments = self.bind(args, kwargs)
|
|
706
725
|
return self.wrapped(*arguments.args, **arguments.kwargs)
|
|
707
726
|
|
|
708
|
-
def __get__(self, instance: object = None, owner: type = None):
|
|
727
|
+
def __get__(self, instance: object = None, owner: type = None) -> Self | MethodType:
|
|
709
728
|
if instance is None:
|
|
710
729
|
return self
|
|
711
730
|
|
|
@@ -739,7 +758,7 @@ class InjectedFunction(EventListener):
|
|
|
739
758
|
)
|
|
740
759
|
return Arguments(bound.args, bound.kwargs)
|
|
741
760
|
|
|
742
|
-
def set_owner(self, owner: type):
|
|
761
|
+
def set_owner(self, owner: type) -> Self:
|
|
743
762
|
if self.__dependencies.are_resolved:
|
|
744
763
|
raise TypeError(
|
|
745
764
|
"Function owner must be assigned before dependencies are resolved."
|
|
@@ -752,7 +771,7 @@ class InjectedFunction(EventListener):
|
|
|
752
771
|
return self
|
|
753
772
|
|
|
754
773
|
@synchronized()
|
|
755
|
-
def update(self, module: Module):
|
|
774
|
+
def update(self, module: Module) -> Self:
|
|
756
775
|
self.__dependencies = Dependencies.resolve(self.signature, module, self.__owner)
|
|
757
776
|
return self
|
|
758
777
|
|
|
@@ -764,7 +783,7 @@ class InjectedFunction(EventListener):
|
|
|
764
783
|
return decorator(wrapped) if wrapped else decorator
|
|
765
784
|
|
|
766
785
|
@singledispatchmethod
|
|
767
|
-
def on_event(self, event: Event, /) ->
|
|
786
|
+
def on_event(self, event: Event, /) -> None: # type: ignore
|
|
768
787
|
return None
|
|
769
788
|
|
|
770
789
|
@on_event.register
|
|
@@ -773,7 +792,7 @@ class InjectedFunction(EventListener):
|
|
|
773
792
|
yield
|
|
774
793
|
self.update(event.on_module)
|
|
775
794
|
|
|
776
|
-
def __set_signature(self):
|
|
795
|
+
def __set_signature(self) -> Self:
|
|
777
796
|
self.__signature__ = inspect.signature(self.wrapped, eval_str=True)
|
|
778
797
|
return self
|
|
779
798
|
|
injection/exceptions.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from injection.common.tools.type import format_type
|
|
4
|
-
|
|
5
3
|
__all__ = (
|
|
6
4
|
"InjectionError",
|
|
7
5
|
"NoInjectable",
|
|
@@ -15,15 +13,15 @@ class InjectionError(Exception):
|
|
|
15
13
|
pass
|
|
16
14
|
|
|
17
15
|
|
|
18
|
-
class NoInjectable(KeyError, InjectionError):
|
|
16
|
+
class NoInjectable[T](KeyError, InjectionError):
|
|
19
17
|
__slots__ = ("__class",)
|
|
20
18
|
|
|
21
|
-
def __init__(self, cls: type | Any):
|
|
22
|
-
super().__init__(f"No injectable for `{
|
|
19
|
+
def __init__(self, cls: type[T] | Any):
|
|
20
|
+
super().__init__(f"No injectable for `{cls}`.")
|
|
23
21
|
self.__class = cls
|
|
24
22
|
|
|
25
23
|
@property
|
|
26
|
-
def cls(self) -> type:
|
|
24
|
+
def cls(self) -> type[T]:
|
|
27
25
|
return self.__class
|
|
28
26
|
|
|
29
27
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
|
|
3
3
|
from rodi import ContainerProtocol
|
|
4
4
|
|
|
@@ -6,8 +6,6 @@ from injection import Module, default_module
|
|
|
6
6
|
|
|
7
7
|
__all__ = ("InjectionServices",)
|
|
8
8
|
|
|
9
|
-
_T = TypeVar("_T")
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
class InjectionServices(ContainerProtocol):
|
|
13
11
|
"""
|
|
@@ -26,5 +24,5 @@ class InjectionServices(ContainerProtocol):
|
|
|
26
24
|
self.__module.injectable(obj_type)
|
|
27
25
|
return self
|
|
28
26
|
|
|
29
|
-
def resolve(self, obj_type: type[
|
|
27
|
+
def resolve[T](self, obj_type: type[T] | Any, *args, **kwargs) -> T:
|
|
30
28
|
return self.__module.resolve(obj_type)
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-injection
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Fast and easy dependency injection framework.
|
|
5
5
|
Home-page: https://github.com/100nm/python-injection
|
|
6
6
|
License: MIT
|
|
7
7
|
Keywords: dependencies,inject,injection
|
|
8
8
|
Author: remimd
|
|
9
|
-
Requires-Python: >=3.
|
|
9
|
+
Requires-Python: >=3.12,<4
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
13
|
Project-URL: Repository, https://github.com/100nm/python-injection
|
|
16
14
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
injection/__init__.py,sha256=Bf6S99E2srD3752xlJf3uAdiGIzY2YHOZafcwEiwY70,739
|
|
2
|
+
injection/__init__.pyi,sha256=HEk1HXAmwtq2ZEFLf5A7VWhdpPVWVQpjsLip9JzepEY,6023
|
|
3
|
+
injection/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
injection/common/event.py,sha256=5Rdb2m3vAMCic8cQAVkStJDbrDrW_lk6kav8wYwmexM,1283
|
|
5
|
+
injection/common/invertible.py,sha256=noNcmJ96IQi0XJms0dyfrx_AvKZnQM0sZyxhc2l6qo0,527
|
|
6
|
+
injection/common/lazy.py,sha256=FEas6ewwOGWvRR8cflmyVvSLZd_-Fxd0QeIdvAM5I9c,1313
|
|
7
|
+
injection/common/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
injection/common/tools/threading.py,sha256=Urcy59Rp34psRWmzzQyNDu4Zm-DuCkPsp4qO1x_W4qQ,165
|
|
9
|
+
injection/common/tools/type.py,sha256=5Ixswd9-sSqJdmh9lTd3jADFHWgD0wZSwecVi1opeO0,1715
|
|
10
|
+
injection/core/__init__.py,sha256=zuf0ubI2dHnbjn1059eduhS-ACIkkROa6-dhp10krh0,22
|
|
11
|
+
injection/core/module.py,sha256=nCa10YQu-o-W0jMt-EnjCuXc1VioqN5CZXK2EoS4zgo,21241
|
|
12
|
+
injection/exceptions.py,sha256=RsWWiWwKSMU0vxXQqQSn6CKHLMrGu4SSzYUAy9OJRXk,626
|
|
13
|
+
injection/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
injection/integrations/blacksheep.py,sha256=GQBZCyl_DNDuCJdV56EYaiYCXGDMmP66cEahRzUZpmc,737
|
|
15
|
+
injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
injection/utils.py,sha256=_79aiciimZpuoUTz5lojKySUMMzpkU-e7SotiHIFTI8,676
|
|
17
|
+
python_injection-0.9.0.dist-info/METADATA,sha256=j_ikavu9sPJ2xkKcX6Vr8MmhoNayLEiVNLPQ99TzWNY,3570
|
|
18
|
+
python_injection-0.9.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
19
|
+
python_injection-0.9.0.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
injection/__init__.py,sha256=Bf6S99E2srD3752xlJf3uAdiGIzY2YHOZafcwEiwY70,739
|
|
2
|
-
injection/__init__.pyi,sha256=fNTW5TUZQmaxPooaa_vJ_nyR_-DqZ13hSWHh_TsdeOo,5913
|
|
3
|
-
injection/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
injection/common/event.py,sha256=TvkFv-5zF_oUTPhh5U0BKD5HanvCJKHA0H7yceMRy5c,1261
|
|
5
|
-
injection/common/invertible.py,sha256=BZnkDg_NZDsTXGca5w5Wg_nYE3oRO_Wlodi2XtE55ck,595
|
|
6
|
-
injection/common/lazy.py,sha256=1C34uoG229Gl0DEUcD9-eQrL4K_oIofOLzdQ1SiY6rw,1401
|
|
7
|
-
injection/common/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
injection/common/tools/threading.py,sha256=RAtzBFLVNJMflWIHxrP83fjafnFq8_JLgFoYQg8nVyE,182
|
|
9
|
-
injection/common/tools/type.py,sha256=05fD5UkUI1kPoFWEjQz4j266SYfJQMK-Ti88JXNxb_M,1276
|
|
10
|
-
injection/core/__init__.py,sha256=zuf0ubI2dHnbjn1059eduhS-ACIkkROa6-dhp10krh0,22
|
|
11
|
-
injection/core/module.py,sha256=9QAYw5u8ULev3UWZCJ3R2dH9-xCqjc5e_9_19hrVWWw,20626
|
|
12
|
-
injection/exceptions.py,sha256=f2lVSTAx-Nv89s0skn15y-sCkr656ROuWYs-XlrcEn8,683
|
|
13
|
-
injection/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
injection/integrations/blacksheep.py,sha256=dFXzrxkJRy9z44CcwG0ROYshT3zUZTVyuQkRy390RvU,765
|
|
15
|
-
injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
injection/utils.py,sha256=_79aiciimZpuoUTz5lojKySUMMzpkU-e7SotiHIFTI8,676
|
|
17
|
-
python_injection-0.8.5.dist-info/METADATA,sha256=ZUrcGLYxHJC3IIwnBDJgsA3wlZ25zTNHeopIVWi4EHM,3672
|
|
18
|
-
python_injection-0.8.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
19
|
-
python_injection-0.8.5.dist-info/RECORD,,
|
|
File without changes
|