python-injection 0.6.7__tar.gz → 0.6.9__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.
Potentially problematic release.
This version of python-injection might be problematic. Click here for more details.
- {python_injection-0.6.7 → python_injection-0.6.9}/PKG-INFO +14 -5
- {python_injection-0.6.7 → python_injection-0.6.9}/documentation/basic-usage.md +13 -4
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/_pkg.py +4 -2
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/_pkg.pyi +33 -4
- python_injection-0.6.9/injection/common/tools/_type.py +48 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/core/module.py +68 -112
- {python_injection-0.6.7 → python_injection-0.6.9}/pyproject.toml +2 -2
- python_injection-0.6.7/injection/common/tools/_type.py +0 -35
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/__init__.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/common/__init__.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/common/event.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/common/lazy.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/common/tools/__init__.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/core/__init__.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/exceptions.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/integrations/__init__.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/integrations/blacksheep.py +0 -0
- {python_injection-0.6.7 → python_injection-0.6.9}/injection/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-injection
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.9
|
|
4
4
|
Summary: Fast and easy dependency injection framework.
|
|
5
5
|
Home-page: https://github.com/100nm/python-injection
|
|
6
6
|
License: MIT
|
|
@@ -19,6 +19,8 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
|
|
20
20
|
## Create an injectable
|
|
21
21
|
|
|
22
|
+
> **Note**: If the class needs dependencies, these will be resolved when the instance is retrieved.
|
|
23
|
+
|
|
22
24
|
If you wish to inject a singleton, use `singleton` decorator.
|
|
23
25
|
|
|
24
26
|
```python
|
|
@@ -39,7 +41,14 @@ class Injectable:
|
|
|
39
41
|
""" class implementation """
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
If you have a constant (such as a global variable) and wish to register it as an injectable, use `set_constant`
|
|
45
|
+
function.
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from injection import set_constant
|
|
49
|
+
|
|
50
|
+
app = set_constant(Application())
|
|
51
|
+
```
|
|
43
52
|
|
|
44
53
|
## Inject an instance
|
|
45
54
|
|
|
@@ -57,6 +66,9 @@ def my_function(instance: Injectable):
|
|
|
57
66
|
If `inject` decorates a class, it will be applied to the `__init__` method.
|
|
58
67
|
_Especially useful for dataclasses:_
|
|
59
68
|
|
|
69
|
+
> **Note**: Doesn't work with Pydantic `BaseModel` because the signature of the `__init__` method doesn't contain the
|
|
70
|
+
> dependencies.
|
|
71
|
+
|
|
60
72
|
```python
|
|
61
73
|
from dataclasses import dataclass
|
|
62
74
|
|
|
@@ -68,9 +80,6 @@ class DataClass:
|
|
|
68
80
|
instance: Injectable = ...
|
|
69
81
|
```
|
|
70
82
|
|
|
71
|
-
> **Note**: Doesn't work with Pydantic `BaseModel` because the signature of the `__init__` method doesn't contain the
|
|
72
|
-
> dependencies.
|
|
73
|
-
|
|
74
83
|
## Get an instance
|
|
75
84
|
|
|
76
85
|
_Example with `get_instance` function:_
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Create an injectable
|
|
4
4
|
|
|
5
|
+
> **Note**: If the class needs dependencies, these will be resolved when the instance is retrieved.
|
|
6
|
+
|
|
5
7
|
If you wish to inject a singleton, use `singleton` decorator.
|
|
6
8
|
|
|
7
9
|
```python
|
|
@@ -22,7 +24,14 @@ class Injectable:
|
|
|
22
24
|
""" class implementation """
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
If you have a constant (such as a global variable) and wish to register it as an injectable, use `set_constant`
|
|
28
|
+
function.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from injection import set_constant
|
|
32
|
+
|
|
33
|
+
app = set_constant(Application())
|
|
34
|
+
```
|
|
26
35
|
|
|
27
36
|
## Inject an instance
|
|
28
37
|
|
|
@@ -40,6 +49,9 @@ def my_function(instance: Injectable):
|
|
|
40
49
|
If `inject` decorates a class, it will be applied to the `__init__` method.
|
|
41
50
|
_Especially useful for dataclasses:_
|
|
42
51
|
|
|
52
|
+
> **Note**: Doesn't work with Pydantic `BaseModel` because the signature of the `__init__` method doesn't contain the
|
|
53
|
+
> dependencies.
|
|
54
|
+
|
|
43
55
|
```python
|
|
44
56
|
from dataclasses import dataclass
|
|
45
57
|
|
|
@@ -51,9 +63,6 @@ class DataClass:
|
|
|
51
63
|
instance: Injectable = ...
|
|
52
64
|
```
|
|
53
65
|
|
|
54
|
-
> **Note**: Doesn't work with Pydantic `BaseModel` because the signature of the `__init__` method doesn't contain the
|
|
55
|
-
> dependencies.
|
|
56
|
-
|
|
57
66
|
## Get an instance
|
|
58
67
|
|
|
59
68
|
_Example with `get_instance` function:_
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from .core import Module, ModulePriorities
|
|
1
|
+
from .core import Injectable, Module, ModulePriorities
|
|
2
2
|
|
|
3
3
|
__all__ = (
|
|
4
|
+
"Injectable",
|
|
4
5
|
"Module",
|
|
5
6
|
"ModulePriorities",
|
|
6
7
|
"default_module",
|
|
@@ -8,6 +9,7 @@ __all__ = (
|
|
|
8
9
|
"get_lazy_instance",
|
|
9
10
|
"inject",
|
|
10
11
|
"injectable",
|
|
12
|
+
"set_constant",
|
|
11
13
|
"singleton",
|
|
12
14
|
)
|
|
13
15
|
|
|
@@ -15,7 +17,7 @@ default_module = Module(f"{__name__}:default_module")
|
|
|
15
17
|
|
|
16
18
|
get_instance = default_module.get_instance
|
|
17
19
|
get_lazy_instance = default_module.get_lazy_instance
|
|
18
|
-
|
|
19
20
|
inject = default_module.inject
|
|
20
21
|
injectable = default_module.injectable
|
|
22
|
+
set_constant = default_module.set_constant
|
|
21
23
|
singleton = default_module.singleton
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
1
2
|
from collections.abc import Callable, Iterable
|
|
2
3
|
from contextlib import ContextDecorator
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from types import UnionType
|
|
5
|
-
from typing import
|
|
6
|
+
from typing import (
|
|
7
|
+
Any,
|
|
8
|
+
ContextManager,
|
|
9
|
+
Final,
|
|
10
|
+
Protocol,
|
|
11
|
+
TypeVar,
|
|
12
|
+
final,
|
|
13
|
+
runtime_checkable,
|
|
14
|
+
)
|
|
6
15
|
|
|
7
16
|
from injection.common.lazy import Lazy
|
|
8
17
|
|
|
@@ -12,9 +21,9 @@ default_module: Final[Module] = ...
|
|
|
12
21
|
|
|
13
22
|
get_instance = default_module.get_instance
|
|
14
23
|
get_lazy_instance = default_module.get_lazy_instance
|
|
15
|
-
|
|
16
24
|
inject = default_module.inject
|
|
17
25
|
injectable = default_module.injectable
|
|
26
|
+
set_constant = default_module.set_constant
|
|
18
27
|
singleton = default_module.singleton
|
|
19
28
|
|
|
20
29
|
@final
|
|
@@ -40,6 +49,7 @@ class Module:
|
|
|
40
49
|
wrapped: Callable[..., Any] = ...,
|
|
41
50
|
/,
|
|
42
51
|
*,
|
|
52
|
+
cls: type[Injectable] = ...,
|
|
43
53
|
on: type | Iterable[type] | UnionType = ...,
|
|
44
54
|
):
|
|
45
55
|
"""
|
|
@@ -59,12 +69,22 @@ class Module:
|
|
|
59
69
|
singleton will be constructed. At injection time, the injected instance will
|
|
60
70
|
always be the same.
|
|
61
71
|
"""
|
|
62
|
-
def
|
|
72
|
+
def set_constant(
|
|
73
|
+
self,
|
|
74
|
+
instance: _T,
|
|
75
|
+
on: type | Iterable[type] | UnionType = ...,
|
|
76
|
+
) -> _T:
|
|
77
|
+
"""
|
|
78
|
+
Function for registering a specific instance to be injected. This is useful for
|
|
79
|
+
registering global variables. The difference with the singleton decorator is
|
|
80
|
+
that no dependencies are resolved, so the module doesn't need to be locked.
|
|
81
|
+
"""
|
|
82
|
+
def get_instance(self, cls: type[_T]) -> _T | None:
|
|
63
83
|
"""
|
|
64
84
|
Function used to retrieve an instance associated with the type passed in
|
|
65
85
|
parameter or return `None`.
|
|
66
86
|
"""
|
|
67
|
-
def get_lazy_instance(self, cls: type[_T]
|
|
87
|
+
def get_lazy_instance(self, cls: type[_T]) -> Lazy[_T | None]:
|
|
68
88
|
"""
|
|
69
89
|
Function used to retrieve an instance associated with the type passed in
|
|
70
90
|
parameter or `None`. Return a `Lazy` object. To access the instance contained
|
|
@@ -107,3 +127,12 @@ class Module:
|
|
|
107
127
|
class ModulePriorities(Enum):
|
|
108
128
|
HIGH = ...
|
|
109
129
|
LOW = ...
|
|
130
|
+
|
|
131
|
+
@runtime_checkable
|
|
132
|
+
class Injectable(Protocol[_T]):
|
|
133
|
+
def __init__(self, factory: Callable[[], _T] = ..., *args, **kwargs): ...
|
|
134
|
+
@property
|
|
135
|
+
def is_locked(self) -> bool: ...
|
|
136
|
+
def unlock(self): ...
|
|
137
|
+
@abstractmethod
|
|
138
|
+
def get_instance(self) -> _T: ...
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from collections.abc import Iterable, Iterator
|
|
2
|
+
from inspect import get_annotations, isfunction
|
|
3
|
+
from types import NoneType, UnionType
|
|
4
|
+
from typing import Annotated, Any, Union, get_args, get_origin
|
|
5
|
+
|
|
6
|
+
__all__ = ("find_types", "format_type", "get_origins")
|
|
7
|
+
|
|
8
|
+
|
|
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
|
+
|
|
15
|
+
|
|
16
|
+
def get_origins(*types: type | Any) -> Iterator[type | Any]:
|
|
17
|
+
for tp in types:
|
|
18
|
+
origin = get_origin(tp) or tp
|
|
19
|
+
|
|
20
|
+
if origin in (None, NoneType):
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
elif origin in (Union, UnionType):
|
|
24
|
+
args = get_args(tp)
|
|
25
|
+
|
|
26
|
+
elif origin is Annotated is not tp:
|
|
27
|
+
args = (tp.__origin__,)
|
|
28
|
+
|
|
29
|
+
else:
|
|
30
|
+
yield origin
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
yield from get_origins(*args)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def find_types(*args: Any) -> Iterator[type | UnionType]:
|
|
37
|
+
for argument in args:
|
|
38
|
+
if isinstance(argument, Iterable) and not isinstance(argument, type | str):
|
|
39
|
+
arguments = argument
|
|
40
|
+
|
|
41
|
+
elif isfunction(argument):
|
|
42
|
+
arguments = (get_annotations(argument, eval_str=True).get("return"),)
|
|
43
|
+
|
|
44
|
+
else:
|
|
45
|
+
yield argument
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
yield from find_types(*arguments)
|
|
@@ -15,8 +15,8 @@ from collections.abc import (
|
|
|
15
15
|
from contextlib import ContextDecorator, contextmanager, suppress
|
|
16
16
|
from dataclasses import dataclass, field
|
|
17
17
|
from enum import Enum, auto
|
|
18
|
-
from functools import singledispatchmethod, wraps
|
|
19
|
-
from inspect import Signature,
|
|
18
|
+
from functools import partialmethod, singledispatchmethod, wraps
|
|
19
|
+
from inspect import Signature, isclass
|
|
20
20
|
from threading import RLock
|
|
21
21
|
from types import MappingProxyType, UnionType
|
|
22
22
|
from typing import (
|
|
@@ -26,13 +26,12 @@ from typing import (
|
|
|
26
26
|
Protocol,
|
|
27
27
|
TypeVar,
|
|
28
28
|
cast,
|
|
29
|
-
final,
|
|
30
29
|
runtime_checkable,
|
|
31
30
|
)
|
|
32
31
|
|
|
33
32
|
from injection.common.event import Event, EventChannel, EventListener
|
|
34
33
|
from injection.common.lazy import Lazy, LazyMapping
|
|
35
|
-
from injection.common.tools import format_type, get_origins
|
|
34
|
+
from injection.common.tools import find_types, format_type, get_origins
|
|
36
35
|
from injection.exceptions import (
|
|
37
36
|
ModuleError,
|
|
38
37
|
ModuleLockError,
|
|
@@ -46,6 +45,7 @@ _logger = logging.getLogger(__name__)
|
|
|
46
45
|
_thread_lock = RLock()
|
|
47
46
|
|
|
48
47
|
_T = TypeVar("_T")
|
|
48
|
+
Types = Iterable[type] | UnionType
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
"""
|
|
@@ -132,6 +132,9 @@ Injectables
|
|
|
132
132
|
class Injectable(Protocol[_T]):
|
|
133
133
|
__slots__ = ()
|
|
134
134
|
|
|
135
|
+
def __init__(self, factory: Callable[[], _T] = ..., *args, **kwargs):
|
|
136
|
+
...
|
|
137
|
+
|
|
135
138
|
@property
|
|
136
139
|
def is_locked(self) -> bool:
|
|
137
140
|
return False
|
|
@@ -211,7 +214,7 @@ class Container:
|
|
|
211
214
|
def __injectables(self) -> frozenset[Injectable]:
|
|
212
215
|
return frozenset(self.__data.values())
|
|
213
216
|
|
|
214
|
-
def update(self, classes:
|
|
217
|
+
def update(self, classes: Types, injectable: Injectable):
|
|
215
218
|
classes = frozenset(get_origins(*classes))
|
|
216
219
|
|
|
217
220
|
if classes:
|
|
@@ -287,18 +290,6 @@ class Module(EventListener):
|
|
|
287
290
|
def __str__(self) -> str:
|
|
288
291
|
return self.name or object.__str__(self)
|
|
289
292
|
|
|
290
|
-
@property
|
|
291
|
-
def inject(self) -> InjectDecorator:
|
|
292
|
-
return InjectDecorator(self)
|
|
293
|
-
|
|
294
|
-
@property
|
|
295
|
-
def injectable(self) -> InjectableDecorator:
|
|
296
|
-
return InjectableDecorator(self, NewInjectable)
|
|
297
|
-
|
|
298
|
-
@property
|
|
299
|
-
def singleton(self) -> InjectableDecorator:
|
|
300
|
-
return InjectableDecorator(self, SingletonInjectable)
|
|
301
|
-
|
|
302
293
|
@property
|
|
303
294
|
def is_locked(self) -> bool:
|
|
304
295
|
return any(broker.is_locked for broker in self.__brokers)
|
|
@@ -308,7 +299,58 @@ class Module(EventListener):
|
|
|
308
299
|
yield from tuple(self.__modules)
|
|
309
300
|
yield self.__container
|
|
310
301
|
|
|
311
|
-
def
|
|
302
|
+
def injectable(
|
|
303
|
+
self,
|
|
304
|
+
wrapped: Callable[..., Any] = None,
|
|
305
|
+
/,
|
|
306
|
+
*,
|
|
307
|
+
cls: type[Injectable] = NewInjectable,
|
|
308
|
+
on: type | Types = None,
|
|
309
|
+
):
|
|
310
|
+
def decorator(wp):
|
|
311
|
+
factory = self.inject(wp, return_factory=True)
|
|
312
|
+
injectable = cls(factory)
|
|
313
|
+
classes = find_types(wp, on)
|
|
314
|
+
self.update(classes, injectable)
|
|
315
|
+
return wp
|
|
316
|
+
|
|
317
|
+
return decorator(wrapped) if wrapped else decorator
|
|
318
|
+
|
|
319
|
+
singleton = partialmethod(injectable, cls=SingletonInjectable)
|
|
320
|
+
|
|
321
|
+
def set_constant(self, instance: _T, on: type | Types = None) -> _T:
|
|
322
|
+
cls = type(instance)
|
|
323
|
+
|
|
324
|
+
@self.injectable(on=(cls, on))
|
|
325
|
+
def get_constant():
|
|
326
|
+
return instance
|
|
327
|
+
|
|
328
|
+
return instance
|
|
329
|
+
|
|
330
|
+
def inject(
|
|
331
|
+
self,
|
|
332
|
+
wrapped: Callable[..., Any] = None,
|
|
333
|
+
/,
|
|
334
|
+
*,
|
|
335
|
+
return_factory: bool = False,
|
|
336
|
+
):
|
|
337
|
+
def decorator(wp):
|
|
338
|
+
if not return_factory and isclass(wp):
|
|
339
|
+
wp.__init__ = decorator(wp.__init__)
|
|
340
|
+
return wp
|
|
341
|
+
|
|
342
|
+
lazy_binder = Lazy[Binder](lambda: self.__new_binder(wp))
|
|
343
|
+
|
|
344
|
+
@wraps(wp)
|
|
345
|
+
def wrapper(*args, **kwargs):
|
|
346
|
+
arguments = (~lazy_binder).bind(*args, **kwargs)
|
|
347
|
+
return wp(*arguments.args, **arguments.kwargs)
|
|
348
|
+
|
|
349
|
+
return wrapper
|
|
350
|
+
|
|
351
|
+
return decorator(wrapped) if wrapped else decorator
|
|
352
|
+
|
|
353
|
+
def get_instance(self, cls: type[_T]) -> _T | None:
|
|
312
354
|
try:
|
|
313
355
|
injectable = self[cls]
|
|
314
356
|
except KeyError:
|
|
@@ -317,10 +359,10 @@ class Module(EventListener):
|
|
|
317
359
|
instance = injectable.get_instance()
|
|
318
360
|
return cast(cls, instance)
|
|
319
361
|
|
|
320
|
-
def get_lazy_instance(self, cls: type[_T]
|
|
362
|
+
def get_lazy_instance(self, cls: type[_T]) -> Lazy[_T | None]:
|
|
321
363
|
return Lazy(lambda: self.get_instance(cls))
|
|
322
364
|
|
|
323
|
-
def update(self, classes:
|
|
365
|
+
def update(self, classes: Types, injectable: Injectable):
|
|
324
366
|
self.__container.update(classes, injectable)
|
|
325
367
|
return self
|
|
326
368
|
|
|
@@ -410,6 +452,12 @@ class Module(EventListener):
|
|
|
410
452
|
f"`{module}` can't be found in the modules used by `{self}`."
|
|
411
453
|
) from exc
|
|
412
454
|
|
|
455
|
+
def __new_binder(self, target: Callable[..., Any]) -> Binder:
|
|
456
|
+
signature = inspect.signature(target, eval_str=True)
|
|
457
|
+
binder = Binder(signature).update(self)
|
|
458
|
+
self.add_listener(binder)
|
|
459
|
+
return binder
|
|
460
|
+
|
|
413
461
|
|
|
414
462
|
"""
|
|
415
463
|
Binder
|
|
@@ -492,95 +540,3 @@ class Binder(EventListener):
|
|
|
492
540
|
def _(self, event: ModuleEvent, /) -> ContextManager:
|
|
493
541
|
yield
|
|
494
542
|
self.update(event.on_module)
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
"""
|
|
498
|
-
Decorators
|
|
499
|
-
"""
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
@final
|
|
503
|
-
@dataclass(repr=False, frozen=True, slots=True)
|
|
504
|
-
class InjectDecorator:
|
|
505
|
-
__module: Module
|
|
506
|
-
|
|
507
|
-
def __call__(self, wrapped: Callable[..., Any] = None, /):
|
|
508
|
-
def decorator(wp):
|
|
509
|
-
if isclass(wp):
|
|
510
|
-
return self.__class_decorator(wp)
|
|
511
|
-
|
|
512
|
-
return self.__decorator(wp)
|
|
513
|
-
|
|
514
|
-
return decorator(wrapped) if wrapped else decorator
|
|
515
|
-
|
|
516
|
-
def __decorator(self, function: Callable[..., Any], /) -> Callable[..., Any]:
|
|
517
|
-
lazy_binder = Lazy[Binder](lambda: self.__new_binder(function))
|
|
518
|
-
|
|
519
|
-
@wraps(function)
|
|
520
|
-
def wrapper(*args, **kwargs):
|
|
521
|
-
arguments = (~lazy_binder).bind(*args, **kwargs)
|
|
522
|
-
return function(*arguments.args, **arguments.kwargs)
|
|
523
|
-
|
|
524
|
-
return wrapper
|
|
525
|
-
|
|
526
|
-
def __class_decorator(self, cls: type, /) -> type:
|
|
527
|
-
cls.__init__ = self.__decorator(cls.__init__)
|
|
528
|
-
return cls
|
|
529
|
-
|
|
530
|
-
def __new_binder(self, function: Callable[..., Any]) -> Binder:
|
|
531
|
-
signature = inspect.signature(function, eval_str=True)
|
|
532
|
-
binder = Binder(signature).update(self.__module)
|
|
533
|
-
self.__module.add_listener(binder)
|
|
534
|
-
return binder
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
@final
|
|
538
|
-
@dataclass(repr=False, frozen=True, slots=True)
|
|
539
|
-
class InjectableDecorator:
|
|
540
|
-
__module: Module
|
|
541
|
-
__injectable_type: type[BaseInjectable]
|
|
542
|
-
|
|
543
|
-
def __repr__(self) -> str:
|
|
544
|
-
return f"<{self.__injectable_type.__qualname__} decorator>"
|
|
545
|
-
|
|
546
|
-
def __call__(
|
|
547
|
-
self,
|
|
548
|
-
wrapped: Callable[..., Any] = None,
|
|
549
|
-
/,
|
|
550
|
-
*,
|
|
551
|
-
on: type | Iterable[type] | UnionType = None,
|
|
552
|
-
):
|
|
553
|
-
def decorator(wp):
|
|
554
|
-
@lambda fn: fn()
|
|
555
|
-
def classes():
|
|
556
|
-
if cls := self.__get_class(wp):
|
|
557
|
-
yield cls
|
|
558
|
-
|
|
559
|
-
if on is None:
|
|
560
|
-
return
|
|
561
|
-
elif isinstance(on, type | str):
|
|
562
|
-
yield on
|
|
563
|
-
else:
|
|
564
|
-
yield from on
|
|
565
|
-
|
|
566
|
-
@self.__module.inject
|
|
567
|
-
@wraps(wp, updated=())
|
|
568
|
-
def factory(*args, **kwargs):
|
|
569
|
-
return wp(*args, **kwargs)
|
|
570
|
-
|
|
571
|
-
injectable = self.__injectable_type(factory)
|
|
572
|
-
self.__module.update(classes, injectable)
|
|
573
|
-
|
|
574
|
-
return wp
|
|
575
|
-
|
|
576
|
-
return decorator(wrapped) if wrapped else decorator
|
|
577
|
-
|
|
578
|
-
@staticmethod
|
|
579
|
-
def __get_class(wrapped: Callable[..., Any]) -> type | None:
|
|
580
|
-
if isclass(wrapped):
|
|
581
|
-
return wrapped
|
|
582
|
-
|
|
583
|
-
if isfunction(wrapped):
|
|
584
|
-
return get_annotations(wrapped, eval_str=True).get("return")
|
|
585
|
-
|
|
586
|
-
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-injection"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.9"
|
|
4
4
|
description = "Fast and easy dependency injection framework."
|
|
5
5
|
authors = ["remimd"]
|
|
6
6
|
keywords = ["dependencies", "inject", "injection"]
|
|
@@ -14,7 +14,7 @@ python = ">=3.10, <4"
|
|
|
14
14
|
|
|
15
15
|
[tool.poetry.group.dev.dependencies]
|
|
16
16
|
black = "*"
|
|
17
|
-
blacksheep = "^2.0.
|
|
17
|
+
blacksheep = "^2.0.5"
|
|
18
18
|
flake8 = "*"
|
|
19
19
|
isort = "*"
|
|
20
20
|
pydantic = "^2.5.3"
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
from types import NoneType, UnionType
|
|
2
|
-
from typing import Any, Iterator, Union, get_args
|
|
3
|
-
|
|
4
|
-
__all__ = ("format_type", "get_origins")
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def format_type(cls: type | Any) -> str:
|
|
8
|
-
try:
|
|
9
|
-
return f"{cls.__module__}.{cls.__qualname__}"
|
|
10
|
-
except AttributeError:
|
|
11
|
-
return str(cls)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def get_full_origin(cls: type | Any) -> type | Any:
|
|
15
|
-
try:
|
|
16
|
-
origin = cls.__origin__
|
|
17
|
-
except AttributeError:
|
|
18
|
-
return cls
|
|
19
|
-
|
|
20
|
-
return get_full_origin(origin)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def get_origins(*classes: type | Any) -> Iterator[type | Any]:
|
|
24
|
-
for cls in classes:
|
|
25
|
-
if cls in (None, NoneType):
|
|
26
|
-
continue
|
|
27
|
-
|
|
28
|
-
origin = get_full_origin(cls)
|
|
29
|
-
|
|
30
|
-
if origin is Union or isinstance(cls, UnionType):
|
|
31
|
-
for argument in get_args(cls):
|
|
32
|
-
yield from get_origins(argument)
|
|
33
|
-
|
|
34
|
-
else:
|
|
35
|
-
yield origin
|
|
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
|