python-injection 0.7.5__tar.gz → 0.8.0__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.7.5 → python_injection-0.8.0}/PKG-INFO +1 -1
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/common/lazy.py +19 -23
- python_injection-0.8.0/injection/common/queue.py +68 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/core/module.py +52 -13
- {python_injection-0.7.5 → python_injection-0.8.0}/pyproject.toml +1 -1
- {python_injection-0.7.5 → python_injection-0.8.0}/documentation/basic-usage.md +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/__init__.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/_pkg.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/_pkg.pyi +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/common/__init__.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/common/event.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/common/tools/__init__.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/common/tools/threading.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/common/tools/type.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/core/__init__.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/exceptions.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/integrations/__init__.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/integrations/blacksheep.py +0 -0
- {python_injection-0.7.5 → python_injection-0.8.0}/injection/utils.py +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from collections.abc import Callable, Iterator, Mapping
|
|
2
|
-
from contextlib import suppress
|
|
3
2
|
from types import MappingProxyType
|
|
4
|
-
from typing import
|
|
3
|
+
from typing import Generic, TypeVar
|
|
5
4
|
|
|
6
5
|
from injection.common.tools.threading import thread_lock
|
|
7
6
|
|
|
@@ -13,35 +12,32 @@ _V = TypeVar("_V")
|
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class Lazy(Generic[_T]):
|
|
16
|
-
__slots__ = ("
|
|
15
|
+
__slots__ = ("__cache", "__is_set")
|
|
17
16
|
|
|
18
17
|
def __init__(self, factory: Callable[[], _T]):
|
|
19
|
-
|
|
20
|
-
nonlocal factory
|
|
21
|
-
|
|
22
|
-
with thread_lock:
|
|
23
|
-
value = factory()
|
|
24
|
-
self.is_set = True
|
|
25
|
-
del factory
|
|
18
|
+
self.__setup_cache(factory)
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
def __invert__(self) -> _T:
|
|
21
|
+
return next(self.__cache)
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
@property
|
|
24
|
+
def is_set(self) -> bool:
|
|
25
|
+
return self.__is_set
|
|
32
26
|
|
|
33
|
-
def
|
|
34
|
-
|
|
27
|
+
def __setup_cache(self, factory: Callable[[], _T]):
|
|
28
|
+
def new_cache() -> Iterator[_T]:
|
|
29
|
+
with thread_lock:
|
|
30
|
+
self.__is_set = True
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
nonlocal factory
|
|
33
|
+
cached = factory()
|
|
34
|
+
del factory
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if self.is_set:
|
|
42
|
-
raise TypeError(f"`{self}` is frozen.")
|
|
36
|
+
while True:
|
|
37
|
+
yield cached
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
self.__cache = new_cache()
|
|
40
|
+
self.__is_set = False
|
|
45
41
|
|
|
46
42
|
|
|
47
43
|
class LazyMapping(Mapping[_K, _V]):
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from collections import deque
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import NoReturn, Protocol, TypeVar
|
|
6
|
+
|
|
7
|
+
from injection.common.tools.threading import thread_lock
|
|
8
|
+
|
|
9
|
+
__all__ = ("LimitedQueue",)
|
|
10
|
+
|
|
11
|
+
_T = TypeVar("_T")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Queue(Iterator[_T], Protocol):
|
|
15
|
+
__slots__ = ()
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def add(self, item: _T):
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(repr=False, frozen=True, slots=True)
|
|
23
|
+
class SimpleQueue(Queue[_T]):
|
|
24
|
+
__items: deque[_T] = field(default_factory=deque, init=False)
|
|
25
|
+
|
|
26
|
+
def __next__(self) -> _T:
|
|
27
|
+
try:
|
|
28
|
+
return self.__items.popleft()
|
|
29
|
+
except IndexError as exc:
|
|
30
|
+
raise StopIteration from exc
|
|
31
|
+
|
|
32
|
+
def add(self, item: _T):
|
|
33
|
+
self.__items.append(item)
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class NoQueue(Queue[_T]):
|
|
38
|
+
__slots__ = ()
|
|
39
|
+
|
|
40
|
+
def __bool__(self) -> bool:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
def __next__(self) -> NoReturn:
|
|
44
|
+
raise StopIteration
|
|
45
|
+
|
|
46
|
+
def add(self, item: _T) -> NoReturn:
|
|
47
|
+
raise TypeError("Queue doesn't exist.")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(repr=False, slots=True)
|
|
51
|
+
class LimitedQueue(Queue[_T]):
|
|
52
|
+
__queue: Queue[_T] = field(default_factory=SimpleQueue)
|
|
53
|
+
|
|
54
|
+
def __next__(self) -> _T:
|
|
55
|
+
if not self.__queue:
|
|
56
|
+
raise StopIteration
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
return next(self.__queue)
|
|
60
|
+
except StopIteration as exc:
|
|
61
|
+
with thread_lock:
|
|
62
|
+
self.__queue = NoQueue()
|
|
63
|
+
|
|
64
|
+
raise exc
|
|
65
|
+
|
|
66
|
+
def add(self, item: _T):
|
|
67
|
+
self.__queue.add(item)
|
|
68
|
+
return self
|
|
@@ -38,6 +38,7 @@ from typing import (
|
|
|
38
38
|
|
|
39
39
|
from injection.common.event import Event, EventChannel, EventListener
|
|
40
40
|
from injection.common.lazy import Lazy, LazyMapping
|
|
41
|
+
from injection.common.queue import LimitedQueue
|
|
41
42
|
from injection.common.tools.threading import (
|
|
42
43
|
frozen_collection,
|
|
43
44
|
synchronized,
|
|
@@ -418,9 +419,14 @@ class Module(EventListener, Broker):
|
|
|
418
419
|
wp.__init__ = self.inject(wp.__init__)
|
|
419
420
|
return wp
|
|
420
421
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
function = InjectedFunction(wp)
|
|
423
|
+
|
|
424
|
+
@function.setup
|
|
425
|
+
def listen():
|
|
426
|
+
function.update(self)
|
|
427
|
+
self.add_listener(function)
|
|
428
|
+
|
|
429
|
+
return function
|
|
424
430
|
|
|
425
431
|
return decorator(wrapped) if wrapped else decorator
|
|
426
432
|
|
|
@@ -612,22 +618,36 @@ class Arguments(NamedTuple):
|
|
|
612
618
|
|
|
613
619
|
|
|
614
620
|
class InjectedFunction(EventListener):
|
|
615
|
-
__slots__ = (
|
|
621
|
+
__slots__ = (
|
|
622
|
+
"__dict__",
|
|
623
|
+
"__signature__",
|
|
624
|
+
"__dependencies",
|
|
625
|
+
"__owner",
|
|
626
|
+
"__setup_queue",
|
|
627
|
+
"__wrapper",
|
|
628
|
+
)
|
|
616
629
|
|
|
617
630
|
def __init__(self, wrapped: Callable[..., Any], /):
|
|
618
631
|
update_wrapper(self, wrapped)
|
|
619
|
-
self.__signature__ = Lazy[Signature](
|
|
620
|
-
lambda: inspect.signature(wrapped, eval_str=True)
|
|
621
|
-
)
|
|
622
632
|
|
|
623
633
|
@wraps(wrapped)
|
|
624
634
|
def wrapper(*args, **kwargs):
|
|
635
|
+
self.__consume_setup_queue()
|
|
625
636
|
args, kwargs = self.bind(args, kwargs)
|
|
626
637
|
return wrapped(*args, **kwargs)
|
|
627
638
|
|
|
628
639
|
self.__wrapper = wrapper
|
|
629
640
|
self.__dependencies = Dependencies.empty()
|
|
630
641
|
self.__owner = None
|
|
642
|
+
self.__setup_queue = LimitedQueue[Callable[[], Any]]()
|
|
643
|
+
self.setup(
|
|
644
|
+
lambda: self.__set_signature(
|
|
645
|
+
inspect.signature(
|
|
646
|
+
wrapped,
|
|
647
|
+
eval_str=True,
|
|
648
|
+
)
|
|
649
|
+
)
|
|
650
|
+
)
|
|
631
651
|
|
|
632
652
|
def __repr__(self) -> str:
|
|
633
653
|
return repr(self.__wrapper)
|
|
@@ -638,7 +658,7 @@ class InjectedFunction(EventListener):
|
|
|
638
658
|
def __call__(self, /, *args, **kwargs) -> Any:
|
|
639
659
|
return self.__wrapper(*args, **kwargs)
|
|
640
660
|
|
|
641
|
-
def __get__(self, instance: object
|
|
661
|
+
def __get__(self, instance: object = None, owner: type = None):
|
|
642
662
|
if instance is None:
|
|
643
663
|
return self
|
|
644
664
|
|
|
@@ -647,7 +667,7 @@ class InjectedFunction(EventListener):
|
|
|
647
667
|
def __set_name__(self, owner: type, name: str):
|
|
648
668
|
if self.__dependencies.are_resolved:
|
|
649
669
|
raise TypeError(
|
|
650
|
-
"
|
|
670
|
+
"Function owner must be assigned before dependencies are resolved."
|
|
651
671
|
)
|
|
652
672
|
|
|
653
673
|
if self.__owner:
|
|
@@ -657,7 +677,7 @@ class InjectedFunction(EventListener):
|
|
|
657
677
|
|
|
658
678
|
@property
|
|
659
679
|
def signature(self) -> Signature:
|
|
660
|
-
return self.__signature__
|
|
680
|
+
return self.__signature__
|
|
661
681
|
|
|
662
682
|
def bind(
|
|
663
683
|
self,
|
|
@@ -671,9 +691,9 @@ class InjectedFunction(EventListener):
|
|
|
671
691
|
return Arguments(args, kwargs)
|
|
672
692
|
|
|
673
693
|
bound = self.signature.bind_partial(*args, **kwargs)
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
694
|
+
bound.arguments = (
|
|
695
|
+
bound.arguments | self.__dependencies.arguments | bound.arguments
|
|
696
|
+
)
|
|
677
697
|
return Arguments(bound.args, bound.kwargs)
|
|
678
698
|
|
|
679
699
|
def update(self, module: Module):
|
|
@@ -686,6 +706,13 @@ class InjectedFunction(EventListener):
|
|
|
686
706
|
|
|
687
707
|
return self
|
|
688
708
|
|
|
709
|
+
def setup(self, wrapped: Callable[[], Any] = None, /):
|
|
710
|
+
def decorator(wp):
|
|
711
|
+
self.__setup_queue.add(wp)
|
|
712
|
+
return wp
|
|
713
|
+
|
|
714
|
+
return decorator(wrapped) if wrapped else decorator
|
|
715
|
+
|
|
689
716
|
@singledispatchmethod
|
|
690
717
|
def on_event(self, event: Event, /):
|
|
691
718
|
pass
|
|
@@ -695,3 +722,15 @@ class InjectedFunction(EventListener):
|
|
|
695
722
|
def _(self, event: ModuleEvent, /) -> ContextManager:
|
|
696
723
|
yield
|
|
697
724
|
self.update(event.on_module)
|
|
725
|
+
|
|
726
|
+
def __consume_setup_queue(self):
|
|
727
|
+
for function in self.__setup_queue:
|
|
728
|
+
function()
|
|
729
|
+
|
|
730
|
+
return self
|
|
731
|
+
|
|
732
|
+
def __set_signature(self, signature: Signature):
|
|
733
|
+
with thread_lock:
|
|
734
|
+
self.__signature__ = signature
|
|
735
|
+
|
|
736
|
+
return self
|
|
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
|
|
File without changes
|