python-injection 0.7.2__py3-none-any.whl → 0.7.4__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.
Potentially problematic release.
This version of python-injection might be problematic. Click here for more details.
- injection/_pkg.py +2 -2
- injection/_pkg.pyi +5 -12
- injection/core/module.py +58 -52
- injection/exceptions.py +4 -4
- {python_injection-0.7.2.dist-info → python_injection-0.7.4.dist-info}/METADATA +1 -1
- {python_injection-0.7.2.dist-info → python_injection-0.7.4.dist-info}/RECORD +7 -8
- injection/integrations/typer.py +0 -15
- {python_injection-0.7.2.dist-info → python_injection-0.7.4.dist-info}/WHEEL +0 -0
injection/_pkg.py
CHANGED
injection/_pkg.pyi
CHANGED
|
@@ -85,14 +85,7 @@ class Module:
|
|
|
85
85
|
always be the same.
|
|
86
86
|
"""
|
|
87
87
|
|
|
88
|
-
def should_be_injectable(
|
|
89
|
-
self,
|
|
90
|
-
wrapped: Callable[..., Any] = ...,
|
|
91
|
-
/,
|
|
92
|
-
*,
|
|
93
|
-
on: type | Iterable[type] | UnionType = ...,
|
|
94
|
-
override: bool = ...,
|
|
95
|
-
):
|
|
88
|
+
def should_be_injectable(self, wrapped: type = ..., /):
|
|
96
89
|
"""
|
|
97
90
|
Decorator applicable to a class. It is used to specify whether an injectable
|
|
98
91
|
should be registered. Raise an exception at injection time if the class isn't
|
|
@@ -128,7 +121,7 @@ class Module:
|
|
|
128
121
|
Example: instance = ~lazy_instance
|
|
129
122
|
"""
|
|
130
123
|
|
|
131
|
-
def use(self, module: Module, priority:
|
|
124
|
+
def use(self, module: Module, priority: ModulePriority = ...):
|
|
132
125
|
"""
|
|
133
126
|
Function for using another module. Using another module replaces the module's
|
|
134
127
|
dependencies with those of the module used. If the dependency is not found, it
|
|
@@ -143,13 +136,13 @@ class Module:
|
|
|
143
136
|
def use_temporarily(
|
|
144
137
|
self,
|
|
145
138
|
module: Module,
|
|
146
|
-
priority:
|
|
139
|
+
priority: ModulePriority = ...,
|
|
147
140
|
) -> ContextManager | ContextDecorator:
|
|
148
141
|
"""
|
|
149
142
|
Context manager or decorator for temporary use of a module.
|
|
150
143
|
"""
|
|
151
144
|
|
|
152
|
-
def change_priority(self, module: Module, priority:
|
|
145
|
+
def change_priority(self, module: Module, priority: ModulePriority):
|
|
153
146
|
"""
|
|
154
147
|
Function for changing the priority of a module in use.
|
|
155
148
|
There are two priority values:
|
|
@@ -164,7 +157,7 @@ class Module:
|
|
|
164
157
|
"""
|
|
165
158
|
|
|
166
159
|
@final
|
|
167
|
-
class
|
|
160
|
+
class ModulePriority(Enum):
|
|
168
161
|
HIGH = ...
|
|
169
162
|
LOW = ...
|
|
170
163
|
|
injection/core/module.py
CHANGED
|
@@ -11,6 +11,7 @@ from collections.abc import (
|
|
|
11
11
|
Iterator,
|
|
12
12
|
Mapping,
|
|
13
13
|
MutableMapping,
|
|
14
|
+
Set,
|
|
14
15
|
)
|
|
15
16
|
from contextlib import ContextDecorator, contextmanager, suppress
|
|
16
17
|
from dataclasses import dataclass, field
|
|
@@ -41,7 +42,7 @@ from injection.exceptions import (
|
|
|
41
42
|
NoInjectable,
|
|
42
43
|
)
|
|
43
44
|
|
|
44
|
-
__all__ = ("Injectable", "Module", "
|
|
45
|
+
__all__ = ("Injectable", "Module", "ModulePriority")
|
|
45
46
|
|
|
46
47
|
_logger = logging.getLogger(__name__)
|
|
47
48
|
_thread_lock = RLock()
|
|
@@ -117,7 +118,7 @@ class ModuleRemoved(ModuleEvent):
|
|
|
117
118
|
@dataclass(frozen=True, slots=True)
|
|
118
119
|
class ModulePriorityUpdated(ModuleEvent):
|
|
119
120
|
module_updated: Module
|
|
120
|
-
priority:
|
|
121
|
+
priority: ModulePriority
|
|
121
122
|
|
|
122
123
|
def __str__(self) -> str:
|
|
123
124
|
return (
|
|
@@ -135,13 +136,15 @@ Injectables
|
|
|
135
136
|
class Injectable(Protocol[_T]):
|
|
136
137
|
__slots__ = ()
|
|
137
138
|
|
|
138
|
-
def __init__(self, __factory: Callable[[], _T] =
|
|
139
|
+
def __init__(self, __factory: Callable[[], _T] = None, /):
|
|
140
|
+
pass
|
|
139
141
|
|
|
140
142
|
@property
|
|
141
143
|
def is_locked(self) -> bool:
|
|
142
144
|
return False
|
|
143
145
|
|
|
144
|
-
def unlock(self):
|
|
146
|
+
def unlock(self):
|
|
147
|
+
pass
|
|
145
148
|
|
|
146
149
|
@abstractmethod
|
|
147
150
|
def get_instance(self) -> _T:
|
|
@@ -187,31 +190,15 @@ class SingletonInjectable(BaseInjectable[_T]):
|
|
|
187
190
|
return instance
|
|
188
191
|
|
|
189
192
|
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
@dataclass(repr=False, frozen=True, slots=True)
|
|
194
|
+
class ShouldBeInjectable(Injectable[_T]):
|
|
195
|
+
cls: type[_T]
|
|
192
196
|
|
|
193
197
|
def __bool__(self) -> bool:
|
|
194
198
|
return False
|
|
195
199
|
|
|
196
|
-
@property
|
|
197
|
-
def formatted_type(self) -> str:
|
|
198
|
-
return format_type(self.factory)
|
|
199
|
-
|
|
200
|
-
@property
|
|
201
|
-
@abstractmethod
|
|
202
|
-
def exception(self) -> BaseException:
|
|
203
|
-
raise NotImplementedError
|
|
204
|
-
|
|
205
200
|
def get_instance(self) -> NoReturn:
|
|
206
|
-
raise self.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
class ShouldBeInjectable(InjectableWarning[_T]):
|
|
210
|
-
__slots__ = ()
|
|
211
|
-
|
|
212
|
-
@property
|
|
213
|
-
def exception(self) -> BaseException:
|
|
214
|
-
return InjectionError(f"`{self.formatted_type}` should be an injectable.")
|
|
201
|
+
raise InjectionError(f"`{format_type(self.cls)}` should be an injectable.")
|
|
215
202
|
|
|
216
203
|
|
|
217
204
|
"""
|
|
@@ -265,23 +252,30 @@ class Container(Broker):
|
|
|
265
252
|
def is_locked(self) -> bool:
|
|
266
253
|
return any(injectable.is_locked for injectable in self.__injectables)
|
|
267
254
|
|
|
255
|
+
@property
|
|
256
|
+
def __classes(self) -> frozenset[type]:
|
|
257
|
+
return frozenset(self.__data.keys())
|
|
258
|
+
|
|
268
259
|
@property
|
|
269
260
|
def __injectables(self) -> frozenset[Injectable]:
|
|
270
261
|
return frozenset(self.__data.values())
|
|
271
262
|
|
|
272
|
-
def update(self, classes:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
263
|
+
def update(self, classes: Iterable[type], injectable: Injectable, override: bool):
|
|
264
|
+
classes = frozenset(get_origins(*classes))
|
|
265
|
+
|
|
266
|
+
with _thread_lock:
|
|
267
|
+
if not injectable:
|
|
268
|
+
classes -= self.__classes
|
|
269
|
+
override = True
|
|
276
270
|
|
|
277
|
-
|
|
278
|
-
|
|
271
|
+
if classes:
|
|
272
|
+
event = ContainerDependenciesUpdated(self, classes, override)
|
|
279
273
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
274
|
+
with self.notify(event):
|
|
275
|
+
if not override:
|
|
276
|
+
self.__check_if_exists(classes)
|
|
283
277
|
|
|
284
|
-
|
|
278
|
+
self.__data.update((cls, injectable) for cls in classes)
|
|
285
279
|
|
|
286
280
|
return self
|
|
287
281
|
|
|
@@ -296,9 +290,11 @@ class Container(Broker):
|
|
|
296
290
|
def notify(self, event: Event) -> ContextManager | ContextDecorator:
|
|
297
291
|
return self.__channel.dispatch(event)
|
|
298
292
|
|
|
299
|
-
def __check_if_exists(self,
|
|
300
|
-
|
|
301
|
-
|
|
293
|
+
def __check_if_exists(self, classes: Set[type]):
|
|
294
|
+
intersection = classes & self.__classes
|
|
295
|
+
|
|
296
|
+
for cls in intersection:
|
|
297
|
+
if self.__data[cls]:
|
|
302
298
|
raise RuntimeError(
|
|
303
299
|
f"An injectable already exists for the class `{format_type(cls)}`."
|
|
304
300
|
)
|
|
@@ -309,7 +305,7 @@ Module
|
|
|
309
305
|
"""
|
|
310
306
|
|
|
311
307
|
|
|
312
|
-
class
|
|
308
|
+
class ModulePriority(Enum):
|
|
313
309
|
HIGH = auto()
|
|
314
310
|
LOW = auto()
|
|
315
311
|
|
|
@@ -339,7 +335,7 @@ class Module(EventListener, Broker):
|
|
|
339
335
|
raise NoInjectable(cls)
|
|
340
336
|
|
|
341
337
|
def __setitem__(self, cls: type | UnionType, injectable: Injectable, /):
|
|
342
|
-
self.update((cls,), injectable
|
|
338
|
+
self.update((cls,), injectable)
|
|
343
339
|
|
|
344
340
|
def __contains__(self, cls: type | UnionType, /) -> bool:
|
|
345
341
|
return any(cls in broker for broker in self.__brokers)
|
|
@@ -376,11 +372,13 @@ class Module(EventListener, Broker):
|
|
|
376
372
|
return decorator(wrapped) if wrapped else decorator
|
|
377
373
|
|
|
378
374
|
singleton = partialmethod(injectable, cls=SingletonInjectable)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
375
|
+
|
|
376
|
+
def should_be_injectable(self, wrapped: type = None, /):
|
|
377
|
+
def decorator(wp):
|
|
378
|
+
self[wp] = ShouldBeInjectable(wp)
|
|
379
|
+
return wp
|
|
380
|
+
|
|
381
|
+
return decorator(wrapped) if wrapped else decorator
|
|
384
382
|
|
|
385
383
|
def set_constant(
|
|
386
384
|
self,
|
|
@@ -437,14 +435,19 @@ class Module(EventListener, Broker):
|
|
|
437
435
|
def get_lazy_instance(self, cls: type[_T]) -> Lazy[_T | None]:
|
|
438
436
|
return Lazy(lambda: self.get_instance(cls))
|
|
439
437
|
|
|
440
|
-
def update(
|
|
438
|
+
def update(
|
|
439
|
+
self,
|
|
440
|
+
classes: Iterable[type],
|
|
441
|
+
injectable: Injectable,
|
|
442
|
+
override: bool = False,
|
|
443
|
+
):
|
|
441
444
|
self.__container.update(classes, injectable, override)
|
|
442
445
|
return self
|
|
443
446
|
|
|
444
447
|
def use(
|
|
445
448
|
self,
|
|
446
449
|
module: Module,
|
|
447
|
-
priority:
|
|
450
|
+
priority: ModulePriority = ModulePriority.get_default(),
|
|
448
451
|
):
|
|
449
452
|
if module is self:
|
|
450
453
|
raise ModuleError("Module can't be used by itself.")
|
|
@@ -475,13 +478,13 @@ class Module(EventListener, Broker):
|
|
|
475
478
|
def use_temporarily(
|
|
476
479
|
self,
|
|
477
480
|
module: Module,
|
|
478
|
-
priority:
|
|
481
|
+
priority: ModulePriority = ModulePriority.get_default(),
|
|
479
482
|
) -> ContextManager | ContextDecorator:
|
|
480
483
|
self.use(module, priority)
|
|
481
484
|
yield
|
|
482
485
|
self.stop_using(module)
|
|
483
486
|
|
|
484
|
-
def change_priority(self, module: Module, priority:
|
|
487
|
+
def change_priority(self, module: Module, priority: ModulePriority):
|
|
485
488
|
event = ModulePriorityUpdated(self, module, priority)
|
|
486
489
|
|
|
487
490
|
with self.notify(event):
|
|
@@ -517,8 +520,8 @@ class Module(EventListener, Broker):
|
|
|
517
520
|
if self.is_locked:
|
|
518
521
|
raise ModuleLockError(f"`{self}` is locked.")
|
|
519
522
|
|
|
520
|
-
def __move_module(self, module: Module, priority:
|
|
521
|
-
last = priority ==
|
|
523
|
+
def __move_module(self, module: Module, priority: ModulePriority):
|
|
524
|
+
last = priority == ModulePriority.LOW
|
|
522
525
|
|
|
523
526
|
try:
|
|
524
527
|
self.__modules.move_to_end(module, last=last)
|
|
@@ -617,11 +620,14 @@ class Binder(EventListener):
|
|
|
617
620
|
return Arguments(bound.args, bound.kwargs)
|
|
618
621
|
|
|
619
622
|
def update(self, module: Module):
|
|
620
|
-
|
|
623
|
+
with _thread_lock:
|
|
624
|
+
self.__dependencies = Dependencies.resolve(self.__signature, module)
|
|
625
|
+
|
|
621
626
|
return self
|
|
622
627
|
|
|
623
628
|
@singledispatchmethod
|
|
624
|
-
def on_event(self, event: Event, /):
|
|
629
|
+
def on_event(self, event: Event, /):
|
|
630
|
+
pass
|
|
625
631
|
|
|
626
632
|
@on_event.register
|
|
627
633
|
@contextmanager
|
injection/exceptions.py
CHANGED
|
@@ -10,7 +10,7 @@ __all__ = (
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class InjectionError(Exception):
|
|
13
|
-
|
|
13
|
+
pass
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class NoInjectable(KeyError, InjectionError):
|
|
@@ -26,12 +26,12 @@ class NoInjectable(KeyError, InjectionError):
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class ModuleError(InjectionError):
|
|
29
|
-
|
|
29
|
+
pass
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class ModuleLockError(ModuleError):
|
|
33
|
-
|
|
33
|
+
pass
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class ModuleNotUsedError(KeyError, ModuleError):
|
|
37
|
-
|
|
37
|
+
pass
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
injection/__init__.py,sha256=9_AVJILxKIBiL_6KJSh2RRydgSHXH38uahAGD0S1-dI,20
|
|
2
|
-
injection/_pkg.py,sha256=
|
|
3
|
-
injection/_pkg.pyi,sha256=
|
|
2
|
+
injection/_pkg.py,sha256=nMIRLAQG6096bcR2Mz1egxe5FItBUsw8zR9yzjt1HDM,647
|
|
3
|
+
injection/_pkg.pyi,sha256=zxbidnUvr-8x7F8hLJUgEBzyefXtNW6Ajtuin6Z0cf8,5327
|
|
4
4
|
injection/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
injection/common/event.py,sha256=uFoGRnxxkohH53JEStn4tN2Pn79HlgGExh7VkXdBwVQ,1316
|
|
6
6
|
injection/common/lazy.py,sha256=HIefQ1z7ivgU791MDSwBmUcdST3bOv0sivSMyR2DfHc,1493
|
|
7
7
|
injection/common/tools/__init__.py,sha256=S2y9DaQ4EaTRty9fKpBtPXA7hSjkzgM5N2jFf5jcmJU,21
|
|
8
8
|
injection/common/tools/_type.py,sha256=-zL0dtoVZme71Mscvav7iEWxY2-JltzNTekbWOCPSFo,1276
|
|
9
9
|
injection/core/__init__.py,sha256=zuf0ubI2dHnbjn1059eduhS-ACIkkROa6-dhp10krh0,22
|
|
10
|
-
injection/core/module.py,sha256=
|
|
11
|
-
injection/exceptions.py,sha256=
|
|
10
|
+
injection/core/module.py,sha256=lEBJ6QGjPyp7bwEWE0RrOr26yrpJr1GKqsA-EV2LOAM,16594
|
|
11
|
+
injection/exceptions.py,sha256=lm79jrBkvK52BpcAo1kx7GeDCUtskNBRt9rQ6IE3B4A,648
|
|
12
12
|
injection/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
injection/integrations/blacksheep.py,sha256=vcLil1IccS7JtXpuVu7s2LqN5Zravfe_7xpAt5cTIU0,723
|
|
14
|
-
injection/integrations/typer.py,sha256=XtQjQhcd7k-513Wp5cP-7ES8-uWI5iI1T1o4kIEFvjU,266
|
|
15
14
|
injection/utils.py,sha256=_79aiciimZpuoUTz5lojKySUMMzpkU-e7SotiHIFTI8,676
|
|
16
|
-
python_injection-0.7.
|
|
17
|
-
python_injection-0.7.
|
|
18
|
-
python_injection-0.7.
|
|
15
|
+
python_injection-0.7.4.dist-info/METADATA,sha256=JXV2O9HN1D8LGa6CSA5KaQ4lDmm4flzuZioxG4z4hBY,3433
|
|
16
|
+
python_injection-0.7.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
17
|
+
python_injection-0.7.4.dist-info/RECORD,,
|
injection/integrations/typer.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from typer import Option
|
|
2
|
-
|
|
3
|
-
__all__ = ("ignore",)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def ignore():
|
|
7
|
-
"""
|
|
8
|
-
Typer option for the CLI to ignore this option and replace it with `None`.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
return Option(
|
|
12
|
-
default_factory=str,
|
|
13
|
-
parser=lambda _: None,
|
|
14
|
-
hidden=True,
|
|
15
|
-
)
|
|
File without changes
|