python-injection 0.6.8__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.8 → python_injection-0.6.9}/PKG-INFO +1 -1
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/_pkg.py +3 -4
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/_pkg.pyi +21 -4
- python_injection-0.6.9/injection/common/tools/_type.py +48 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/core/module.py +54 -98
- {python_injection-0.6.8 → python_injection-0.6.9}/pyproject.toml +1 -1
- python_injection-0.6.8/injection/common/tools/_type.py +0 -36
- {python_injection-0.6.8 → python_injection-0.6.9}/documentation/basic-usage.md +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/__init__.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/common/__init__.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/common/event.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/common/lazy.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/common/tools/__init__.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/core/__init__.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/exceptions.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/integrations/__init__.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/integrations/blacksheep.py +0 -0
- {python_injection-0.6.8 → python_injection-0.6.9}/injection/utils.py +0 -0
|
@@ -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",
|
|
@@ -16,9 +17,7 @@ default_module = Module(f"{__name__}:default_module")
|
|
|
16
17
|
|
|
17
18
|
get_instance = default_module.get_instance
|
|
18
19
|
get_lazy_instance = default_module.get_lazy_instance
|
|
19
|
-
|
|
20
20
|
inject = default_module.inject
|
|
21
21
|
injectable = default_module.injectable
|
|
22
|
-
singleton = default_module.singleton
|
|
23
|
-
|
|
24
22
|
set_constant = default_module.set_constant
|
|
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,12 +21,10 @@ 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
|
|
18
|
-
singleton = default_module.singleton
|
|
19
|
-
|
|
20
26
|
set_constant = default_module.set_constant
|
|
27
|
+
singleton = default_module.singleton
|
|
21
28
|
|
|
22
29
|
@final
|
|
23
30
|
class Module:
|
|
@@ -42,6 +49,7 @@ class Module:
|
|
|
42
49
|
wrapped: Callable[..., Any] = ...,
|
|
43
50
|
/,
|
|
44
51
|
*,
|
|
52
|
+
cls: type[Injectable] = ...,
|
|
45
53
|
on: type | Iterable[type] | UnionType = ...,
|
|
46
54
|
):
|
|
47
55
|
"""
|
|
@@ -119,3 +127,12 @@ class Module:
|
|
|
119
127
|
class ModulePriorities(Enum):
|
|
120
128
|
HIGH = ...
|
|
121
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,
|
|
@@ -133,6 +132,9 @@ Injectables
|
|
|
133
132
|
class Injectable(Protocol[_T]):
|
|
134
133
|
__slots__ = ()
|
|
135
134
|
|
|
135
|
+
def __init__(self, factory: Callable[[], _T] = ..., *args, **kwargs):
|
|
136
|
+
...
|
|
137
|
+
|
|
136
138
|
@property
|
|
137
139
|
def is_locked(self) -> bool:
|
|
138
140
|
return False
|
|
@@ -288,18 +290,6 @@ class Module(EventListener):
|
|
|
288
290
|
def __str__(self) -> str:
|
|
289
291
|
return self.name or object.__str__(self)
|
|
290
292
|
|
|
291
|
-
@property
|
|
292
|
-
def inject(self) -> InjectDecorator:
|
|
293
|
-
return InjectDecorator(self)
|
|
294
|
-
|
|
295
|
-
@property
|
|
296
|
-
def injectable(self) -> InjectableDecorator:
|
|
297
|
-
return InjectableDecorator(self, NewInjectable)
|
|
298
|
-
|
|
299
|
-
@property
|
|
300
|
-
def singleton(self) -> InjectableDecorator:
|
|
301
|
-
return InjectableDecorator(self, SingletonInjectable)
|
|
302
|
-
|
|
303
293
|
@property
|
|
304
294
|
def is_locked(self) -> bool:
|
|
305
295
|
return any(broker.is_locked for broker in self.__brokers)
|
|
@@ -309,6 +299,25 @@ class Module(EventListener):
|
|
|
309
299
|
yield from tuple(self.__modules)
|
|
310
300
|
yield self.__container
|
|
311
301
|
|
|
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
|
+
|
|
312
321
|
def set_constant(self, instance: _T, on: type | Types = None) -> _T:
|
|
313
322
|
cls = type(instance)
|
|
314
323
|
|
|
@@ -318,6 +327,29 @@ class Module(EventListener):
|
|
|
318
327
|
|
|
319
328
|
return instance
|
|
320
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
|
+
|
|
321
353
|
def get_instance(self, cls: type[_T]) -> _T | None:
|
|
322
354
|
try:
|
|
323
355
|
injectable = self[cls]
|
|
@@ -420,6 +452,12 @@ class Module(EventListener):
|
|
|
420
452
|
f"`{module}` can't be found in the modules used by `{self}`."
|
|
421
453
|
) from exc
|
|
422
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
|
+
|
|
423
461
|
|
|
424
462
|
"""
|
|
425
463
|
Binder
|
|
@@ -502,85 +540,3 @@ class Binder(EventListener):
|
|
|
502
540
|
def _(self, event: ModuleEvent, /) -> ContextManager:
|
|
503
541
|
yield
|
|
504
542
|
self.update(event.on_module)
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
"""
|
|
508
|
-
Decorators
|
|
509
|
-
"""
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
@final
|
|
513
|
-
@dataclass(repr=False, frozen=True, slots=True)
|
|
514
|
-
class InjectDecorator:
|
|
515
|
-
__module: Module
|
|
516
|
-
|
|
517
|
-
def __call__(self, wrapped: Callable[..., Any] = None, /):
|
|
518
|
-
def decorator(wp):
|
|
519
|
-
if isclass(wp):
|
|
520
|
-
return self.__class_decorator(wp)
|
|
521
|
-
|
|
522
|
-
return self.__decorator(wp)
|
|
523
|
-
|
|
524
|
-
return decorator(wrapped) if wrapped else decorator
|
|
525
|
-
|
|
526
|
-
def __decorator(self, function: Callable[..., Any], /) -> Callable[..., Any]:
|
|
527
|
-
lazy_binder = Lazy[Binder](lambda: self.__new_binder(function))
|
|
528
|
-
|
|
529
|
-
@wraps(function)
|
|
530
|
-
def wrapper(*args, **kwargs):
|
|
531
|
-
arguments = (~lazy_binder).bind(*args, **kwargs)
|
|
532
|
-
return function(*arguments.args, **arguments.kwargs)
|
|
533
|
-
|
|
534
|
-
return wrapper
|
|
535
|
-
|
|
536
|
-
def __class_decorator(self, cls: type, /) -> type:
|
|
537
|
-
cls.__init__ = self.__decorator(cls.__init__)
|
|
538
|
-
return cls
|
|
539
|
-
|
|
540
|
-
def __new_binder(self, function: Callable[..., Any]) -> Binder:
|
|
541
|
-
signature = inspect.signature(function, eval_str=True)
|
|
542
|
-
binder = Binder(signature).update(self.__module)
|
|
543
|
-
self.__module.add_listener(binder)
|
|
544
|
-
return binder
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
@final
|
|
548
|
-
@dataclass(repr=False, frozen=True, slots=True)
|
|
549
|
-
class InjectableDecorator:
|
|
550
|
-
__module: Module
|
|
551
|
-
__injectable_type: type[BaseInjectable]
|
|
552
|
-
|
|
553
|
-
def __repr__(self) -> str:
|
|
554
|
-
return f"<{self.__injectable_type.__qualname__} decorator>"
|
|
555
|
-
|
|
556
|
-
def __call__(
|
|
557
|
-
self,
|
|
558
|
-
wrapped: Callable[..., Any] = None,
|
|
559
|
-
/,
|
|
560
|
-
*,
|
|
561
|
-
on: type | Types = None,
|
|
562
|
-
):
|
|
563
|
-
def decorator(wp):
|
|
564
|
-
@self.__module.inject
|
|
565
|
-
@wraps(wp, updated=())
|
|
566
|
-
def factory(*args, **kwargs):
|
|
567
|
-
return wp(*args, **kwargs)
|
|
568
|
-
|
|
569
|
-
injectable = self.__injectable_type(factory)
|
|
570
|
-
classes = self.__get_classes(wp, on)
|
|
571
|
-
self.__module.update(classes, injectable)
|
|
572
|
-
return wp
|
|
573
|
-
|
|
574
|
-
return decorator(wrapped) if wrapped else decorator
|
|
575
|
-
|
|
576
|
-
@classmethod
|
|
577
|
-
def __get_classes(cls, *objects: Any) -> Iterator[type | UnionType]:
|
|
578
|
-
for obj in objects:
|
|
579
|
-
if isinstance(obj, Iterable) and not isinstance(obj, type | str):
|
|
580
|
-
yield from cls.__get_classes(*obj)
|
|
581
|
-
|
|
582
|
-
elif isfunction(obj):
|
|
583
|
-
yield get_annotations(obj, eval_str=True).get("return")
|
|
584
|
-
|
|
585
|
-
else:
|
|
586
|
-
yield obj
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from collections.abc import Iterator
|
|
2
|
-
from types import NoneType, UnionType
|
|
3
|
-
from typing import Annotated, Any, Union, get_args, get_origin
|
|
4
|
-
|
|
5
|
-
__all__ = ("format_type", "get_origins")
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def format_type(cls: type | Any) -> str:
|
|
9
|
-
try:
|
|
10
|
-
return f"{cls.__module__}.{cls.__qualname__}"
|
|
11
|
-
except AttributeError:
|
|
12
|
-
return str(cls)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def get_origins(*classes: type | Any) -> Iterator[type | Any]:
|
|
16
|
-
for cls in classes:
|
|
17
|
-
origin = get_origin(cls) or cls
|
|
18
|
-
|
|
19
|
-
if origin in (None, NoneType):
|
|
20
|
-
continue
|
|
21
|
-
|
|
22
|
-
arguments = get_args(cls)
|
|
23
|
-
|
|
24
|
-
if origin in (Union, UnionType):
|
|
25
|
-
yield from get_origins(*arguments)
|
|
26
|
-
|
|
27
|
-
elif origin is Annotated:
|
|
28
|
-
try:
|
|
29
|
-
annotated = arguments[0]
|
|
30
|
-
except IndexError:
|
|
31
|
-
continue
|
|
32
|
-
|
|
33
|
-
yield from get_origins(annotated)
|
|
34
|
-
|
|
35
|
-
else:
|
|
36
|
-
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
|
|
File without changes
|