python-injection 0.7.4__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.4 → python_injection-0.8.0}/PKG-INFO +1 -1
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/_pkg.pyi +1 -9
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/common/event.py +3 -1
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/common/lazy.py +25 -25
- python_injection-0.8.0/injection/common/queue.py +68 -0
- python_injection-0.8.0/injection/common/tools/threading.py +28 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/core/module.py +147 -47
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/exceptions.py +1 -1
- python_injection-0.8.0/injection/integrations/__init__.py +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/pyproject.toml +1 -1
- python_injection-0.7.4/injection/common/tools/__init__.py +0 -1
- {python_injection-0.7.4 → python_injection-0.8.0}/documentation/basic-usage.md +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/__init__.py +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/_pkg.py +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/common/__init__.py +0 -0
- {python_injection-0.7.4/injection/integrations → python_injection-0.8.0/injection/common/tools}/__init__.py +0 -0
- /python_injection-0.7.4/injection/common/tools/_type.py → /python_injection-0.8.0/injection/common/tools/type.py +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/core/__init__.py +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/integrations/blacksheep.py +0 -0
- {python_injection-0.7.4 → python_injection-0.8.0}/injection/utils.py +0 -0
|
@@ -39,19 +39,11 @@ class Module:
|
|
|
39
39
|
|
|
40
40
|
def __init__(self, name: str = ...): ...
|
|
41
41
|
def __contains__(self, cls: type | UnionType, /) -> bool: ...
|
|
42
|
-
def inject(
|
|
43
|
-
self,
|
|
44
|
-
wrapped: Callable[..., Any] = ...,
|
|
45
|
-
/,
|
|
46
|
-
*,
|
|
47
|
-
force: bool = ...,
|
|
48
|
-
):
|
|
42
|
+
def inject(self, wrapped: Callable[..., Any] = ..., /):
|
|
49
43
|
"""
|
|
50
44
|
Decorator applicable to a class or function. Inject function dependencies using
|
|
51
45
|
parameter type annotations. If applied to a class, the dependencies resolved
|
|
52
46
|
will be those of the `__init__` method.
|
|
53
|
-
|
|
54
|
-
With `force=True`, parameters passed to replace dependencies will be ignored.
|
|
55
47
|
"""
|
|
56
48
|
|
|
57
49
|
def injectable(
|
|
@@ -4,6 +4,8 @@ from dataclasses import dataclass, field
|
|
|
4
4
|
from typing import ContextManager
|
|
5
5
|
from weakref import WeakSet
|
|
6
6
|
|
|
7
|
+
from injection.common.tools.threading import frozen_collection
|
|
8
|
+
|
|
7
9
|
__all__ = ("Event", "EventChannel", "EventListener")
|
|
8
10
|
|
|
9
11
|
|
|
@@ -26,7 +28,7 @@ class EventChannel:
|
|
|
26
28
|
@contextmanager
|
|
27
29
|
def dispatch(self, event: Event) -> ContextManager | ContextDecorator:
|
|
28
30
|
with ExitStack() as stack:
|
|
29
|
-
for listener in
|
|
31
|
+
for listener in frozen_collection(self.__listeners):
|
|
30
32
|
context_manager = listener.on_event(event)
|
|
31
33
|
|
|
32
34
|
if context_manager is None:
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
from collections.abc import Callable, Iterator, Mapping
|
|
2
|
-
from threading import RLock
|
|
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
|
|
|
8
|
-
|
|
9
|
-
_thread_lock = RLock()
|
|
7
|
+
__all__ = ("Lazy", "LazyMapping")
|
|
10
8
|
|
|
11
9
|
_T = TypeVar("_T")
|
|
12
10
|
_K = TypeVar("_K")
|
|
@@ -14,39 +12,37 @@ _V = TypeVar("_V")
|
|
|
14
12
|
|
|
15
13
|
|
|
16
14
|
class Lazy(Generic[_T]):
|
|
17
|
-
__slots__ = ("
|
|
15
|
+
__slots__ = ("__cache", "__is_set")
|
|
18
16
|
|
|
19
17
|
def __init__(self, factory: Callable[[], _T]):
|
|
20
|
-
self.
|
|
21
|
-
self.__value = _sentinel
|
|
18
|
+
self.__setup_cache(factory)
|
|
22
19
|
|
|
23
20
|
def __invert__(self) -> _T:
|
|
24
|
-
|
|
25
|
-
with _thread_lock:
|
|
26
|
-
self.__value = self.__factory()
|
|
27
|
-
self.__factory = _sentinel
|
|
21
|
+
return next(self.__cache)
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
@property
|
|
24
|
+
def is_set(self) -> bool:
|
|
25
|
+
return self.__is_set
|
|
30
26
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
def __setup_cache(self, factory: Callable[[], _T]):
|
|
28
|
+
def new_cache() -> Iterator[_T]:
|
|
29
|
+
with thread_lock:
|
|
30
|
+
self.__is_set = True
|
|
34
31
|
|
|
35
|
-
|
|
32
|
+
nonlocal factory
|
|
33
|
+
cached = factory()
|
|
34
|
+
del factory
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return False
|
|
36
|
+
while True:
|
|
37
|
+
yield cached
|
|
38
|
+
|
|
39
|
+
self.__cache = new_cache()
|
|
40
|
+
self.__is_set = False
|
|
43
41
|
|
|
44
42
|
|
|
45
43
|
class LazyMapping(Mapping[_K, _V]):
|
|
46
44
|
__slots__ = ("__lazy",)
|
|
47
45
|
|
|
48
|
-
__lazy: Lazy[MappingProxyType[_K, _V]]
|
|
49
|
-
|
|
50
46
|
def __init__(self, iterator: Iterator[tuple[_K, _V]]):
|
|
51
47
|
self.__lazy = Lazy(lambda: MappingProxyType(dict(iterator)))
|
|
52
48
|
|
|
@@ -58,3 +54,7 @@ class LazyMapping(Mapping[_K, _V]):
|
|
|
58
54
|
|
|
59
55
|
def __len__(self) -> int:
|
|
60
56
|
return len(~self.__lazy)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def is_set(self) -> bool:
|
|
60
|
+
return self.__lazy.is_set
|
|
@@ -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
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from collections.abc import Callable, Collection, Iterator
|
|
2
|
+
from functools import wraps
|
|
3
|
+
from threading import RLock
|
|
4
|
+
from typing import Any, TypeVar
|
|
5
|
+
|
|
6
|
+
__all__ = ("frozen_collection", "synchronized", "thread_lock")
|
|
7
|
+
|
|
8
|
+
_T = TypeVar("_T")
|
|
9
|
+
thread_lock = RLock()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def synchronized(function: Callable[..., Any] = None, /):
|
|
13
|
+
def decorator(fn):
|
|
14
|
+
@wraps(fn)
|
|
15
|
+
def wrapper(*args, **kwargs):
|
|
16
|
+
with thread_lock:
|
|
17
|
+
return fn(*args, **kwargs)
|
|
18
|
+
|
|
19
|
+
return wrapper
|
|
20
|
+
|
|
21
|
+
return decorator(function) if function else decorator
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def frozen_collection(collection: Collection[_T]) -> Iterator[_T]:
|
|
25
|
+
with thread_lock:
|
|
26
|
+
t = tuple(collection)
|
|
27
|
+
|
|
28
|
+
yield from t
|
|
@@ -16,12 +16,17 @@ from collections.abc import (
|
|
|
16
16
|
from contextlib import ContextDecorator, contextmanager, suppress
|
|
17
17
|
from dataclasses import dataclass, field
|
|
18
18
|
from enum import Enum, auto
|
|
19
|
-
from functools import
|
|
19
|
+
from functools import (
|
|
20
|
+
partialmethod,
|
|
21
|
+
singledispatchmethod,
|
|
22
|
+
update_wrapper,
|
|
23
|
+
wraps,
|
|
24
|
+
)
|
|
20
25
|
from inspect import Signature, isclass
|
|
21
|
-
from
|
|
22
|
-
from types import MappingProxyType, UnionType
|
|
26
|
+
from types import UnionType
|
|
23
27
|
from typing import (
|
|
24
28
|
Any,
|
|
29
|
+
ClassVar,
|
|
25
30
|
ContextManager,
|
|
26
31
|
NamedTuple,
|
|
27
32
|
NoReturn,
|
|
@@ -33,7 +38,13 @@ from typing import (
|
|
|
33
38
|
|
|
34
39
|
from injection.common.event import Event, EventChannel, EventListener
|
|
35
40
|
from injection.common.lazy import Lazy, LazyMapping
|
|
36
|
-
from injection.common.
|
|
41
|
+
from injection.common.queue import LimitedQueue
|
|
42
|
+
from injection.common.tools.threading import (
|
|
43
|
+
frozen_collection,
|
|
44
|
+
synchronized,
|
|
45
|
+
thread_lock,
|
|
46
|
+
)
|
|
47
|
+
from injection.common.tools.type import find_types, format_type, get_origins
|
|
37
48
|
from injection.exceptions import (
|
|
38
49
|
InjectionError,
|
|
39
50
|
ModuleError,
|
|
@@ -45,7 +56,6 @@ from injection.exceptions import (
|
|
|
45
56
|
__all__ = ("Injectable", "Module", "ModulePriority")
|
|
46
57
|
|
|
47
58
|
_logger = logging.getLogger(__name__)
|
|
48
|
-
_thread_lock = RLock()
|
|
49
59
|
|
|
50
60
|
_T = TypeVar("_T")
|
|
51
61
|
Types = Iterable[type] | UnionType
|
|
@@ -166,7 +176,7 @@ class NewInjectable(BaseInjectable[_T]):
|
|
|
166
176
|
class SingletonInjectable(BaseInjectable[_T]):
|
|
167
177
|
__slots__ = ("__dict__",)
|
|
168
178
|
|
|
169
|
-
__INSTANCE_KEY = "$instance"
|
|
179
|
+
__INSTANCE_KEY: ClassVar[str] = "$instance"
|
|
170
180
|
|
|
171
181
|
@property
|
|
172
182
|
def cache(self) -> MutableMapping[str, Any]:
|
|
@@ -183,7 +193,7 @@ class SingletonInjectable(BaseInjectable[_T]):
|
|
|
183
193
|
with suppress(KeyError):
|
|
184
194
|
return self.cache[self.__INSTANCE_KEY]
|
|
185
195
|
|
|
186
|
-
with
|
|
196
|
+
with thread_lock:
|
|
187
197
|
instance = self.factory()
|
|
188
198
|
self.cache[self.__INSTANCE_KEY] = instance
|
|
189
199
|
|
|
@@ -263,7 +273,7 @@ class Container(Broker):
|
|
|
263
273
|
def update(self, classes: Iterable[type], injectable: Injectable, override: bool):
|
|
264
274
|
classes = frozenset(get_origins(*classes))
|
|
265
275
|
|
|
266
|
-
with
|
|
276
|
+
with thread_lock:
|
|
267
277
|
if not injectable:
|
|
268
278
|
classes -= self.__classes
|
|
269
279
|
override = True
|
|
@@ -279,6 +289,7 @@ class Container(Broker):
|
|
|
279
289
|
|
|
280
290
|
return self
|
|
281
291
|
|
|
292
|
+
@synchronized
|
|
282
293
|
def unlock(self):
|
|
283
294
|
for injectable in self.__injectables:
|
|
284
295
|
injectable.unlock()
|
|
@@ -349,7 +360,7 @@ class Module(EventListener, Broker):
|
|
|
349
360
|
|
|
350
361
|
@property
|
|
351
362
|
def __brokers(self) -> Iterator[Broker]:
|
|
352
|
-
yield from
|
|
363
|
+
yield from frozen_collection(self.__modules)
|
|
353
364
|
yield self.__container
|
|
354
365
|
|
|
355
366
|
def injectable(
|
|
@@ -401,22 +412,21 @@ class Module(EventListener, Broker):
|
|
|
401
412
|
wrapped: Callable[..., Any] = None,
|
|
402
413
|
/,
|
|
403
414
|
*,
|
|
404
|
-
force: bool = False,
|
|
405
415
|
return_factory: bool = False,
|
|
406
416
|
):
|
|
407
417
|
def decorator(wp):
|
|
408
418
|
if not return_factory and isclass(wp):
|
|
409
|
-
wp.__init__ = self.inject(wp.__init__
|
|
419
|
+
wp.__init__ = self.inject(wp.__init__)
|
|
410
420
|
return wp
|
|
411
421
|
|
|
412
|
-
|
|
422
|
+
function = InjectedFunction(wp)
|
|
413
423
|
|
|
414
|
-
@
|
|
415
|
-
def
|
|
416
|
-
|
|
417
|
-
|
|
424
|
+
@function.setup
|
|
425
|
+
def listen():
|
|
426
|
+
function.update(self)
|
|
427
|
+
self.add_listener(function)
|
|
418
428
|
|
|
419
|
-
return
|
|
429
|
+
return function
|
|
420
430
|
|
|
421
431
|
return decorator(wrapped) if wrapped else decorator
|
|
422
432
|
|
|
@@ -492,6 +502,7 @@ class Module(EventListener, Broker):
|
|
|
492
502
|
|
|
493
503
|
return self
|
|
494
504
|
|
|
505
|
+
@synchronized
|
|
495
506
|
def unlock(self):
|
|
496
507
|
for broker in self.__brokers:
|
|
497
508
|
broker.unlock()
|
|
@@ -530,44 +541,45 @@ class Module(EventListener, Broker):
|
|
|
530
541
|
f"`{module}` can't be found in the modules used by `{self}`."
|
|
531
542
|
) from exc
|
|
532
543
|
|
|
533
|
-
def __new_binder(self, target: Callable[..., Any]) -> Binder:
|
|
534
|
-
signature = inspect.signature(target, eval_str=True)
|
|
535
|
-
binder = Binder(signature).update(self)
|
|
536
|
-
self.add_listener(binder)
|
|
537
|
-
return binder
|
|
538
|
-
|
|
539
544
|
|
|
540
545
|
"""
|
|
541
|
-
|
|
546
|
+
InjectedFunction
|
|
542
547
|
"""
|
|
543
548
|
|
|
544
549
|
|
|
545
550
|
@dataclass(repr=False, frozen=True, slots=True)
|
|
546
551
|
class Dependencies:
|
|
547
|
-
|
|
552
|
+
mapping: Mapping[str, Injectable]
|
|
548
553
|
|
|
549
554
|
def __bool__(self) -> bool:
|
|
550
|
-
return bool(self.
|
|
555
|
+
return bool(self.mapping)
|
|
551
556
|
|
|
552
557
|
def __iter__(self) -> Iterator[tuple[str, Any]]:
|
|
553
|
-
for name, injectable in self.
|
|
558
|
+
for name, injectable in self.mapping.items():
|
|
554
559
|
yield name, injectable.get_instance()
|
|
555
560
|
|
|
561
|
+
@property
|
|
562
|
+
def are_resolved(self) -> bool:
|
|
563
|
+
if isinstance(self.mapping, LazyMapping) and not self.mapping.is_set:
|
|
564
|
+
return False
|
|
565
|
+
|
|
566
|
+
return bool(self)
|
|
567
|
+
|
|
556
568
|
@property
|
|
557
569
|
def arguments(self) -> OrderedDict[str, Any]:
|
|
558
570
|
return OrderedDict(self)
|
|
559
571
|
|
|
560
572
|
@classmethod
|
|
561
573
|
def from_mapping(cls, mapping: Mapping[str, Injectable]):
|
|
562
|
-
return cls(
|
|
574
|
+
return cls(mapping=mapping)
|
|
563
575
|
|
|
564
576
|
@classmethod
|
|
565
577
|
def empty(cls):
|
|
566
578
|
return cls.from_mapping({})
|
|
567
579
|
|
|
568
580
|
@classmethod
|
|
569
|
-
def resolve(cls, signature: Signature, module: Module):
|
|
570
|
-
dependencies = LazyMapping(cls.__resolver(signature, module))
|
|
581
|
+
def resolve(cls, signature: Signature, module: Module, owner: type = None):
|
|
582
|
+
dependencies = LazyMapping(cls.__resolver(signature, module, owner))
|
|
571
583
|
return cls.from_mapping(dependencies)
|
|
572
584
|
|
|
573
585
|
@classmethod
|
|
@@ -575,33 +587,102 @@ class Dependencies:
|
|
|
575
587
|
cls,
|
|
576
588
|
signature: Signature,
|
|
577
589
|
module: Module,
|
|
590
|
+
owner: type = None,
|
|
578
591
|
) -> Iterator[tuple[str, Injectable]]:
|
|
579
|
-
for name,
|
|
592
|
+
for name, annotation in cls.__get_annotations(signature, owner):
|
|
580
593
|
try:
|
|
581
|
-
injectable = module[
|
|
594
|
+
injectable = module[annotation]
|
|
582
595
|
except KeyError:
|
|
583
596
|
continue
|
|
584
597
|
|
|
585
598
|
yield name, injectable
|
|
586
599
|
|
|
600
|
+
@staticmethod
|
|
601
|
+
def __get_annotations(
|
|
602
|
+
signature: Signature,
|
|
603
|
+
owner: type = None,
|
|
604
|
+
) -> Iterator[tuple[str, type | Any]]:
|
|
605
|
+
parameters = iter(signature.parameters.items())
|
|
606
|
+
|
|
607
|
+
if owner:
|
|
608
|
+
name, _ = next(parameters)
|
|
609
|
+
yield name, owner
|
|
610
|
+
|
|
611
|
+
for name, parameter in parameters:
|
|
612
|
+
yield name, parameter.annotation
|
|
613
|
+
|
|
587
614
|
|
|
588
615
|
class Arguments(NamedTuple):
|
|
589
616
|
args: Iterable[Any]
|
|
590
617
|
kwargs: Mapping[str, Any]
|
|
591
618
|
|
|
592
619
|
|
|
593
|
-
class
|
|
594
|
-
__slots__ = (
|
|
620
|
+
class InjectedFunction(EventListener):
|
|
621
|
+
__slots__ = (
|
|
622
|
+
"__dict__",
|
|
623
|
+
"__signature__",
|
|
624
|
+
"__dependencies",
|
|
625
|
+
"__owner",
|
|
626
|
+
"__setup_queue",
|
|
627
|
+
"__wrapper",
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
def __init__(self, wrapped: Callable[..., Any], /):
|
|
631
|
+
update_wrapper(self, wrapped)
|
|
632
|
+
|
|
633
|
+
@wraps(wrapped)
|
|
634
|
+
def wrapper(*args, **kwargs):
|
|
635
|
+
self.__consume_setup_queue()
|
|
636
|
+
args, kwargs = self.bind(args, kwargs)
|
|
637
|
+
return wrapped(*args, **kwargs)
|
|
595
638
|
|
|
596
|
-
|
|
597
|
-
self.__signature = signature
|
|
639
|
+
self.__wrapper = wrapper
|
|
598
640
|
self.__dependencies = Dependencies.empty()
|
|
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
|
+
)
|
|
651
|
+
|
|
652
|
+
def __repr__(self) -> str:
|
|
653
|
+
return repr(self.__wrapper)
|
|
654
|
+
|
|
655
|
+
def __str__(self) -> str:
|
|
656
|
+
return str(self.__wrapper)
|
|
657
|
+
|
|
658
|
+
def __call__(self, /, *args, **kwargs) -> Any:
|
|
659
|
+
return self.__wrapper(*args, **kwargs)
|
|
660
|
+
|
|
661
|
+
def __get__(self, instance: object = None, owner: type = None):
|
|
662
|
+
if instance is None:
|
|
663
|
+
return self
|
|
664
|
+
|
|
665
|
+
return self.__wrapper.__get__(instance, owner)
|
|
666
|
+
|
|
667
|
+
def __set_name__(self, owner: type, name: str):
|
|
668
|
+
if self.__dependencies.are_resolved:
|
|
669
|
+
raise TypeError(
|
|
670
|
+
"Function owner must be assigned before dependencies are resolved."
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
if self.__owner:
|
|
674
|
+
raise TypeError("Function owner is already defined.")
|
|
675
|
+
|
|
676
|
+
self.__owner = owner
|
|
677
|
+
|
|
678
|
+
@property
|
|
679
|
+
def signature(self) -> Signature:
|
|
680
|
+
return self.__signature__
|
|
599
681
|
|
|
600
682
|
def bind(
|
|
601
683
|
self,
|
|
602
684
|
args: Iterable[Any] = (),
|
|
603
685
|
kwargs: Mapping[str, Any] = None,
|
|
604
|
-
force: bool = False,
|
|
605
686
|
) -> Arguments:
|
|
606
687
|
if kwargs is None:
|
|
607
688
|
kwargs = {}
|
|
@@ -609,22 +690,29 @@ class Binder(EventListener):
|
|
|
609
690
|
if not self.__dependencies:
|
|
610
691
|
return Arguments(args, kwargs)
|
|
611
692
|
|
|
612
|
-
bound = self.
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
bound.arguments |= dependencies
|
|
617
|
-
else:
|
|
618
|
-
bound.arguments = dependencies | bound.arguments
|
|
619
|
-
|
|
693
|
+
bound = self.signature.bind_partial(*args, **kwargs)
|
|
694
|
+
bound.arguments = (
|
|
695
|
+
bound.arguments | self.__dependencies.arguments | bound.arguments
|
|
696
|
+
)
|
|
620
697
|
return Arguments(bound.args, bound.kwargs)
|
|
621
698
|
|
|
622
699
|
def update(self, module: Module):
|
|
623
|
-
with
|
|
624
|
-
self.__dependencies = Dependencies.resolve(
|
|
700
|
+
with thread_lock:
|
|
701
|
+
self.__dependencies = Dependencies.resolve(
|
|
702
|
+
self.signature,
|
|
703
|
+
module,
|
|
704
|
+
self.__owner,
|
|
705
|
+
)
|
|
625
706
|
|
|
626
707
|
return self
|
|
627
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
|
+
|
|
628
716
|
@singledispatchmethod
|
|
629
717
|
def on_event(self, event: Event, /):
|
|
630
718
|
pass
|
|
@@ -634,3 +722,15 @@ class Binder(EventListener):
|
|
|
634
722
|
def _(self, event: ModuleEvent, /) -> ContextManager:
|
|
635
723
|
yield
|
|
636
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from ._type import *
|
|
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
|