python-injection 0.26.2__py3-none-any.whl → 0.26.3__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/_core/common/asynchronous.py +4 -9
- injection/_core/common/event.py +3 -3
- injection/_core/common/lazy.py +1 -1
- injection/_core/common/threading.py +4 -4
- injection/_core/descriptors.py +2 -2
- injection/_core/injectables.py +4 -6
- injection/_core/locator.py +2 -3
- injection/_core/module.py +30 -31
- injection/_core/scope.py +23 -16
- injection/entrypoint.py +10 -10
- {python_injection-0.26.2.dist-info → python_injection-0.26.3.dist-info}/METADATA +6 -1
- {python_injection-0.26.2.dist-info → python_injection-0.26.3.dist-info}/RECORD +14 -14
- {python_injection-0.26.2.dist-info → python_injection-0.26.3.dist-info}/WHEEL +1 -1
- {python_injection-0.26.2.dist-info → python_injection-0.26.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from collections.abc import Awaitable, Callable, Generator
|
|
3
|
+
from contextlib import AbstractAsyncContextManager
|
|
3
4
|
from dataclasses import dataclass
|
|
4
|
-
from typing import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
NoReturn,
|
|
8
|
-
Protocol,
|
|
9
|
-
runtime_checkable,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
AsyncSemaphore: Callable[[int], AsyncContextManager[Any]]
|
|
5
|
+
from typing import Any, NoReturn, Protocol, runtime_checkable
|
|
6
|
+
|
|
7
|
+
AsyncSemaphore: Callable[[int], AbstractAsyncContextManager[Any]]
|
|
13
8
|
|
|
14
9
|
try:
|
|
15
10
|
import anyio
|
injection/_core/common/event.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections.abc import Iterator
|
|
3
|
-
from contextlib import ExitStack, contextmanager
|
|
3
|
+
from contextlib import AbstractContextManager, ExitStack, contextmanager
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Self
|
|
6
6
|
from weakref import WeakSet
|
|
7
7
|
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ class EventListener(ABC):
|
|
|
14
14
|
__slots__ = ("__weakref__",)
|
|
15
15
|
|
|
16
16
|
@abstractmethod
|
|
17
|
-
def on_event(self, event: Event, /) ->
|
|
17
|
+
def on_event(self, event: Event, /) -> AbstractContextManager[None] | None:
|
|
18
18
|
raise NotImplementedError
|
|
19
19
|
|
|
20
20
|
|
injection/_core/common/lazy.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
from contextlib import nullcontext
|
|
1
|
+
from contextlib import AbstractContextManager, nullcontext
|
|
2
2
|
from os import getenv
|
|
3
3
|
from threading import RLock
|
|
4
|
-
from typing import Any,
|
|
4
|
+
from typing import Any, Final
|
|
5
5
|
|
|
6
6
|
_PYTHON_INJECTION_THREADSAFE: Final[bool] = bool(
|
|
7
|
-
int(getenv("PYTHON_INJECTION_THREADSAFE", 0))
|
|
7
|
+
int(getenv("PYTHON_INJECTION_THREADSAFE", "0"))
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def get_lock(threadsafe: bool | None = None) ->
|
|
11
|
+
def get_lock(threadsafe: bool | None = None) -> AbstractContextManager[Any]:
|
|
12
12
|
threadsafe = _PYTHON_INJECTION_THREADSAFE if threadsafe is None else threadsafe
|
|
13
13
|
return RLock() if threadsafe else nullcontext()
|
injection/_core/descriptors.py
CHANGED
|
@@ -73,7 +73,7 @@ class BoundMappedScope:
|
|
|
73
73
|
async def adefine(
|
|
74
74
|
self,
|
|
75
75
|
/,
|
|
76
|
-
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(),
|
|
76
|
+
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(), # noqa: B008
|
|
77
77
|
threadsafe: bool | None = None,
|
|
78
78
|
) -> AsyncIterator[None]:
|
|
79
79
|
async with adefine_scope(self.name, kind, threadsafe) as scope:
|
|
@@ -86,7 +86,7 @@ class BoundMappedScope:
|
|
|
86
86
|
def define(
|
|
87
87
|
self,
|
|
88
88
|
/,
|
|
89
|
-
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(),
|
|
89
|
+
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(), # noqa: B008
|
|
90
90
|
threadsafe: bool | None = None,
|
|
91
91
|
) -> Iterator[None]:
|
|
92
92
|
with define_scope(self.name, kind, threadsafe) as scope:
|
injection/_core/injectables.py
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections.abc import Awaitable, Callable, MutableMapping, Sequence
|
|
3
|
-
from contextlib import suppress
|
|
3
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager, suppress
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import partial
|
|
6
6
|
from typing import (
|
|
7
7
|
Any,
|
|
8
|
-
AsyncContextManager,
|
|
9
8
|
ClassVar,
|
|
10
|
-
ContextManager,
|
|
11
9
|
NoReturn,
|
|
12
10
|
Protocol,
|
|
13
11
|
Self,
|
|
@@ -55,7 +53,7 @@ class TransientInjectable[T](Injectable[T]):
|
|
|
55
53
|
class CacheLogic[T]:
|
|
56
54
|
__slots__ = ("__semaphore",)
|
|
57
55
|
|
|
58
|
-
__semaphore:
|
|
56
|
+
__semaphore: AbstractAsyncContextManager[Any]
|
|
59
57
|
|
|
60
58
|
def __init__(self) -> None:
|
|
61
59
|
self.__semaphore = AsyncSemaphore(1)
|
|
@@ -169,7 +167,7 @@ class ScopedInjectable[R, T](Injectable[T], ABC):
|
|
|
169
167
|
return partial(cls, scope_names=names)
|
|
170
168
|
|
|
171
169
|
|
|
172
|
-
class AsyncCMScopedInjectable[T](ScopedInjectable[
|
|
170
|
+
class AsyncCMScopedInjectable[T](ScopedInjectable[AbstractAsyncContextManager[T], T]):
|
|
173
171
|
__slots__ = ()
|
|
174
172
|
|
|
175
173
|
async def abuild(self, scope: Scope) -> T:
|
|
@@ -180,7 +178,7 @@ class AsyncCMScopedInjectable[T](ScopedInjectable[AsyncContextManager[T], T]):
|
|
|
180
178
|
raise RuntimeError("Can't use async context manager synchronously.")
|
|
181
179
|
|
|
182
180
|
|
|
183
|
-
class CMScopedInjectable[T](ScopedInjectable[
|
|
181
|
+
class CMScopedInjectable[T](ScopedInjectable[AbstractContextManager[T], T]):
|
|
184
182
|
__slots__ = ()
|
|
185
183
|
|
|
186
184
|
async def abuild(self, scope: Scope) -> T:
|
injection/_core/locator.py
CHANGED
|
@@ -2,13 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from collections.abc import Awaitable, Callable, Collection, Iterable, Iterator
|
|
5
|
-
from contextlib import suppress
|
|
5
|
+
from contextlib import AbstractContextManager, suppress
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from enum import StrEnum
|
|
8
8
|
from inspect import iscoroutinefunction
|
|
9
9
|
from typing import (
|
|
10
10
|
Any,
|
|
11
|
-
ContextManager,
|
|
12
11
|
Literal,
|
|
13
12
|
NamedTuple,
|
|
14
13
|
Protocol,
|
|
@@ -226,7 +225,7 @@ class Locator:
|
|
|
226
225
|
self.__channel.add_listener(listener)
|
|
227
226
|
return self
|
|
228
227
|
|
|
229
|
-
def dispatch(self, event: Event) ->
|
|
228
|
+
def dispatch(self, event: Event) -> AbstractContextManager[None]:
|
|
230
229
|
return self.__channel.dispatch(event)
|
|
231
230
|
|
|
232
231
|
def __iter_injectables(
|
injection/_core/module.py
CHANGED
|
@@ -14,7 +14,13 @@ from collections.abc import (
|
|
|
14
14
|
Iterator,
|
|
15
15
|
Mapping,
|
|
16
16
|
)
|
|
17
|
-
from contextlib import
|
|
17
|
+
from contextlib import (
|
|
18
|
+
AbstractAsyncContextManager,
|
|
19
|
+
AbstractContextManager,
|
|
20
|
+
asynccontextmanager,
|
|
21
|
+
contextmanager,
|
|
22
|
+
suppress,
|
|
23
|
+
)
|
|
18
24
|
from dataclasses import dataclass, field
|
|
19
25
|
from enum import StrEnum
|
|
20
26
|
from functools import partialmethod, singledispatchmethod, update_wrapper
|
|
@@ -30,17 +36,7 @@ from inspect import (
|
|
|
30
36
|
from inspect import signature as inspect_signature
|
|
31
37
|
from logging import Logger, getLogger
|
|
32
38
|
from types import MethodType
|
|
33
|
-
from typing import
|
|
34
|
-
TYPE_CHECKING,
|
|
35
|
-
Any,
|
|
36
|
-
AsyncContextManager,
|
|
37
|
-
ClassVar,
|
|
38
|
-
ContextManager,
|
|
39
|
-
Literal,
|
|
40
|
-
NamedTuple,
|
|
41
|
-
Self,
|
|
42
|
-
overload,
|
|
43
|
-
)
|
|
39
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Literal, NamedTuple, Self, overload
|
|
44
40
|
|
|
45
41
|
from type_analyzer import MatchingTypesConfig, iter_matching_types, matching_types
|
|
46
42
|
|
|
@@ -157,7 +153,7 @@ class Priority(StrEnum):
|
|
|
157
153
|
type PriorityStr = Literal["low", "high"]
|
|
158
154
|
|
|
159
155
|
type ContextManagerRecipe[**P, T] = (
|
|
160
|
-
Callable[P,
|
|
156
|
+
Callable[P, AbstractContextManager[T]] | Callable[P, AbstractAsyncContextManager[T]]
|
|
161
157
|
)
|
|
162
158
|
type GeneratorRecipe[**P, T] = (
|
|
163
159
|
Callable[P, Generator[T, Any, Any]] | Callable[P, AsyncGenerator[T, Any]]
|
|
@@ -231,7 +227,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
231
227
|
ignore_type_hint: bool = False,
|
|
232
228
|
inject: bool = True,
|
|
233
229
|
on: TypeInfo[T] = (),
|
|
234
|
-
mode: Mode | ModeStr = Mode.get_default(),
|
|
230
|
+
mode: Mode | ModeStr = Mode.get_default(), # noqa: B008
|
|
235
231
|
) -> Any:
|
|
236
232
|
def decorator(wp: Recipe[P, T]) -> Recipe[P, T]:
|
|
237
233
|
hints = on if ignore_type_hint else (wp, on)
|
|
@@ -255,7 +251,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
255
251
|
ignore_type_hint: bool = False,
|
|
256
252
|
inject: bool = True,
|
|
257
253
|
on: TypeInfo[T] = (),
|
|
258
|
-
mode: Mode | ModeStr = Mode.get_default(),
|
|
254
|
+
mode: Mode | ModeStr = Mode.get_default(), # noqa: B008
|
|
259
255
|
) -> Any:
|
|
260
256
|
def decorator(
|
|
261
257
|
wrapped: Recipe[P, T] | GeneratorRecipe[P, T],
|
|
@@ -307,7 +303,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
307
303
|
on: TypeInfo[T] = (),
|
|
308
304
|
*,
|
|
309
305
|
alias: bool = False,
|
|
310
|
-
mode: Mode | ModeStr = Mode.get_default(),
|
|
306
|
+
mode: Mode | ModeStr = Mode.get_default(), # noqa: B008
|
|
311
307
|
) -> T:
|
|
312
308
|
if not alias:
|
|
313
309
|
on = (type(instance), on)
|
|
@@ -325,7 +321,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
325
321
|
/,
|
|
326
322
|
scope_name: str,
|
|
327
323
|
*,
|
|
328
|
-
mode: Mode | ModeStr = Mode.get_default(),
|
|
324
|
+
mode: Mode | ModeStr = Mode.get_default(), # noqa: B008
|
|
329
325
|
) -> SlotKey[T]:
|
|
330
326
|
injectable = ScopedSlotInjectable(cls, scope_name)
|
|
331
327
|
broker = StaticInjectableBroker(injectable)
|
|
@@ -341,8 +337,8 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
341
337
|
) -> Any:
|
|
342
338
|
def decorator(wp: Callable[P, T]) -> Callable[P, T]:
|
|
343
339
|
if isclass(wp):
|
|
344
|
-
wp.__init__ = self.inject(wp.__init__, threadsafe=threadsafe)
|
|
345
|
-
return wp
|
|
340
|
+
wp.__init__ = self.inject(wp.__init__, threadsafe=threadsafe) # type: ignore[method-assign]
|
|
341
|
+
return wp # type: ignore[return-value]
|
|
346
342
|
|
|
347
343
|
return self.make_injected_function(wp, threadsafe)
|
|
348
344
|
|
|
@@ -583,7 +579,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
583
579
|
self,
|
|
584
580
|
module: Module,
|
|
585
581
|
*,
|
|
586
|
-
priority: Priority | PriorityStr = Priority.get_default(),
|
|
582
|
+
priority: Priority | PriorityStr = Priority.get_default(), # noqa: B008
|
|
587
583
|
) -> Self:
|
|
588
584
|
if module is self:
|
|
589
585
|
raise ModuleError("Module can't be used by itself.")
|
|
@@ -604,10 +600,9 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
604
600
|
def stop_using(self, module: Module) -> Self:
|
|
605
601
|
event = ModuleRemoved(self, module)
|
|
606
602
|
|
|
607
|
-
with suppress(KeyError):
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
module.remove_listener(self)
|
|
603
|
+
with suppress(KeyError), self.dispatch(event):
|
|
604
|
+
self.__modules.pop(module)
|
|
605
|
+
module.remove_listener(self)
|
|
611
606
|
|
|
612
607
|
return self
|
|
613
608
|
|
|
@@ -616,7 +611,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
616
611
|
self,
|
|
617
612
|
module: Module,
|
|
618
613
|
*,
|
|
619
|
-
priority: Priority | PriorityStr = Priority.get_default(),
|
|
614
|
+
priority: Priority | PriorityStr = Priority.get_default(), # noqa: B008
|
|
620
615
|
unlock: bool = False,
|
|
621
616
|
) -> Iterator[Self]:
|
|
622
617
|
self.use(module, priority=priority)
|
|
@@ -660,7 +655,7 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
660
655
|
self.__channel.remove_listener(listener)
|
|
661
656
|
return self
|
|
662
657
|
|
|
663
|
-
def on_event(self, event: Event, /) ->
|
|
658
|
+
def on_event(self, event: Event, /) -> AbstractContextManager[None]:
|
|
664
659
|
self_event = ModuleEventProxy(self, event)
|
|
665
660
|
return self.dispatch(self_event)
|
|
666
661
|
|
|
@@ -829,7 +824,7 @@ class InjectMetadata[**P, T](Caller[P, T], EventListener):
|
|
|
829
824
|
)
|
|
830
825
|
|
|
831
826
|
__dependencies: Dependencies
|
|
832
|
-
__lock:
|
|
827
|
+
__lock: AbstractContextManager[Any]
|
|
833
828
|
__owner: type | None
|
|
834
829
|
__signature: Signature
|
|
835
830
|
__tasks: deque[Callable[..., Any]]
|
|
@@ -904,8 +899,12 @@ class InjectMetadata[**P, T](Caller[P, T], EventListener):
|
|
|
904
899
|
self.__dependencies = Dependencies.resolve(self.signature, module, self.__owner)
|
|
905
900
|
return self
|
|
906
901
|
|
|
907
|
-
def task[**
|
|
908
|
-
|
|
902
|
+
def task[**TaskP, TaskR](
|
|
903
|
+
self,
|
|
904
|
+
wrapped: Callable[TaskP, TaskR] | None = None,
|
|
905
|
+
/,
|
|
906
|
+
) -> Any:
|
|
907
|
+
def decorator(wp: Callable[TaskP, TaskR]) -> Callable[TaskP, TaskR]:
|
|
909
908
|
self.__tasks.append(wp)
|
|
910
909
|
return wp
|
|
911
910
|
|
|
@@ -920,7 +919,7 @@ class InjectMetadata[**P, T](Caller[P, T], EventListener):
|
|
|
920
919
|
return self
|
|
921
920
|
|
|
922
921
|
@singledispatchmethod
|
|
923
|
-
def on_event(self, event: Event, /) ->
|
|
922
|
+
def on_event(self, event: Event, /) -> AbstractContextManager[None] | None:
|
|
924
923
|
return None
|
|
925
924
|
|
|
926
925
|
@on_event.register
|
|
@@ -941,7 +940,7 @@ class InjectMetadata[**P, T](Caller[P, T], EventListener):
|
|
|
941
940
|
arguments: dict[str, Any],
|
|
942
941
|
additional_arguments: dict[str, Any],
|
|
943
942
|
) -> Arguments:
|
|
944
|
-
bound = BoundArguments(self.signature, additional_arguments | arguments)
|
|
943
|
+
bound = BoundArguments(self.signature, additional_arguments | arguments)
|
|
945
944
|
return Arguments(bound.args, bound.kwargs)
|
|
946
945
|
|
|
947
946
|
def __run_tasks(self) -> None:
|
injection/_core/scope.py
CHANGED
|
@@ -4,7 +4,14 @@ import itertools
|
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from collections import defaultdict
|
|
6
6
|
from collections.abc import AsyncIterator, Collection, Iterator, Mapping, MutableMapping
|
|
7
|
-
from contextlib import
|
|
7
|
+
from contextlib import (
|
|
8
|
+
AbstractAsyncContextManager,
|
|
9
|
+
AbstractContextManager,
|
|
10
|
+
AsyncExitStack,
|
|
11
|
+
ExitStack,
|
|
12
|
+
asynccontextmanager,
|
|
13
|
+
contextmanager,
|
|
14
|
+
)
|
|
8
15
|
from contextvars import ContextVar
|
|
9
16
|
from dataclasses import dataclass, field
|
|
10
17
|
from enum import StrEnum
|
|
@@ -13,8 +20,6 @@ from types import EllipsisType, TracebackType
|
|
|
13
20
|
from typing import (
|
|
14
21
|
TYPE_CHECKING,
|
|
15
22
|
Any,
|
|
16
|
-
AsyncContextManager,
|
|
17
|
-
ContextManager,
|
|
18
23
|
Final,
|
|
19
24
|
Literal,
|
|
20
25
|
NoReturn,
|
|
@@ -56,7 +61,7 @@ class ScopeResolver(Protocol):
|
|
|
56
61
|
raise NotImplementedError
|
|
57
62
|
|
|
58
63
|
@abstractmethod
|
|
59
|
-
def bind(self, scope: Scope) ->
|
|
64
|
+
def bind(self, scope: Scope) -> AbstractContextManager[None]:
|
|
60
65
|
raise NotImplementedError
|
|
61
66
|
|
|
62
67
|
@abstractmethod
|
|
@@ -128,7 +133,7 @@ __scope_resolvers: Final[Mapping[str, Mapping[str, ScopeResolver]]] = {
|
|
|
128
133
|
async def adefine_scope(
|
|
129
134
|
name: str,
|
|
130
135
|
/,
|
|
131
|
-
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(),
|
|
136
|
+
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(), # noqa: B008
|
|
132
137
|
threadsafe: bool | None = None,
|
|
133
138
|
) -> AsyncIterator[ScopeFacade]:
|
|
134
139
|
async with AsyncScope() as scope:
|
|
@@ -140,12 +145,11 @@ async def adefine_scope(
|
|
|
140
145
|
def define_scope(
|
|
141
146
|
name: str,
|
|
142
147
|
/,
|
|
143
|
-
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(),
|
|
148
|
+
kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(), # noqa: B008
|
|
144
149
|
threadsafe: bool | None = None,
|
|
145
150
|
) -> Iterator[ScopeFacade]:
|
|
146
|
-
with SyncScope() as scope:
|
|
147
|
-
|
|
148
|
-
yield facade
|
|
151
|
+
with SyncScope() as scope, _bind_scope(name, scope, kind, threadsafe) as facade:
|
|
152
|
+
yield facade
|
|
149
153
|
|
|
150
154
|
|
|
151
155
|
if TYPE_CHECKING: # pragma: no cover
|
|
@@ -234,11 +238,11 @@ class Scope(Protocol):
|
|
|
234
238
|
cache: MutableMapping[SlotKey[Any], Any]
|
|
235
239
|
|
|
236
240
|
@abstractmethod
|
|
237
|
-
async def aenter[T](self, context_manager:
|
|
241
|
+
async def aenter[T](self, context_manager: AbstractAsyncContextManager[T]) -> T:
|
|
238
242
|
raise NotImplementedError
|
|
239
243
|
|
|
240
244
|
@abstractmethod
|
|
241
|
-
def enter[T](self, context_manager:
|
|
245
|
+
def enter[T](self, context_manager: AbstractContextManager[T]) -> T:
|
|
242
246
|
raise NotImplementedError
|
|
243
247
|
|
|
244
248
|
|
|
@@ -270,10 +274,10 @@ class AsyncScope(BaseScope[AsyncExitStack]):
|
|
|
270
274
|
self.close()
|
|
271
275
|
return await self.delegate.__aexit__(exc_type, exc_value, traceback)
|
|
272
276
|
|
|
273
|
-
async def aenter[T](self, context_manager:
|
|
277
|
+
async def aenter[T](self, context_manager: AbstractAsyncContextManager[T]) -> T:
|
|
274
278
|
return await self.delegate.enter_async_context(context_manager)
|
|
275
279
|
|
|
276
|
-
def enter[T](self, context_manager:
|
|
280
|
+
def enter[T](self, context_manager: AbstractContextManager[T]) -> T:
|
|
277
281
|
return self.delegate.enter_context(context_manager)
|
|
278
282
|
|
|
279
283
|
|
|
@@ -296,10 +300,13 @@ class SyncScope(BaseScope[ExitStack]):
|
|
|
296
300
|
self.close()
|
|
297
301
|
return self.delegate.__exit__(exc_type, exc_value, traceback)
|
|
298
302
|
|
|
299
|
-
async def aenter[T](
|
|
303
|
+
async def aenter[T](
|
|
304
|
+
self,
|
|
305
|
+
context_manager: AbstractAsyncContextManager[T],
|
|
306
|
+
) -> NoReturn:
|
|
300
307
|
raise ScopeError("Synchronous scope doesn't support async context manager.")
|
|
301
308
|
|
|
302
|
-
def enter[T](self, context_manager:
|
|
309
|
+
def enter[T](self, context_manager: AbstractContextManager[T]) -> T:
|
|
303
310
|
return self.delegate.enter_context(context_manager)
|
|
304
311
|
|
|
305
312
|
|
|
@@ -319,7 +326,7 @@ class ScopeFacade(Protocol):
|
|
|
319
326
|
@dataclass(repr=False, frozen=True, slots=True)
|
|
320
327
|
class _UserScope(ScopeFacade):
|
|
321
328
|
scope: Scope
|
|
322
|
-
lock:
|
|
329
|
+
lock: AbstractContextManager[Any]
|
|
323
330
|
|
|
324
331
|
def set_slot[T](self, key: SlotKey[T], value: T) -> Self:
|
|
325
332
|
return self.slot_map({key: value})
|
injection/entrypoint.py
CHANGED
|
@@ -194,18 +194,18 @@ class EntrypointBuilder[**P, T1, T2](_EntrypointDecorator[P, T1, T2]):
|
|
|
194
194
|
|
|
195
195
|
return decorator(wrapped) if wrapped else decorator
|
|
196
196
|
|
|
197
|
-
def async_to_sync[
|
|
198
|
-
self: EntrypointBuilder[P, T1, Awaitable[
|
|
199
|
-
run: Callable[[Coroutine[Any, Any,
|
|
197
|
+
def async_to_sync[T](
|
|
198
|
+
self: EntrypointBuilder[P, T1, Awaitable[T]],
|
|
199
|
+
run: Callable[[Coroutine[Any, Any, T]], T] = asyncio.run,
|
|
200
200
|
/,
|
|
201
|
-
) -> EntrypointBuilder[P, T1,
|
|
201
|
+
) -> EntrypointBuilder[P, T1, T]:
|
|
202
202
|
return self._add_rule(_AsyncToSyncRule(run)) # type: ignore[arg-type]
|
|
203
203
|
|
|
204
|
-
def decorate[
|
|
204
|
+
def decorate[T](
|
|
205
205
|
self,
|
|
206
|
-
decorator: Callable[[Callable[P, T2]], Callable[P,
|
|
206
|
+
decorator: Callable[[Callable[P, T2]], Callable[P, T]],
|
|
207
207
|
/,
|
|
208
|
-
) -> EntrypointBuilder[P, T1,
|
|
208
|
+
) -> EntrypointBuilder[P, T1, T]:
|
|
209
209
|
return self._add_rule(_DecorateRule(decorator))
|
|
210
210
|
|
|
211
211
|
def inject(self) -> Self:
|
|
@@ -224,10 +224,10 @@ class EntrypointBuilder[**P, T1, T2](_EntrypointDecorator[P, T1, T2]):
|
|
|
224
224
|
self._add_rule(_LoadProfileRule(self.profile_loader, name))
|
|
225
225
|
return self
|
|
226
226
|
|
|
227
|
-
def _add_rule[
|
|
227
|
+
def _add_rule[T](
|
|
228
228
|
self,
|
|
229
|
-
rule: Rule[P, T2,
|
|
230
|
-
) -> EntrypointBuilder[P, T1,
|
|
229
|
+
rule: Rule[P, T2, T],
|
|
230
|
+
) -> EntrypointBuilder[P, T1, T]:
|
|
231
231
|
self.__rules.append(rule)
|
|
232
232
|
return self # type: ignore[return-value]
|
|
233
233
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-injection
|
|
3
|
-
Version: 0.26.
|
|
3
|
+
Version: 0.26.3
|
|
4
4
|
Summary: Dead-simple dependency injection framework for Python.
|
|
5
5
|
Project-URL: Documentation, https://python-injection.remimd.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/100nm/python-injection
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
21
22
|
Classifier: Topic :: Software Development :: Libraries
|
|
22
23
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
23
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -68,6 +69,7 @@ Simply apply the decorators and the package takes care of the rest.
|
|
|
68
69
|
```python
|
|
69
70
|
from injection import injectable, inject, singleton
|
|
70
71
|
|
|
72
|
+
|
|
71
73
|
@singleton
|
|
72
74
|
class Printer:
|
|
73
75
|
def __init__(self):
|
|
@@ -77,6 +79,7 @@ class Printer:
|
|
|
77
79
|
self.history.append(message)
|
|
78
80
|
print(message)
|
|
79
81
|
|
|
82
|
+
|
|
80
83
|
@injectable
|
|
81
84
|
class Service:
|
|
82
85
|
def __init__(self, printer: Printer):
|
|
@@ -85,10 +88,12 @@ class Service:
|
|
|
85
88
|
def hello(self):
|
|
86
89
|
self.printer.print("Hello world!")
|
|
87
90
|
|
|
91
|
+
|
|
88
92
|
@inject
|
|
89
93
|
def main(service: Service):
|
|
90
94
|
service.hello()
|
|
91
95
|
|
|
96
|
+
|
|
92
97
|
if __name__ == "__main__":
|
|
93
98
|
main()
|
|
94
99
|
```
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
injection/__init__.py,sha256=8nYCdToksoBIRTiJFrEbAUa_g8--dFL--4pfSGlGDP4,1350
|
|
2
2
|
injection/__init__.pyi,sha256=XzOmrlk_6HNAiQVU4aUDoy3414enMaKTNPpKpXHLYyI,13659
|
|
3
|
-
injection/entrypoint.py,sha256
|
|
3
|
+
injection/entrypoint.py,sha256=-pQuu2pM6CIs-GBNYhlqRe2bPBvShbi_q-AKeOw0Iko,6698
|
|
4
4
|
injection/exceptions.py,sha256=v57yMujiq6H_zwwn30A8UYEZX9R9k-bY8FnsdaimPM4,1025
|
|
5
5
|
injection/loaders.py,sha256=gBwEfmR1ZHybD2hdtVr-ji6HZS7gCQvgajoiatmZpeM,7394
|
|
6
6
|
injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
injection/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
injection/_core/asfunction.py,sha256=GY228WHQWvA-9rg3unR8ttyIJlhwxy0bC3LUO5K8Erg,1864
|
|
9
|
-
injection/_core/descriptors.py,sha256=
|
|
10
|
-
injection/_core/injectables.py,sha256=
|
|
11
|
-
injection/_core/locator.py,sha256=
|
|
12
|
-
injection/_core/module.py,sha256=
|
|
13
|
-
injection/_core/scope.py,sha256=
|
|
9
|
+
injection/_core/descriptors.py,sha256=OBuGGPPn9b2dLTfFA1tdUD2zv11F4_1h1Vsm_cNaF-M,3602
|
|
10
|
+
injection/_core/injectables.py,sha256=6PY_-DCfCd7eTZoHwBxvuPMX78XIYq128sAKOAjoiOQ,6467
|
|
11
|
+
injection/_core/locator.py,sha256=zSzLN7WiEPlYyrWra8siVnqx78jEW7AZ0rn5hZSmF3o,8270
|
|
12
|
+
injection/_core/module.py,sha256=W4HsK7OJ_wlKIkca4g6O4LT5v1nf2D6ow-303JasLQ0,28918
|
|
13
|
+
injection/_core/scope.py,sha256=WIkv8PvmSZt4us3PKZA8KuM4Mtd7TzXVhi-V_zxt-kE,9060
|
|
14
14
|
injection/_core/slots.py,sha256=g9TG6CbqRzCsjg01iPyfRtTTUCJnnJOwcj9mJabH0dc,37
|
|
15
15
|
injection/_core/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
injection/_core/common/asynchronous.py,sha256=
|
|
17
|
-
injection/_core/common/event.py,sha256=
|
|
16
|
+
injection/_core/common/asynchronous.py,sha256=QldcR-QyrDD8u1T-P5gEm2Vb-2DbU64bdE7NZXf_AhU,1785
|
|
17
|
+
injection/_core/common/event.py,sha256=oZj1Uw4-XAcdBFzy7xmn9CC6HoIMxbdVXkHICLSORqk,1252
|
|
18
18
|
injection/_core/common/invertible.py,sha256=gA_vw5nBjgp_w9MrDK5jMO8lhuOQWON8BbPpKzEuIY0,502
|
|
19
|
-
injection/_core/common/lazy.py,sha256=
|
|
20
|
-
injection/_core/common/threading.py,sha256
|
|
19
|
+
injection/_core/common/lazy.py,sha256=jTv7mYChvRp6WLWILLbEejrHq24gFRKOkkUuZjnwYlE,796
|
|
20
|
+
injection/_core/common/threading.py,sha256=-A1z7l363JZx8em88INpvV-DOQ7xO2y57u5I7Pta-Jw,459
|
|
21
21
|
injection/_core/common/type.py,sha256=d1CtWyu--7Ru7vi9uqAQucO1oXFmAsuUhP2j-dCYkfM,1533
|
|
22
22
|
injection/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
injection/ext/fastapi.py,sha256=wpiNyHKEPwQ7sAJt30XpkgiCi4-gfmyqkQWw9BejXwg,1633
|
|
24
24
|
injection/ext/fastapi.pyi,sha256=HLs7mfruIEFRrN_Xf8oCvSa4qwHWfwm6HHU_KMedXkE,185
|
|
25
25
|
injection/testing/__init__.py,sha256=ZWMacZuGhK8Edq1L0Ng0PaRlgKXEunyFZkFvx7-IYIQ,935
|
|
26
26
|
injection/testing/__init__.pyi,sha256=ZFQMUZmvBVkV6Ch7jiYE9zeJhnqHAQnt3vWQ1Th0zDk,646
|
|
27
|
-
python_injection-0.26.
|
|
28
|
-
python_injection-0.26.
|
|
29
|
-
python_injection-0.26.
|
|
30
|
-
python_injection-0.26.
|
|
27
|
+
python_injection-0.26.3.dist-info/METADATA,sha256=QhVKKiAbtQNT1Y68W0JPBo4nTU_yPPCMY-sAiEqgjRw,3706
|
|
28
|
+
python_injection-0.26.3.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
29
|
+
python_injection-0.26.3.dist-info/licenses/LICENSE,sha256=oC77BOa9kaaQni5rW-Z-ytz3E5h4EVg248BHg9UFgyg,1063
|
|
30
|
+
python_injection-0.26.3.dist-info/RECORD,,
|
|
File without changes
|