python-injection 0.14.0.post0__py3-none-any.whl → 0.14.2__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__.pyi +9 -2
- injection/_core/hook.py +3 -5
- injection/_core/module.py +39 -32
- injection/exceptions.py +5 -1
- {python_injection-0.14.0.post0.dist-info → python_injection-0.14.2.dist-info}/METADATA +1 -1
- {python_injection-0.14.0.post0.dist-info → python_injection-0.14.2.dist-info}/RECORD +7 -7
- {python_injection-0.14.0.post0.dist-info → python_injection-0.14.2.dist-info}/WHEEL +0 -0
injection/__init__.pyi
CHANGED
@@ -10,6 +10,7 @@ from ._core.common.type import InputType as _InputType
|
|
10
10
|
from ._core.common.type import TypeInfo as _TypeInfo
|
11
11
|
from ._core.module import InjectableFactory as _InjectableFactory
|
12
12
|
from ._core.module import ModeStr, PriorityStr
|
13
|
+
from ._core.module import Recipe as _Recipe
|
13
14
|
|
14
15
|
__MODULE: Final[Module] = ...
|
15
16
|
|
@@ -91,7 +92,7 @@ class Module:
|
|
91
92
|
|
92
93
|
def injectable[**P, T](
|
93
94
|
self,
|
94
|
-
wrapped:
|
95
|
+
wrapped: _Recipe[P, T] = ...,
|
95
96
|
/,
|
96
97
|
*,
|
97
98
|
cls: _InjectableFactory[T] = ...,
|
@@ -107,7 +108,7 @@ class Module:
|
|
107
108
|
|
108
109
|
def singleton[**P, T](
|
109
110
|
self,
|
110
|
-
wrapped:
|
111
|
+
wrapped: _Recipe[P, T] = ...,
|
111
112
|
/,
|
112
113
|
*,
|
113
114
|
inject: bool = ...,
|
@@ -176,6 +177,12 @@ class Module:
|
|
176
177
|
/,
|
177
178
|
threadsafe: bool = ...,
|
178
179
|
) -> Callable[P, T]: ...
|
180
|
+
def make_async_factory[T](
|
181
|
+
self,
|
182
|
+
wrapped: type[T],
|
183
|
+
/,
|
184
|
+
threadsafe: bool = ...,
|
185
|
+
) -> Callable[..., Awaitable[T]]: ...
|
179
186
|
async def afind_instance[T](self, cls: _InputType[T]) -> T: ...
|
180
187
|
def find_instance[T](self, cls: _InputType[T]) -> T:
|
181
188
|
"""
|
injection/_core/hook.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import itertools
|
2
|
-
from collections import deque
|
3
2
|
from collections.abc import Callable, Generator, Iterator
|
4
3
|
from dataclasses import dataclass, field
|
5
4
|
from inspect import isclass, isgeneratorfunction
|
@@ -14,8 +13,8 @@ type HookFunction[**P, T] = Callable[P, T] | HookGeneratorFunction[P, T]
|
|
14
13
|
|
15
14
|
@dataclass(eq=False, frozen=True, slots=True)
|
16
15
|
class Hook[**P, T]:
|
17
|
-
__functions:
|
18
|
-
default_factory=
|
16
|
+
__functions: list[HookFunction[P, T]] = field(
|
17
|
+
default_factory=list,
|
19
18
|
init=False,
|
20
19
|
repr=False,
|
21
20
|
)
|
@@ -36,7 +35,7 @@ class Hook[**P, T]:
|
|
36
35
|
return iter(self.__functions)
|
37
36
|
|
38
37
|
def add(self, *functions: HookFunction[P, T]) -> Self:
|
39
|
-
self.__functions.
|
38
|
+
self.__functions.extend(reversed(functions))
|
40
39
|
return self
|
41
40
|
|
42
41
|
@classmethod
|
@@ -65,7 +64,6 @@ class Hook[**P, T]:
|
|
65
64
|
hook.throw(exc)
|
66
65
|
else:
|
67
66
|
hook.send(value)
|
68
|
-
return value
|
69
67
|
|
70
68
|
except StopIteration as stop:
|
71
69
|
return stop.value
|
injection/_core/module.py
CHANGED
@@ -3,10 +3,12 @@ from __future__ import annotations
|
|
3
3
|
from abc import ABC, abstractmethod
|
4
4
|
from collections import OrderedDict, deque
|
5
5
|
from collections.abc import (
|
6
|
+
AsyncGenerator,
|
6
7
|
AsyncIterator,
|
7
8
|
Awaitable,
|
8
9
|
Callable,
|
9
10
|
Collection,
|
11
|
+
Generator,
|
10
12
|
Iterable,
|
11
13
|
Iterator,
|
12
14
|
Mapping,
|
@@ -71,6 +73,7 @@ from injection.exceptions import (
|
|
71
73
|
ModuleLockError,
|
72
74
|
ModuleNotUsedError,
|
73
75
|
NoInjectable,
|
76
|
+
SkipInjectable,
|
74
77
|
)
|
75
78
|
|
76
79
|
"""
|
@@ -360,6 +363,14 @@ class Priority(StrEnum):
|
|
360
363
|
|
361
364
|
type PriorityStr = Literal["low", "high"]
|
362
365
|
|
366
|
+
type ContextManagerLikeRecipe[**P, T] = (
|
367
|
+
Callable[P, ContextManager[T]] | Callable[P, AsyncContextManager[T]]
|
368
|
+
)
|
369
|
+
type GeneratorRecipe[**P, T] = (
|
370
|
+
Callable[P, Generator[T, Any, Any]] | Callable[P, AsyncGenerator[T, Any]]
|
371
|
+
)
|
372
|
+
type Recipe[**P, T] = Callable[P, T] | Callable[P, Awaitable[T]]
|
373
|
+
|
363
374
|
|
364
375
|
@dataclass(eq=False, frozen=True, slots=True)
|
365
376
|
class Module(Broker, EventListener):
|
@@ -411,7 +422,7 @@ class Module(Broker, EventListener):
|
|
411
422
|
|
412
423
|
def injectable[**P, T](
|
413
424
|
self,
|
414
|
-
wrapped:
|
425
|
+
wrapped: Recipe[P, T] | None = None,
|
415
426
|
/,
|
416
427
|
*,
|
417
428
|
cls: InjectableFactory[T] = SimpleInjectable,
|
@@ -420,9 +431,7 @@ class Module(Broker, EventListener):
|
|
420
431
|
on: TypeInfo[T] = (),
|
421
432
|
mode: Mode | ModeStr = Mode.get_default(),
|
422
433
|
) -> Any:
|
423
|
-
def decorator(
|
424
|
-
wp: Callable[P, T] | Callable[P, Awaitable[T]],
|
425
|
-
) -> Callable[P, T] | Callable[P, Awaitable[T]]:
|
434
|
+
def decorator(wp: Recipe[P, T]) -> Recipe[P, T]:
|
426
435
|
factory = extract_caller(self.make_injected_function(wp) if inject else wp)
|
427
436
|
hints = on if ignore_type_hint else (wp, on)
|
428
437
|
updater = Updater(
|
@@ -447,23 +456,10 @@ class Module(Broker, EventListener):
|
|
447
456
|
mode: Mode | ModeStr = Mode.get_default(),
|
448
457
|
) -> Any:
|
449
458
|
def decorator(
|
450
|
-
wrapped:
|
451
|
-
|
452
|
-
| Callable[P, Iterator[T]]
|
453
|
-
| Callable[P, AsyncIterator[T]],
|
454
|
-
) -> (
|
455
|
-
Callable[P, T]
|
456
|
-
| Callable[P, Awaitable[T]]
|
457
|
-
| Callable[P, Iterator[T]]
|
458
|
-
| Callable[P, AsyncIterator[T]]
|
459
|
-
):
|
459
|
+
wrapped: Recipe[P, T] | GeneratorRecipe[P, T],
|
460
|
+
) -> Recipe[P, T] | GeneratorRecipe[P, T]:
|
460
461
|
injectable_class: Callable[[Caller[P, Any], str], Injectable[T]]
|
461
|
-
wrapper:
|
462
|
-
Callable[P, T]
|
463
|
-
| Callable[P, Awaitable[T]]
|
464
|
-
| Callable[P, ContextManager[T]]
|
465
|
-
| Callable[P, AsyncContextManager[T]]
|
466
|
-
)
|
462
|
+
wrapper: Recipe[P, T] | ContextManagerLikeRecipe[P, T]
|
467
463
|
|
468
464
|
if isasyncgenfunction(wrapped):
|
469
465
|
hint = get_yield_hint(wrapped)
|
@@ -588,6 +584,18 @@ class Module(Broker, EventListener):
|
|
588
584
|
|
589
585
|
return SyncInjectedFunction(metadata)
|
590
586
|
|
587
|
+
def make_async_factory[T](
|
588
|
+
self,
|
589
|
+
wrapped: type[T],
|
590
|
+
/,
|
591
|
+
threadsafe: bool = False,
|
592
|
+
) -> Callable[..., Awaitable[T]]:
|
593
|
+
factory: InjectedFunction[..., T] = self.make_injected_function(
|
594
|
+
wrapped,
|
595
|
+
threadsafe,
|
596
|
+
)
|
597
|
+
return factory.__inject_metadata__.acall
|
598
|
+
|
591
599
|
async def afind_instance[T](self, cls: InputType[T]) -> T:
|
592
600
|
injectable = self[cls]
|
593
601
|
return await injectable.aget_instance()
|
@@ -613,7 +621,7 @@ class Module(Broker, EventListener):
|
|
613
621
|
async def aget_instance(self, cls, default=None): # type: ignore[no-untyped-def]
|
614
622
|
try:
|
615
623
|
return await self.afind_instance(cls)
|
616
|
-
except KeyError:
|
624
|
+
except (KeyError, SkipInjectable):
|
617
625
|
return default
|
618
626
|
|
619
627
|
@overload
|
@@ -633,7 +641,7 @@ class Module(Broker, EventListener):
|
|
633
641
|
def get_instance(self, cls, default=None): # type: ignore[no-untyped-def]
|
634
642
|
try:
|
635
643
|
return self.find_instance(cls)
|
636
|
-
except KeyError:
|
644
|
+
except (KeyError, SkipInjectable):
|
637
645
|
return default
|
638
646
|
|
639
647
|
@overload
|
@@ -859,29 +867,28 @@ class Dependencies:
|
|
859
867
|
lazy_mapping: Lazy[Mapping[str, Injectable[Any]]]
|
860
868
|
|
861
869
|
def __iter__(self) -> Iterator[tuple[str, Any]]:
|
862
|
-
for name, injectable in self.
|
863
|
-
|
864
|
-
|
870
|
+
for name, injectable in self.items():
|
871
|
+
with suppress(SkipInjectable):
|
872
|
+
yield name, injectable.get_instance()
|
865
873
|
|
866
874
|
async def __aiter__(self) -> AsyncIterator[tuple[str, Any]]:
|
867
|
-
for name, injectable in self.
|
868
|
-
|
869
|
-
|
875
|
+
for name, injectable in self.items():
|
876
|
+
with suppress(SkipInjectable):
|
877
|
+
yield name, await injectable.aget_instance()
|
870
878
|
|
871
879
|
@property
|
872
880
|
def are_resolved(self) -> bool:
|
873
881
|
return self.lazy_mapping.is_set
|
874
882
|
|
875
|
-
@property
|
876
|
-
def mapping(self) -> Mapping[str, Injectable[Any]]:
|
877
|
-
return ~self.lazy_mapping
|
878
|
-
|
879
883
|
async def aget_arguments(self) -> dict[str, Any]:
|
880
884
|
return {key: value async for key, value in self}
|
881
885
|
|
882
886
|
def get_arguments(self) -> dict[str, Any]:
|
883
887
|
return dict(self)
|
884
888
|
|
889
|
+
def items(self) -> Iterator[tuple[str, Injectable[Any]]]:
|
890
|
+
return iter((~self.lazy_mapping).items())
|
891
|
+
|
885
892
|
@classmethod
|
886
893
|
def from_iterable(cls, iterable: Iterable[tuple[str, Injectable[Any]]]) -> Self:
|
887
894
|
lazy_mapping = Lazy(lambda: dict(iterable))
|
injection/exceptions.py
CHANGED
@@ -10,6 +10,7 @@ __all__ = (
|
|
10
10
|
"ScopeAlreadyDefinedError",
|
11
11
|
"ScopeError",
|
12
12
|
"ScopeUndefinedError",
|
13
|
+
"SkipInjectable",
|
13
14
|
)
|
14
15
|
|
15
16
|
|
@@ -30,6 +31,9 @@ class NoInjectable[T](KeyError, InjectionError):
|
|
30
31
|
return self.__class
|
31
32
|
|
32
33
|
|
34
|
+
class SkipInjectable(InjectionError): ...
|
35
|
+
|
36
|
+
|
33
37
|
class ModuleError(InjectionError): ...
|
34
38
|
|
35
39
|
|
@@ -42,7 +46,7 @@ class ModuleNotUsedError(KeyError, ModuleError): ...
|
|
42
46
|
class ScopeError(InjectionError): ...
|
43
47
|
|
44
48
|
|
45
|
-
class ScopeUndefinedError(LookupError, ScopeError): ...
|
49
|
+
class ScopeUndefinedError(LookupError, SkipInjectable, ScopeError): ...
|
46
50
|
|
47
51
|
|
48
52
|
class ScopeAlreadyDefinedError(ScopeError): ...
|
@@ -1,13 +1,13 @@
|
|
1
1
|
injection/__init__.py,sha256=X0vIAoN4MDlhR7YIkup1qHgqbOkwZ3PWgdSi7h-udaM,1049
|
2
|
-
injection/__init__.pyi,sha256=
|
3
|
-
injection/exceptions.py,sha256=
|
2
|
+
injection/__init__.pyi,sha256=6B5GdRNaAJ15Q-QAL8nNpTBVIKEUPJAwWIlCSjOkkJ8,10058
|
3
|
+
injection/exceptions.py,sha256=dp9XYpWHh8R76wbWDJdjmpTHGQp8KuCeveTqarXY_6Y,999
|
4
4
|
injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
injection/utils.py,sha256=Lr0qHaq3_1AkUoAaw2XmMNie_alwYTeTrRlO22FeCnk,2762
|
6
6
|
injection/_core/__init__.py,sha256=XERocCxCZBxPGIaOR37yeiQOZyvjHQ6a4rgRmlkUSuU,1367
|
7
7
|
injection/_core/descriptors.py,sha256=7fSHlgAqmgR_Uta8KocBapOt1Xyj2dI7RY9ZdoStTzw,726
|
8
|
-
injection/_core/hook.py,sha256=
|
8
|
+
injection/_core/hook.py,sha256=rJyaSwFAHM8qizWANPUSt5KzWdjxc5oJ2U8hcGeZjU8,3097
|
9
9
|
injection/_core/injectables.py,sha256=GIumNp0TXf8Voxe1sCPhcqq2gyw4E_hl7I45IJ_tyHE,4512
|
10
|
-
injection/_core/module.py,sha256=
|
10
|
+
injection/_core/module.py,sha256=1eGb4IHVCJByHUnAG83-oPgp8VbZty8x1YZ6OFT0zEU,31232
|
11
11
|
injection/_core/scope.py,sha256=pwOqVKOUM_ZteNScgp-hLqyOHg5Ew75jWlfWLLD2PU8,5437
|
12
12
|
injection/_core/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
injection/_core/common/asynchronous.py,sha256=9bQDVRE6eqo9K0d5H9RzyFalf0WGoGP7cDrKDGbvZPI,1500
|
@@ -20,6 +20,6 @@ injection/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
20
20
|
injection/integrations/fastapi.py,sha256=YHSs85_3m6TUVtOwUcV157b3UZJQIw_aXWAg199a-YE,594
|
21
21
|
injection/testing/__init__.py,sha256=Bh3JqEXw62-JnUnspOXr2jpjGXZJ_K_K9CgfD7dPZeQ,793
|
22
22
|
injection/testing/__init__.pyi,sha256=1h9zNGghxlo4D1jAx5s8EHk54mn7o-qO7WgJa6hwX6U,484
|
23
|
-
python_injection-0.14.
|
24
|
-
python_injection-0.14.
|
25
|
-
python_injection-0.14.
|
23
|
+
python_injection-0.14.2.dist-info/METADATA,sha256=9IhlCQv8o9QERwHq1RZwXB83mmrz4stiLxnoKKhX6sI,3199
|
24
|
+
python_injection-0.14.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
python_injection-0.14.2.dist-info/RECORD,,
|
File without changes
|