python-injection 0.10.2__tar.gz → 0.10.3__tar.gz
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.
- {python_injection-0.10.2 → python_injection-0.10.3}/PKG-INFO +1 -1
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/__init__.py +3 -5
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/__init__.pyi +10 -11
- python_injection-0.10.3/injection/_core/__init__.py +53 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/_core/common/type.py +28 -35
- python_injection-0.10.3/injection/_core/hook.py +96 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/_core/module.py +97 -59
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/exceptions.py +5 -1
- {python_injection-0.10.2 → python_injection-0.10.3}/pyproject.toml +1 -1
- python_injection-0.10.2/injection/integrations/__init__.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/README.md +0 -0
- {python_injection-0.10.2/injection/_core → python_injection-0.10.3/injection/_core/common}/__init__.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/_core/common/event.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/_core/common/invertible.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/_core/common/lazy.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/_core/common/threading.py +0 -0
- {python_injection-0.10.2/injection/_core/common → python_injection-0.10.3/injection/integrations}/__init__.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/integrations/blacksheep.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/py.typed +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/testing/__init__.py +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/testing/__init__.pyi +0 -0
- {python_injection-0.10.2 → python_injection-0.10.3}/injection/utils.py +0 -0
@@ -1,12 +1,10 @@
|
|
1
|
-
from ._core.module import Injectable, Module
|
2
|
-
from ._core.module import Mode as InjectableMode
|
3
|
-
from ._core.module import Priority as ModulePriority
|
1
|
+
from ._core.module import Injectable, Mode, Module, Priority
|
4
2
|
|
5
3
|
__all__ = (
|
6
4
|
"Injectable",
|
7
|
-
"
|
5
|
+
"Mode",
|
8
6
|
"Module",
|
9
|
-
"
|
7
|
+
"Priority",
|
10
8
|
"constant",
|
11
9
|
"find_instance",
|
12
10
|
"get_instance",
|
@@ -16,8 +16,7 @@ from ._core.common.invertible import Invertible as _Invertible
|
|
16
16
|
from ._core.common.type import InputType as _InputType
|
17
17
|
from ._core.common.type import TypeInfo as _TypeInfo
|
18
18
|
from ._core.module import InjectableFactory as _InjectableFactory
|
19
|
-
from ._core.module import ModeStr
|
20
|
-
from ._core.module import PriorityStr as ModulePriorityStr
|
19
|
+
from ._core.module import ModeStr, PriorityStr
|
21
20
|
|
22
21
|
_: Module = ...
|
23
22
|
|
@@ -68,7 +67,7 @@ class Module:
|
|
68
67
|
cls: _InjectableFactory[T] = ...,
|
69
68
|
inject: bool = ...,
|
70
69
|
on: _TypeInfo[T] = ...,
|
71
|
-
mode:
|
70
|
+
mode: Mode | ModeStr = ...,
|
72
71
|
):
|
73
72
|
"""
|
74
73
|
Decorator applicable to a class or function. It is used to indicate how the
|
@@ -83,7 +82,7 @@ class Module:
|
|
83
82
|
*,
|
84
83
|
inject: bool = ...,
|
85
84
|
on: _TypeInfo[T] = ...,
|
86
|
-
mode:
|
85
|
+
mode: Mode | ModeStr = ...,
|
87
86
|
):
|
88
87
|
"""
|
89
88
|
Decorator applicable to a class or function. It is used to indicate how the
|
@@ -104,7 +103,7 @@ class Module:
|
|
104
103
|
/,
|
105
104
|
*,
|
106
105
|
on: _TypeInfo[T] = ...,
|
107
|
-
mode:
|
106
|
+
mode: Mode | ModeStr = ...,
|
108
107
|
):
|
109
108
|
"""
|
110
109
|
Decorator applicable to a class or function. It is used to indicate how the
|
@@ -118,7 +117,7 @@ class Module:
|
|
118
117
|
on: _TypeInfo[T] = ...,
|
119
118
|
*,
|
120
119
|
alias: bool = ...,
|
121
|
-
mode:
|
120
|
+
mode: Mode | ModeStr = ...,
|
122
121
|
) -> Self:
|
123
122
|
"""
|
124
123
|
Function for registering a specific instance to be injected. This is useful for
|
@@ -162,7 +161,7 @@ class Module:
|
|
162
161
|
self,
|
163
162
|
module: Module,
|
164
163
|
*,
|
165
|
-
priority:
|
164
|
+
priority: Priority | PriorityStr = ...,
|
166
165
|
) -> Self:
|
167
166
|
"""
|
168
167
|
Function for using another module. Using another module replaces the module's
|
@@ -179,7 +178,7 @@ class Module:
|
|
179
178
|
self,
|
180
179
|
module: Module,
|
181
180
|
*,
|
182
|
-
priority:
|
181
|
+
priority: Priority | PriorityStr = ...,
|
183
182
|
) -> ContextManager[None] | ContextDecorator:
|
184
183
|
"""
|
185
184
|
Context manager or decorator for temporary use of a module.
|
@@ -188,7 +187,7 @@ class Module:
|
|
188
187
|
def change_priority(
|
189
188
|
self,
|
190
189
|
module: Module,
|
191
|
-
priority:
|
190
|
+
priority: Priority | PriorityStr,
|
192
191
|
) -> Self:
|
193
192
|
"""
|
194
193
|
Function for changing the priority of a module in use.
|
@@ -217,7 +216,7 @@ class Module:
|
|
217
216
|
"""
|
218
217
|
|
219
218
|
@final
|
220
|
-
class
|
219
|
+
class Priority(Enum):
|
221
220
|
LOW = ...
|
222
221
|
HIGH = ...
|
223
222
|
|
@@ -230,7 +229,7 @@ class Injectable[T](Protocol):
|
|
230
229
|
def get_instance(self) -> T: ...
|
231
230
|
|
232
231
|
@final
|
233
|
-
class
|
232
|
+
class Mode(Enum):
|
234
233
|
FALLBACK = ...
|
235
234
|
NORMAL = ...
|
236
235
|
OVERRIDE = ...
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from collections.abc import Iterable
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from injection._core.common.type import InputType, standardize_types
|
5
|
+
from injection._core.hook import HookGenerator
|
6
|
+
from injection._core.module import Locator, Mode, Record, Updater
|
7
|
+
|
8
|
+
__all__ = ()
|
9
|
+
|
10
|
+
|
11
|
+
@Locator.static_hooks.on_conflict
|
12
|
+
def check_mode[T](
|
13
|
+
new: Record[T],
|
14
|
+
existing: Record[T],
|
15
|
+
cls: InputType[T],
|
16
|
+
*_: Any,
|
17
|
+
**__: Any,
|
18
|
+
) -> HookGenerator[bool]:
|
19
|
+
new_mode = new.mode
|
20
|
+
is_override = new_mode == Mode.OVERRIDE
|
21
|
+
|
22
|
+
if new_mode == existing.mode and not is_override:
|
23
|
+
raise RuntimeError(f"An injectable already exists for the class `{cls}`.")
|
24
|
+
|
25
|
+
value = yield
|
26
|
+
return value or is_override
|
27
|
+
|
28
|
+
|
29
|
+
@Locator.static_hooks.on_conflict
|
30
|
+
def compare_mode_rank[T](
|
31
|
+
new: Record[T],
|
32
|
+
existing: Record[T],
|
33
|
+
*_: Any,
|
34
|
+
**__: Any,
|
35
|
+
) -> HookGenerator[bool]:
|
36
|
+
value = yield
|
37
|
+
return value or new.mode.rank > existing.mode.rank
|
38
|
+
|
39
|
+
|
40
|
+
@Locator.static_hooks.on_input
|
41
|
+
def standardize_input_classes[T](
|
42
|
+
*_: Any,
|
43
|
+
**__: Any,
|
44
|
+
) -> HookGenerator[Iterable[InputType[T]]]:
|
45
|
+
classes = yield
|
46
|
+
return tuple(standardize_types(*classes, with_origin=True))
|
47
|
+
|
48
|
+
|
49
|
+
@Locator.static_hooks.on_update
|
50
|
+
def standardize_classes[T](*_: Any, **__: Any) -> HookGenerator[Updater[T]]:
|
51
|
+
updater = yield
|
52
|
+
updater.classes = set(standardize_types(*updater.classes))
|
53
|
+
return updater
|
@@ -1,22 +1,34 @@
|
|
1
|
-
from collections.abc import Callable, Iterable, Iterator
|
2
|
-
from inspect import
|
3
|
-
from types import UnionType
|
4
|
-
from typing import
|
5
|
-
|
6
|
-
|
7
|
-
TypeAliasType,
|
8
|
-
Union,
|
9
|
-
cast,
|
10
|
-
get_args,
|
11
|
-
get_origin,
|
12
|
-
)
|
13
|
-
|
14
|
-
type TypeDef[T] = type[T] | TypeAliasType
|
1
|
+
from collections.abc import Awaitable, Callable, Iterable, Iterator
|
2
|
+
from inspect import iscoroutinefunction, isfunction
|
3
|
+
from types import GenericAlias, UnionType
|
4
|
+
from typing import Annotated, Any, Union, get_args, get_origin, get_type_hints
|
5
|
+
|
6
|
+
type TypeDef[T] = type[T] | GenericAlias
|
15
7
|
type InputType[T] = TypeDef[T] | UnionType
|
16
8
|
type TypeInfo[T] = InputType[T] | Callable[..., T] | Iterable[TypeInfo[T]]
|
17
9
|
|
18
10
|
|
19
|
-
def
|
11
|
+
def get_return_types(*args: TypeInfo[Any]) -> Iterator[InputType[Any]]:
|
12
|
+
for arg in args:
|
13
|
+
if isinstance(arg, Iterable) and not (
|
14
|
+
isinstance(arg, type | str) or isinstance(get_origin(arg), type)
|
15
|
+
):
|
16
|
+
inner_args = arg
|
17
|
+
|
18
|
+
elif isfunction(arg) and (return_type := get_type_hints(arg).get("return")):
|
19
|
+
if iscoroutinefunction(arg):
|
20
|
+
return_type = Awaitable[return_type] # type: ignore[valid-type]
|
21
|
+
|
22
|
+
inner_args = (return_type,)
|
23
|
+
|
24
|
+
else:
|
25
|
+
yield arg # type: ignore[misc]
|
26
|
+
continue
|
27
|
+
|
28
|
+
yield from get_return_types(*inner_args)
|
29
|
+
|
30
|
+
|
31
|
+
def standardize_types(
|
20
32
|
*types: InputType[Any],
|
21
33
|
with_origin: bool = False,
|
22
34
|
) -> Iterator[TypeDef[Any]]:
|
@@ -40,23 +52,4 @@ def analyze_types(
|
|
40
52
|
|
41
53
|
continue
|
42
54
|
|
43
|
-
yield from
|
44
|
-
|
45
|
-
|
46
|
-
def get_return_types(*args: TypeInfo[Any]) -> Iterator[InputType[Any]]:
|
47
|
-
for arg in args:
|
48
|
-
if isinstance(arg, Iterable) and not (
|
49
|
-
isinstance(arg, type | str) or isinstance(get_origin(arg), type)
|
50
|
-
):
|
51
|
-
inner_args = arg
|
52
|
-
|
53
|
-
elif isfunction(arg) and (
|
54
|
-
return_type := get_annotations(arg, eval_str=True).get("return")
|
55
|
-
):
|
56
|
-
inner_args = (return_type,)
|
57
|
-
|
58
|
-
else:
|
59
|
-
yield cast(InputType[Any], arg)
|
60
|
-
continue
|
61
|
-
|
62
|
-
yield from get_return_types(*inner_args)
|
55
|
+
yield from standardize_types(*inner_types, with_origin=with_origin)
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import itertools
|
2
|
+
from collections.abc import Callable, Generator, Iterator
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
from inspect import isclass, isgeneratorfunction
|
5
|
+
from typing import Self
|
6
|
+
|
7
|
+
from injection.exceptions import HookError
|
8
|
+
|
9
|
+
type HookGenerator[T] = Generator[None, T, T]
|
10
|
+
type HookFunction[**P, T] = Callable[P, T | HookGenerator[T]]
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass(eq=False, frozen=True, slots=True)
|
14
|
+
class Hook[**P, T]:
|
15
|
+
__functions: list[HookFunction[P, T]] = field(
|
16
|
+
default_factory=list,
|
17
|
+
init=False,
|
18
|
+
repr=False,
|
19
|
+
)
|
20
|
+
|
21
|
+
def __call__( # type: ignore[no-untyped-def]
|
22
|
+
self,
|
23
|
+
wrapped: HookFunction[P, T] | type[HookFunction[P, T]] | None = None,
|
24
|
+
/,
|
25
|
+
):
|
26
|
+
def decorator(wp): # type: ignore[no-untyped-def]
|
27
|
+
self.add(wp() if isclass(wp) else wp)
|
28
|
+
return wp
|
29
|
+
|
30
|
+
return decorator(wrapped) if wrapped else decorator
|
31
|
+
|
32
|
+
@property
|
33
|
+
def __stack(self) -> Iterator[HookFunction[P, T]]:
|
34
|
+
return iter(self.__functions)
|
35
|
+
|
36
|
+
def add(self, *functions: HookFunction[P, T]) -> Self:
|
37
|
+
self.__functions.extend(functions)
|
38
|
+
return self
|
39
|
+
|
40
|
+
@classmethod
|
41
|
+
def apply_several(cls, handler: Callable[P, T], *hooks: Self) -> Callable[P, T]:
|
42
|
+
stack = itertools.chain.from_iterable((hook.__stack for hook in hooks))
|
43
|
+
return cls.__apply_stack(handler, stack)
|
44
|
+
|
45
|
+
@classmethod
|
46
|
+
def __apply_function(
|
47
|
+
cls,
|
48
|
+
handler: Callable[P, T],
|
49
|
+
function: HookFunction[P, T],
|
50
|
+
) -> Callable[P, T]:
|
51
|
+
if not isgeneratorfunction(function):
|
52
|
+
return function # type: ignore[return-value]
|
53
|
+
|
54
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
55
|
+
hook = function(*args, **kwargs)
|
56
|
+
|
57
|
+
try:
|
58
|
+
next(hook)
|
59
|
+
|
60
|
+
try:
|
61
|
+
value = handler(*args, **kwargs)
|
62
|
+
except BaseException as exc:
|
63
|
+
hook.throw(exc)
|
64
|
+
else:
|
65
|
+
hook.send(value)
|
66
|
+
return value
|
67
|
+
|
68
|
+
except StopIteration as stop:
|
69
|
+
return stop.value
|
70
|
+
|
71
|
+
finally:
|
72
|
+
hook.close()
|
73
|
+
|
74
|
+
raise HookError("Missing return value.")
|
75
|
+
|
76
|
+
return wrapper
|
77
|
+
|
78
|
+
@classmethod
|
79
|
+
def __apply_stack(
|
80
|
+
cls,
|
81
|
+
handler: Callable[P, T],
|
82
|
+
stack: Iterator[HookFunction[P, T]],
|
83
|
+
) -> Callable[P, T]:
|
84
|
+
for function in stack:
|
85
|
+
new_handler = cls.__apply_function(handler, function)
|
86
|
+
return cls.__apply_stack(new_handler, stack)
|
87
|
+
|
88
|
+
return handler
|
89
|
+
|
90
|
+
|
91
|
+
def apply_hooks[**P, T](
|
92
|
+
handler: Callable[P, T],
|
93
|
+
hook: Hook[P, T],
|
94
|
+
*hooks: Hook[P, T],
|
95
|
+
) -> Callable[P, T]:
|
96
|
+
return Hook.apply_several(handler, hook, *hooks)
|
@@ -37,13 +37,8 @@ from injection._core.common.event import Event, EventChannel, EventListener
|
|
37
37
|
from injection._core.common.invertible import Invertible, SimpleInvertible
|
38
38
|
from injection._core.common.lazy import Lazy, LazyMapping
|
39
39
|
from injection._core.common.threading import synchronized
|
40
|
-
from injection._core.common.type import
|
41
|
-
|
42
|
-
TypeDef,
|
43
|
-
TypeInfo,
|
44
|
-
analyze_types,
|
45
|
-
get_return_types,
|
46
|
-
)
|
40
|
+
from injection._core.common.type import InputType, TypeInfo, get_return_types
|
41
|
+
from injection._core.hook import Hook, apply_hooks
|
47
42
|
from injection.exceptions import (
|
48
43
|
InjectionError,
|
49
44
|
ModuleError,
|
@@ -64,7 +59,7 @@ class LocatorEvent(Event, ABC):
|
|
64
59
|
|
65
60
|
@dataclass(frozen=True, slots=True)
|
66
61
|
class LocatorDependenciesUpdated[T](LocatorEvent):
|
67
|
-
classes: Collection[
|
62
|
+
classes: Collection[InputType[T]]
|
68
63
|
mode: Mode
|
69
64
|
|
70
65
|
@override
|
@@ -206,6 +201,13 @@ class ShouldBeInjectable[T](Injectable[T]):
|
|
206
201
|
def get_instance(self) -> NoReturn:
|
207
202
|
raise InjectionError(f"`{self.cls}` should be an injectable.")
|
208
203
|
|
204
|
+
@classmethod
|
205
|
+
def from_callable(cls, callable: Callable[..., T]) -> Self:
|
206
|
+
if not isclass(callable):
|
207
|
+
raise TypeError(f"`{callable}` should be a class.")
|
208
|
+
|
209
|
+
return cls(callable)
|
210
|
+
|
209
211
|
|
210
212
|
"""
|
211
213
|
Broker
|
@@ -255,22 +257,58 @@ class Mode(StrEnum):
|
|
255
257
|
|
256
258
|
type ModeStr = Literal["fallback", "normal", "override"]
|
257
259
|
|
260
|
+
type InjectableFactory[T] = Callable[[Callable[..., T]], Injectable[T]]
|
261
|
+
|
258
262
|
|
259
263
|
class Record[T](NamedTuple):
|
260
264
|
injectable: Injectable[T]
|
261
265
|
mode: Mode
|
262
266
|
|
263
267
|
|
268
|
+
@dataclass(repr=False, eq=False, kw_only=True, slots=True)
|
269
|
+
class Updater[T]:
|
270
|
+
factory: Callable[..., T]
|
271
|
+
classes: Iterable[InputType[T]]
|
272
|
+
injectable_factory: InjectableFactory[T]
|
273
|
+
mode: Mode
|
274
|
+
|
275
|
+
def make_record(self) -> Record[T]:
|
276
|
+
injectable = self.injectable_factory(self.factory)
|
277
|
+
return Record(injectable, self.mode)
|
278
|
+
|
279
|
+
|
280
|
+
class LocatorHooks[T](NamedTuple):
|
281
|
+
on_conflict: Hook[[Record[T], Record[T], InputType[T]], bool]
|
282
|
+
on_input: Hook[[Iterable[InputType[T]]], Iterable[InputType[T]]]
|
283
|
+
on_update: Hook[[Updater[T]], Updater[T]]
|
284
|
+
|
285
|
+
@classmethod
|
286
|
+
def default(cls) -> Self:
|
287
|
+
return cls(
|
288
|
+
on_conflict=Hook(),
|
289
|
+
on_input=Hook(),
|
290
|
+
on_update=Hook(),
|
291
|
+
)
|
292
|
+
|
293
|
+
|
264
294
|
@dataclass(repr=False, frozen=True, slots=True)
|
265
295
|
class Locator(Broker):
|
266
|
-
__records: dict[
|
267
|
-
|
296
|
+
__records: dict[InputType[Any], Record[Any]] = field(
|
297
|
+
default_factory=dict,
|
298
|
+
init=False,
|
299
|
+
)
|
300
|
+
__channel: EventChannel = field(
|
301
|
+
default_factory=EventChannel,
|
302
|
+
init=False,
|
303
|
+
)
|
304
|
+
|
305
|
+
static_hooks: ClassVar[LocatorHooks[Any]] = LocatorHooks.default()
|
268
306
|
|
269
307
|
@override
|
270
308
|
def __getitem__[T](self, cls: InputType[T], /) -> Injectable[T]:
|
271
|
-
for
|
309
|
+
for input_class in self.__standardize_inputs((cls,)):
|
272
310
|
try:
|
273
|
-
record = self.__records[
|
311
|
+
record = self.__records[input_class]
|
274
312
|
except KeyError:
|
275
313
|
continue
|
276
314
|
|
@@ -281,8 +319,8 @@ class Locator(Broker):
|
|
281
319
|
@override
|
282
320
|
def __contains__(self, cls: InputType[Any], /) -> bool:
|
283
321
|
return any(
|
284
|
-
|
285
|
-
for
|
322
|
+
input_class in self.__records
|
323
|
+
for input_class in self.__standardize_inputs((cls,))
|
286
324
|
)
|
287
325
|
|
288
326
|
@property
|
@@ -292,21 +330,16 @@ class Locator(Broker):
|
|
292
330
|
|
293
331
|
@property
|
294
332
|
def __injectables(self) -> frozenset[Injectable[Any]]:
|
295
|
-
return frozenset(injectable for
|
333
|
+
return frozenset(record.injectable for record in self.__records.values())
|
296
334
|
|
297
335
|
@synchronized()
|
298
|
-
def update[T](
|
299
|
-
self
|
300
|
-
|
301
|
-
|
302
|
-
mode: Mode | ModeStr,
|
303
|
-
) -> Self:
|
304
|
-
mode = Mode(mode)
|
305
|
-
record = Record(injectable, mode)
|
306
|
-
records = {cls: record for cls in self.__prepare_for_updating(classes, mode)}
|
336
|
+
def update[T](self, updater: Updater[T]) -> Self:
|
337
|
+
updater = self.__update_preprocessing(updater)
|
338
|
+
record = updater.make_record()
|
339
|
+
records = dict(self.__prepare_for_updating(updater.classes, record))
|
307
340
|
|
308
341
|
if records:
|
309
|
-
event = LocatorDependenciesUpdated(self, records.keys(), mode)
|
342
|
+
event = LocatorDependenciesUpdated(self, records.keys(), record.mode)
|
310
343
|
|
311
344
|
with self.dispatch(event):
|
312
345
|
self.__records.update(records)
|
@@ -331,29 +364,38 @@ class Locator(Broker):
|
|
331
364
|
def __prepare_for_updating[T](
|
332
365
|
self,
|
333
366
|
classes: Iterable[InputType[T]],
|
334
|
-
|
335
|
-
) -> Iterator[
|
336
|
-
|
337
|
-
|
338
|
-
for cls in frozenset(analyze_types(*classes)):
|
367
|
+
record: Record[T],
|
368
|
+
) -> Iterator[tuple[InputType[T], Record[T]]]:
|
369
|
+
for cls in classes:
|
339
370
|
try:
|
340
|
-
|
341
|
-
|
371
|
+
existing = self.__records[cls]
|
342
372
|
except KeyError:
|
343
373
|
...
|
344
|
-
|
345
374
|
else:
|
346
|
-
|
375
|
+
if not self.__keep_new_record(record, existing, cls):
|
376
|
+
continue
|
347
377
|
|
348
|
-
|
349
|
-
raise RuntimeError(
|
350
|
-
f"An injectable already exists for the class `{cls}`."
|
351
|
-
)
|
378
|
+
yield cls, record
|
352
379
|
|
353
|
-
|
354
|
-
|
380
|
+
def __keep_new_record[T](
|
381
|
+
self,
|
382
|
+
new: Record[T],
|
383
|
+
existing: Record[T],
|
384
|
+
cls: InputType[T],
|
385
|
+
) -> bool:
|
386
|
+
return apply_hooks(
|
387
|
+
lambda *args, **kwargs: False,
|
388
|
+
self.static_hooks.on_conflict,
|
389
|
+
)(new, existing, cls)
|
355
390
|
|
356
|
-
|
391
|
+
def __standardize_inputs[T](
|
392
|
+
self,
|
393
|
+
classes: Iterable[InputType[T]],
|
394
|
+
) -> Iterable[InputType[T]]:
|
395
|
+
return apply_hooks(lambda c: c, self.static_hooks.on_input)(classes)
|
396
|
+
|
397
|
+
def __update_preprocessing[T](self, updater: Updater[T]) -> Updater[T]:
|
398
|
+
return apply_hooks(lambda u: u, self.static_hooks.on_update)(updater)
|
357
399
|
|
358
400
|
|
359
401
|
"""
|
@@ -372,8 +414,6 @@ class Priority(StrEnum):
|
|
372
414
|
|
373
415
|
type PriorityStr = Literal["low", "high"]
|
374
416
|
|
375
|
-
type InjectableFactory[T] = Callable[[Callable[..., T]], Injectable[T]]
|
376
|
-
|
377
417
|
|
378
418
|
@dataclass(eq=False, frozen=True, slots=True)
|
379
419
|
class Module(Broker, EventListener):
|
@@ -438,9 +478,14 @@ class Module(Broker, EventListener):
|
|
438
478
|
):
|
439
479
|
def decorator(wp): # type: ignore[no-untyped-def]
|
440
480
|
factory = self.inject(wp, return_factory=True) if inject else wp
|
441
|
-
injectable = cls(factory)
|
442
481
|
classes = get_return_types(wp, on)
|
443
|
-
|
482
|
+
updater = Updater(
|
483
|
+
factory=factory,
|
484
|
+
classes=classes,
|
485
|
+
injectable_factory=cls,
|
486
|
+
mode=Mode(mode),
|
487
|
+
)
|
488
|
+
self.update(updater)
|
444
489
|
return wp
|
445
490
|
|
446
491
|
return decorator(wrapped) if wrapped else decorator
|
@@ -449,11 +494,13 @@ class Module(Broker, EventListener):
|
|
449
494
|
|
450
495
|
def should_be_injectable[T](self, wrapped: type[T] | None = None, /): # type: ignore[no-untyped-def]
|
451
496
|
def decorator(wp): # type: ignore[no-untyped-def]
|
452
|
-
|
453
|
-
|
454
|
-
|
497
|
+
updater = Updater(
|
498
|
+
factory=wp,
|
499
|
+
classes=(wp,),
|
500
|
+
injectable_factory=ShouldBeInjectable.from_callable,
|
455
501
|
mode=Mode.FALLBACK,
|
456
502
|
)
|
503
|
+
self.update(updater)
|
457
504
|
return wp
|
458
505
|
|
459
506
|
return decorator(wrapped) if wrapped else decorator
|
@@ -543,13 +590,8 @@ class Module(Broker, EventListener):
|
|
543
590
|
function.set_owner(cls)
|
544
591
|
return SimpleInvertible(function)
|
545
592
|
|
546
|
-
def update[T](
|
547
|
-
self
|
548
|
-
classes: Iterable[InputType[T]],
|
549
|
-
injectable: Injectable[T],
|
550
|
-
mode: Mode | ModeStr = Mode.get_default(),
|
551
|
-
) -> Self:
|
552
|
-
self.__locator.update(classes, injectable, mode)
|
593
|
+
def update[T](self, updater: Updater[T]) -> Self:
|
594
|
+
self.__locator.update(updater)
|
553
595
|
return self
|
554
596
|
|
555
597
|
def init_modules(self, *modules: Module) -> Self:
|
@@ -881,11 +923,7 @@ class InjectedFunction[**P, T](EventListener):
|
|
881
923
|
yield
|
882
924
|
self.update(event.module)
|
883
925
|
|
884
|
-
@synchronized()
|
885
926
|
def __close_setup_queue(self) -> None:
|
886
|
-
if self.__setup_queue is None:
|
887
|
-
return
|
888
|
-
|
889
927
|
self.__setup_queue = None
|
890
928
|
|
891
929
|
def __setup(self) -> None:
|
@@ -1,11 +1,12 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
3
|
__all__ = (
|
4
|
+
"HookError",
|
4
5
|
"InjectionError",
|
5
|
-
"NoInjectable",
|
6
6
|
"ModuleError",
|
7
7
|
"ModuleLockError",
|
8
8
|
"ModuleNotUsedError",
|
9
|
+
"NoInjectable",
|
9
10
|
)
|
10
11
|
|
11
12
|
|
@@ -33,3 +34,6 @@ class ModuleLockError(ModuleError): ...
|
|
33
34
|
|
34
35
|
|
35
36
|
class ModuleNotUsedError(KeyError, ModuleError): ...
|
37
|
+
|
38
|
+
|
39
|
+
class HookError(InjectionError): ...
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|