python-injection 0.10.12.post0__py3-none-any.whl → 0.12.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.
- injection/__init__.py +10 -9
- injection/__init__.pyi +74 -15
- injection/_core/__init__.py +1 -1
- injection/_core/common/asynchronous.py +54 -0
- injection/_core/common/invertible.py +2 -2
- injection/_core/common/type.py +2 -5
- injection/_core/descriptors.py +25 -0
- injection/_core/hook.py +13 -10
- injection/_core/injectables.py +106 -0
- injection/_core/module.py +260 -145
- injection/integrations/fastapi.py +18 -15
- injection/testing/__init__.py +2 -2
- injection/testing/__init__.pyi +1 -1
- injection/utils.py +2 -2
- {python_injection-0.10.12.post0.dist-info → python_injection-0.12.0.dist-info}/METADATA +9 -12
- python_injection-0.12.0.dist-info/RECORD +24 -0
- {python_injection-0.10.12.post0.dist-info → python_injection-0.12.0.dist-info}/WHEEL +1 -1
- injection/integrations/blacksheep.py +0 -34
- python_injection-0.10.12.post0.dist-info/RECORD +0 -22
injection/__init__.py
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
from ._core.
|
1
|
+
from ._core.descriptors import LazyInstance
|
2
|
+
from ._core.injectables import Injectable
|
3
|
+
from ._core.module import Mode, Module, Priority, mod
|
2
4
|
|
3
5
|
__all__ = (
|
4
6
|
"Injectable",
|
7
|
+
"LazyInstance",
|
5
8
|
"Mode",
|
6
9
|
"Module",
|
7
10
|
"Priority",
|
11
|
+
"afind_instance",
|
12
|
+
"aget_instance",
|
13
|
+
"aget_lazy_instance",
|
8
14
|
"constant",
|
9
15
|
"find_instance",
|
10
16
|
"get_instance",
|
@@ -17,14 +23,9 @@ __all__ = (
|
|
17
23
|
"singleton",
|
18
24
|
)
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
return Module.default()
|
24
|
-
|
25
|
-
return Module.from_name(name)
|
26
|
-
|
27
|
-
|
26
|
+
afind_instance = mod().afind_instance
|
27
|
+
aget_instance = mod().aget_instance
|
28
|
+
aget_lazy_instance = mod().aget_lazy_instance
|
28
29
|
constant = mod().constant
|
29
30
|
find_instance = mod().find_instance
|
30
31
|
get_instance = mod().get_instance
|
injection/__init__.pyi
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from abc import abstractmethod
|
2
|
-
from collections.abc import Callable
|
2
|
+
from collections.abc import Awaitable, Callable
|
3
3
|
from contextlib import ContextDecorator
|
4
4
|
from enum import Enum
|
5
5
|
from logging import Logger
|
@@ -9,6 +9,7 @@ from typing import (
|
|
9
9
|
Protocol,
|
10
10
|
Self,
|
11
11
|
final,
|
12
|
+
overload,
|
12
13
|
runtime_checkable,
|
13
14
|
)
|
14
15
|
|
@@ -20,6 +21,9 @@ from ._core.module import ModeStr, PriorityStr
|
|
20
21
|
|
21
22
|
_: Module = ...
|
22
23
|
|
24
|
+
afind_instance = _.afind_instance
|
25
|
+
aget_instance = _.aget_instance
|
26
|
+
aget_lazy_instance = _.aget_lazy_instance
|
23
27
|
constant = _.constant
|
24
28
|
find_instance = _.find_instance
|
25
29
|
get_instance = _.get_instance
|
@@ -52,59 +56,59 @@ class Module:
|
|
52
56
|
def __contains__(self, cls: _InputType[Any], /) -> bool: ...
|
53
57
|
@property
|
54
58
|
def is_locked(self) -> bool: ...
|
55
|
-
def inject[**P, T](self, wrapped: Callable[P, T] = ..., /)
|
59
|
+
def inject[**P, T](self, wrapped: Callable[P, T] = ..., /) -> Any:
|
56
60
|
"""
|
57
61
|
Decorator applicable to a class or function. Inject function dependencies using
|
58
62
|
parameter type annotations. If applied to a class, the dependencies resolved
|
59
63
|
will be those of the `__init__` method.
|
60
64
|
"""
|
61
65
|
|
62
|
-
def injectable[**P, T](
|
66
|
+
def injectable[**P, T](
|
63
67
|
self,
|
64
|
-
wrapped: Callable[P, T] = ...,
|
68
|
+
wrapped: Callable[P, T] | Callable[P, Awaitable[T]] = ...,
|
65
69
|
/,
|
66
70
|
*,
|
67
71
|
cls: _InjectableFactory[T] = ...,
|
68
72
|
inject: bool = ...,
|
69
73
|
on: _TypeInfo[T] = ...,
|
70
74
|
mode: Mode | ModeStr = ...,
|
71
|
-
):
|
75
|
+
) -> Any:
|
72
76
|
"""
|
73
77
|
Decorator applicable to a class or function. It is used to indicate how the
|
74
78
|
injectable will be constructed. At injection time, a new instance will be
|
75
79
|
injected each time.
|
76
80
|
"""
|
77
81
|
|
78
|
-
def singleton[**P, T](
|
82
|
+
def singleton[**P, T](
|
79
83
|
self,
|
80
|
-
wrapped: Callable[P, T] = ...,
|
84
|
+
wrapped: Callable[P, T] | Callable[P, Awaitable[T]] = ...,
|
81
85
|
/,
|
82
86
|
*,
|
83
87
|
inject: bool = ...,
|
84
88
|
on: _TypeInfo[T] = ...,
|
85
89
|
mode: Mode | ModeStr = ...,
|
86
|
-
):
|
90
|
+
) -> Any:
|
87
91
|
"""
|
88
92
|
Decorator applicable to a class or function. It is used to indicate how the
|
89
93
|
singleton will be constructed. At injection time, the injected instance will
|
90
94
|
always be the same.
|
91
95
|
"""
|
92
96
|
|
93
|
-
def should_be_injectable[T](self, wrapped: type[T] = ..., /)
|
97
|
+
def should_be_injectable[T](self, wrapped: type[T] = ..., /) -> Any:
|
94
98
|
"""
|
95
99
|
Decorator applicable to a class. It is used to specify whether an injectable
|
96
100
|
should be registered. Raise an exception at injection time if the class isn't
|
97
101
|
registered.
|
98
102
|
"""
|
99
103
|
|
100
|
-
def constant[T](
|
104
|
+
def constant[T](
|
101
105
|
self,
|
102
106
|
wrapped: type[T] = ...,
|
103
107
|
/,
|
104
108
|
*,
|
105
109
|
on: _TypeInfo[T] = ...,
|
106
110
|
mode: Mode | ModeStr = ...,
|
107
|
-
):
|
111
|
+
) -> Any:
|
108
112
|
"""
|
109
113
|
Decorator applicable to a class or function. It is used to indicate how the
|
110
114
|
constant is constructed. At injection time, the injected instance will always
|
@@ -130,29 +134,66 @@ class Module:
|
|
130
134
|
wrapped: Callable[P, T],
|
131
135
|
/,
|
132
136
|
) -> Callable[P, T]: ...
|
137
|
+
async def afind_instance[T](self, cls: _InputType[T]) -> T: ...
|
133
138
|
def find_instance[T](self, cls: _InputType[T]) -> T:
|
134
139
|
"""
|
135
140
|
Function used to retrieve an instance associated with the type passed in
|
136
141
|
parameter or an exception will be raised.
|
137
142
|
"""
|
138
143
|
|
144
|
+
@overload
|
145
|
+
async def aget_instance[T, Default](
|
146
|
+
self,
|
147
|
+
cls: _InputType[T],
|
148
|
+
default: Default,
|
149
|
+
) -> T | Default: ...
|
150
|
+
@overload
|
151
|
+
async def aget_instance[T](
|
152
|
+
self,
|
153
|
+
cls: _InputType[T],
|
154
|
+
default: None = ...,
|
155
|
+
) -> T | None: ...
|
156
|
+
@overload
|
139
157
|
def get_instance[T, Default](
|
140
158
|
self,
|
141
159
|
cls: _InputType[T],
|
142
|
-
default: Default
|
143
|
-
) -> T | Default
|
160
|
+
default: Default,
|
161
|
+
) -> T | Default:
|
144
162
|
"""
|
145
163
|
Function used to retrieve an instance associated with the type passed in
|
146
164
|
parameter or return `None`.
|
147
165
|
"""
|
148
166
|
|
167
|
+
@overload
|
168
|
+
def get_instance[T](
|
169
|
+
self,
|
170
|
+
cls: _InputType[T],
|
171
|
+
default: None = ...,
|
172
|
+
) -> T | None: ...
|
173
|
+
@overload
|
174
|
+
def aget_lazy_instance[T, Default](
|
175
|
+
self,
|
176
|
+
cls: _InputType[T],
|
177
|
+
default: Default,
|
178
|
+
*,
|
179
|
+
cache: bool = ...,
|
180
|
+
) -> Awaitable[T | Default]: ...
|
181
|
+
@overload
|
182
|
+
def aget_lazy_instance[T](
|
183
|
+
self,
|
184
|
+
cls: _InputType[T],
|
185
|
+
default: None = ...,
|
186
|
+
*,
|
187
|
+
cache: bool = ...,
|
188
|
+
) -> Awaitable[T | None]: ...
|
189
|
+
@overload
|
149
190
|
def get_lazy_instance[T, Default](
|
150
191
|
self,
|
151
192
|
cls: _InputType[T],
|
152
|
-
default: Default
|
193
|
+
default: Default,
|
153
194
|
*,
|
154
195
|
cache: bool = ...,
|
155
|
-
) -> _Invertible[T | Default
|
196
|
+
) -> _Invertible[T | Default]:
|
156
197
|
"""
|
157
198
|
Function used to retrieve an instance associated with the type passed in
|
158
199
|
parameter or `None`. Return a `Invertible` object. To access the instance
|
@@ -162,6 +203,14 @@ class Module:
|
|
162
203
|
Example: instance = ~lazy_instance
|
163
204
|
"""
|
164
205
|
|
206
|
+
@overload
|
207
|
+
def get_lazy_instance[T](
|
208
|
+
self,
|
209
|
+
cls: _InputType[T],
|
210
|
+
default: None = ...,
|
211
|
+
*,
|
212
|
+
cache: bool = ...,
|
213
|
+
) -> _Invertible[T | None]: ...
|
165
214
|
def init_modules(self, *modules: Module) -> Self:
|
166
215
|
"""
|
167
216
|
Function to clean modules in use and to use those passed as parameters.
|
@@ -212,6 +261,7 @@ class Module:
|
|
212
261
|
Function to unlock the module by deleting cached instances of singletons.
|
213
262
|
"""
|
214
263
|
|
264
|
+
async def all_ready(self) -> None: ...
|
215
265
|
def add_logger(self, logger: Logger) -> Self: ...
|
216
266
|
@classmethod
|
217
267
|
def from_name(cls, name: str) -> Module:
|
@@ -236,6 +286,8 @@ class Injectable[T](Protocol):
|
|
236
286
|
def is_locked(self) -> bool: ...
|
237
287
|
def unlock(self) -> None: ...
|
238
288
|
@abstractmethod
|
289
|
+
async def aget_instance(self) -> T: ...
|
290
|
+
@abstractmethod
|
239
291
|
def get_instance(self) -> T: ...
|
240
292
|
|
241
293
|
@final
|
@@ -243,3 +295,10 @@ class Mode(Enum):
|
|
243
295
|
FALLBACK = ...
|
244
296
|
NORMAL = ...
|
245
297
|
OVERRIDE = ...
|
298
|
+
|
299
|
+
class LazyInstance[T]:
|
300
|
+
def __init__(self, cls: _InputType[T], module: Module = ...) -> None: ...
|
301
|
+
@overload
|
302
|
+
def __get__(self, instance: object, owner: type | None = ...) -> T: ...
|
303
|
+
@overload
|
304
|
+
def __get__(self, instance: None = ..., owner: type | None = ...) -> Self: ...
|
injection/_core/__init__.py
CHANGED
@@ -49,5 +49,5 @@ def standardize_input_classes[T](
|
|
49
49
|
@Locator.static_hooks.on_update
|
50
50
|
def standardize_classes[T](*_: Any, **__: Any) -> HookGenerator[Updater[T]]:
|
51
51
|
updater = yield
|
52
|
-
updater.classes =
|
52
|
+
updater.classes = frozenset(standardize_types(*updater.classes))
|
53
53
|
return updater
|
@@ -0,0 +1,54 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
from collections.abc import Awaitable, Callable, Generator
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Any, NoReturn, Protocol, override, runtime_checkable
|
5
|
+
|
6
|
+
|
7
|
+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
8
|
+
class SimpleAwaitable[T](Awaitable[T]):
|
9
|
+
callable: Callable[..., Awaitable[T]]
|
10
|
+
|
11
|
+
@override
|
12
|
+
def __await__(self) -> Generator[Any, Any, T]:
|
13
|
+
return self.callable().__await__()
|
14
|
+
|
15
|
+
|
16
|
+
@runtime_checkable
|
17
|
+
class Caller[**P, T](Protocol):
|
18
|
+
__slots__ = ()
|
19
|
+
|
20
|
+
@abstractmethod
|
21
|
+
async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
22
|
+
raise NotImplementedError
|
23
|
+
|
24
|
+
@abstractmethod
|
25
|
+
def call(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
26
|
+
raise NotImplementedError
|
27
|
+
|
28
|
+
|
29
|
+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
30
|
+
class AsyncCaller[**P, T](Caller[P, T]):
|
31
|
+
callable: Callable[P, Awaitable[T]]
|
32
|
+
|
33
|
+
@override
|
34
|
+
async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
35
|
+
return await self.callable(*args, **kwargs)
|
36
|
+
|
37
|
+
@override
|
38
|
+
def call(self, /, *args: P.args, **kwargs: P.kwargs) -> NoReturn:
|
39
|
+
raise RuntimeError(
|
40
|
+
"Synchronous call isn't supported for an asynchronous Callable."
|
41
|
+
)
|
42
|
+
|
43
|
+
|
44
|
+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
45
|
+
class SyncCaller[**P, T](Caller[P, T]):
|
46
|
+
callable: Callable[P, T]
|
47
|
+
|
48
|
+
@override
|
49
|
+
async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
50
|
+
return self.callable(*args, **kwargs)
|
51
|
+
|
52
|
+
@override
|
53
|
+
def call(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
54
|
+
return self.callable(*args, **kwargs)
|
@@ -13,8 +13,8 @@ class Invertible[T](Protocol):
|
|
13
13
|
|
14
14
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
15
15
|
class SimpleInvertible[T](Invertible[T]):
|
16
|
-
|
16
|
+
callable: Callable[..., T]
|
17
17
|
|
18
18
|
@override
|
19
19
|
def __invert__(self) -> T:
|
20
|
-
return self.
|
20
|
+
return self.callable()
|
injection/_core/common/type.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
from collections.abc import
|
2
|
-
from inspect import
|
1
|
+
from collections.abc import Callable, Iterable, Iterator
|
2
|
+
from inspect import isfunction
|
3
3
|
from types import GenericAlias, UnionType
|
4
4
|
from typing import (
|
5
5
|
Annotated,
|
@@ -24,9 +24,6 @@ def get_return_types(*args: TypeInfo[Any]) -> Iterator[InputType[Any]]:
|
|
24
24
|
inner_args = arg
|
25
25
|
|
26
26
|
elif isfunction(arg) and (return_type := get_type_hints(arg).get("return")):
|
27
|
-
if iscoroutinefunction(arg):
|
28
|
-
return_type = Awaitable[return_type] # type: ignore[valid-type]
|
29
|
-
|
30
27
|
inner_args = (return_type,)
|
31
28
|
|
32
29
|
else:
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from typing import Self
|
2
|
+
|
3
|
+
from injection._core.common.invertible import Invertible
|
4
|
+
from injection._core.common.type import InputType
|
5
|
+
from injection._core.module import Module, mod
|
6
|
+
|
7
|
+
|
8
|
+
class LazyInstance[T]:
|
9
|
+
__slots__ = ("__value",)
|
10
|
+
|
11
|
+
__value: Invertible[T]
|
12
|
+
|
13
|
+
def __init__(self, cls: InputType[T], module: Module | None = None) -> None:
|
14
|
+
module = module or mod()
|
15
|
+
self.__value = module.get_lazy_instance(cls, default=NotImplemented)
|
16
|
+
|
17
|
+
def __get__(
|
18
|
+
self,
|
19
|
+
instance: object | None = None,
|
20
|
+
owner: type | None = None,
|
21
|
+
) -> Self | T:
|
22
|
+
if instance is None:
|
23
|
+
return self
|
24
|
+
|
25
|
+
return ~self.__value
|
injection/_core/hook.py
CHANGED
@@ -2,12 +2,13 @@ import itertools
|
|
2
2
|
from collections.abc import Callable, Generator, Iterator
|
3
3
|
from dataclasses import dataclass, field
|
4
4
|
from inspect import isclass, isgeneratorfunction
|
5
|
-
from typing import Any, Self
|
5
|
+
from typing import Any, Self, TypeGuard
|
6
6
|
|
7
7
|
from injection.exceptions import HookError
|
8
8
|
|
9
9
|
type HookGenerator[T] = Generator[None, T, T]
|
10
|
-
type
|
10
|
+
type HookGeneratorFunction[**P, T] = Callable[P, HookGenerator[T]]
|
11
|
+
type HookFunction[**P, T] = Callable[P, T] | HookGeneratorFunction[P, T]
|
11
12
|
|
12
13
|
|
13
14
|
@dataclass(eq=False, frozen=True, slots=True)
|
@@ -18,12 +19,12 @@ class Hook[**P, T]:
|
|
18
19
|
repr=False,
|
19
20
|
)
|
20
21
|
|
21
|
-
def __call__(
|
22
|
+
def __call__(
|
22
23
|
self,
|
23
24
|
wrapped: HookFunction[P, T] | type[HookFunction[P, T]] | None = None,
|
24
25
|
/,
|
25
|
-
):
|
26
|
-
def decorator(wp
|
26
|
+
) -> Any:
|
27
|
+
def decorator(wp: Any) -> Any:
|
27
28
|
self.add(wp() if isclass(wp) else wp)
|
28
29
|
return wp
|
29
30
|
|
@@ -48,11 +49,11 @@ class Hook[**P, T]:
|
|
48
49
|
handler: Callable[P, T],
|
49
50
|
function: HookFunction[P, T],
|
50
51
|
) -> Callable[P, T]:
|
51
|
-
if not cls.
|
52
|
+
if not cls.__is_hook_generator_function(function):
|
52
53
|
return function # type: ignore[return-value]
|
53
54
|
|
54
55
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
55
|
-
hook: HookGenerator[T] = function(*args, **kwargs)
|
56
|
+
hook: HookGenerator[T] = function(*args, **kwargs)
|
56
57
|
|
57
58
|
try:
|
58
59
|
next(hook)
|
@@ -88,9 +89,11 @@ class Hook[**P, T]:
|
|
88
89
|
return handler
|
89
90
|
|
90
91
|
@staticmethod
|
91
|
-
def
|
92
|
-
|
93
|
-
|
92
|
+
def __is_hook_generator_function[**_P, _T](
|
93
|
+
function: HookFunction[_P, _T],
|
94
|
+
) -> TypeGuard[HookGeneratorFunction[_P, _T]]:
|
95
|
+
for fn in function, getattr(function, "__call__", None):
|
96
|
+
if isgeneratorfunction(fn):
|
94
97
|
return True
|
95
98
|
|
96
99
|
return False
|
@@ -0,0 +1,106 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
from collections.abc import MutableMapping
|
3
|
+
from contextlib import suppress
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from typing import Any, ClassVar, NoReturn, Protocol, override, runtime_checkable
|
6
|
+
|
7
|
+
from injection._core.common.asynchronous import Caller
|
8
|
+
from injection._core.common.threading import synchronized
|
9
|
+
from injection.exceptions import InjectionError
|
10
|
+
|
11
|
+
|
12
|
+
@runtime_checkable
|
13
|
+
class Injectable[T](Protocol):
|
14
|
+
__slots__ = ()
|
15
|
+
|
16
|
+
@property
|
17
|
+
def is_locked(self) -> bool:
|
18
|
+
return False
|
19
|
+
|
20
|
+
def unlock(self) -> None:
|
21
|
+
return
|
22
|
+
|
23
|
+
@abstractmethod
|
24
|
+
async def aget_instance(self) -> T:
|
25
|
+
raise NotImplementedError
|
26
|
+
|
27
|
+
@abstractmethod
|
28
|
+
def get_instance(self) -> T:
|
29
|
+
raise NotImplementedError
|
30
|
+
|
31
|
+
|
32
|
+
@dataclass(repr=False, frozen=True, slots=True)
|
33
|
+
class BaseInjectable[T](Injectable[T], ABC):
|
34
|
+
factory: Caller[..., T]
|
35
|
+
|
36
|
+
|
37
|
+
class SimpleInjectable[T](BaseInjectable[T]):
|
38
|
+
__slots__ = ()
|
39
|
+
|
40
|
+
@override
|
41
|
+
async def aget_instance(self) -> T:
|
42
|
+
return await self.factory.acall()
|
43
|
+
|
44
|
+
@override
|
45
|
+
def get_instance(self) -> T:
|
46
|
+
return self.factory.call()
|
47
|
+
|
48
|
+
|
49
|
+
class SingletonInjectable[T](BaseInjectable[T]):
|
50
|
+
__slots__ = ("__dict__",)
|
51
|
+
|
52
|
+
__key: ClassVar[str] = "$instance"
|
53
|
+
|
54
|
+
@property
|
55
|
+
def cache(self) -> MutableMapping[str, Any]:
|
56
|
+
return self.__dict__
|
57
|
+
|
58
|
+
@property
|
59
|
+
@override
|
60
|
+
def is_locked(self) -> bool:
|
61
|
+
return self.__key in self.cache
|
62
|
+
|
63
|
+
@override
|
64
|
+
def unlock(self) -> None:
|
65
|
+
self.cache.clear()
|
66
|
+
|
67
|
+
@override
|
68
|
+
async def aget_instance(self) -> T:
|
69
|
+
with suppress(KeyError):
|
70
|
+
return self.__check_instance()
|
71
|
+
|
72
|
+
with synchronized():
|
73
|
+
instance = await self.factory.acall()
|
74
|
+
self.__set_instance(instance)
|
75
|
+
|
76
|
+
return instance
|
77
|
+
|
78
|
+
@override
|
79
|
+
def get_instance(self) -> T:
|
80
|
+
with suppress(KeyError):
|
81
|
+
return self.__check_instance()
|
82
|
+
|
83
|
+
with synchronized():
|
84
|
+
instance = self.factory.call()
|
85
|
+
self.__set_instance(instance)
|
86
|
+
|
87
|
+
return instance
|
88
|
+
|
89
|
+
def __check_instance(self) -> T:
|
90
|
+
return self.cache[self.__key]
|
91
|
+
|
92
|
+
def __set_instance(self, value: T) -> None:
|
93
|
+
self.cache[self.__key] = value
|
94
|
+
|
95
|
+
|
96
|
+
@dataclass(repr=False, frozen=True, slots=True)
|
97
|
+
class ShouldBeInjectable[T](Injectable[T]):
|
98
|
+
cls: type[T]
|
99
|
+
|
100
|
+
@override
|
101
|
+
async def aget_instance(self) -> T:
|
102
|
+
return self.get_instance()
|
103
|
+
|
104
|
+
@override
|
105
|
+
def get_instance(self) -> NoReturn:
|
106
|
+
raise InjectionError(f"`{self.cls}` should be an injectable.")
|