python-injection 0.9.4__tar.gz → 0.9.5__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.9.4 → python_injection-0.9.5}/PKG-INFO +15 -3
- {python_injection-0.9.4 → python_injection-0.9.5}/documentation/basic-usage.md +2 -1
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/__init__.pyi +1 -1
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/tools/type.py +3 -3
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/core/module.py +23 -22
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/integrations/blacksheep.py +0 -1
- python_injection-0.9.5/injection/testing/__init__.py +35 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/testing/__init__.pyi +1 -1
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/utils.py +13 -8
- {python_injection-0.9.4 → python_injection-0.9.5}/pyproject.toml +18 -4
- python_injection-0.9.4/injection/testing/__init__.py +0 -35
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/__init__.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/__init__.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/event.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/invertible.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/lazy.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/tools/__init__.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/common/tools/threading.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/core/__init__.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/exceptions.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/integrations/__init__.py +0 -0
- {python_injection-0.9.4 → python_injection-0.9.5}/injection/py.typed +0 -0
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-injection
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.5
|
|
4
4
|
Summary: Fast and easy dependency injection framework.
|
|
5
5
|
Home-page: https://github.com/100nm/python-injection
|
|
6
6
|
License: MIT
|
|
7
|
-
Keywords: dependencies,inject,injection
|
|
7
|
+
Keywords: dependencies,dependency,inject,injection
|
|
8
8
|
Author: remimd
|
|
9
9
|
Requires-Python: >=3.12,<4
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
10
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
11
16
|
Classifier: Programming Language :: Python :: 3
|
|
12
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Classifier: Typing :: Typed
|
|
13
24
|
Project-URL: Repository, https://github.com/100nm/python-injection
|
|
14
25
|
Description-Content-Type: text/markdown
|
|
15
26
|
|
|
@@ -48,7 +59,8 @@ from injection import set_constant
|
|
|
48
59
|
class ServiceC:
|
|
49
60
|
""" class implementation """
|
|
50
61
|
|
|
51
|
-
service_c =
|
|
62
|
+
service_c = ServiceC()
|
|
63
|
+
set_constant(service_c)
|
|
52
64
|
```
|
|
53
65
|
|
|
54
66
|
## Inject an instance
|
|
@@ -101,7 +101,7 @@ class Module:
|
|
|
101
101
|
on: TypeInfo[T] = ...,
|
|
102
102
|
*,
|
|
103
103
|
mode: InjectableMode | InjectableModeStr = ...,
|
|
104
|
-
) ->
|
|
104
|
+
) -> Self:
|
|
105
105
|
"""
|
|
106
106
|
Function for registering a specific instance to be injected. This is useful for
|
|
107
107
|
registering global variables. The difference with the singleton decorator is
|
|
@@ -59,9 +59,9 @@ def analyze_types(*types: type | Any) -> Iterator[TypeReport[Any]]:
|
|
|
59
59
|
|
|
60
60
|
def get_return_types(*args: TypeInfo[Any]) -> Iterator[type | UnionType]:
|
|
61
61
|
for arg in args:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
if isinstance(arg, Iterable) and not (
|
|
63
|
+
isinstance(arg, type | str) or isinstance(get_origin(arg), type)
|
|
64
|
+
):
|
|
65
65
|
inner_args = arg
|
|
66
66
|
|
|
67
67
|
elif isfunction(arg):
|
|
@@ -66,7 +66,7 @@ Events
|
|
|
66
66
|
|
|
67
67
|
@dataclass(frozen=True, slots=True)
|
|
68
68
|
class ContainerEvent(Event, ABC):
|
|
69
|
-
|
|
69
|
+
container: Container
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
@dataclass(frozen=True, slots=True)
|
|
@@ -85,7 +85,7 @@ class ContainerDependenciesUpdated(ContainerEvent):
|
|
|
85
85
|
|
|
86
86
|
@dataclass(frozen=True, slots=True)
|
|
87
87
|
class ModuleEvent(Event, ABC):
|
|
88
|
-
|
|
88
|
+
module: Module
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
@dataclass(frozen=True, slots=True)
|
|
@@ -93,7 +93,7 @@ class ModuleEventProxy(ModuleEvent):
|
|
|
93
93
|
event: Event
|
|
94
94
|
|
|
95
95
|
def __str__(self) -> str:
|
|
96
|
-
return f"`{self.
|
|
96
|
+
return f"`{self.module}` has propagated an event: {self.origin}"
|
|
97
97
|
|
|
98
98
|
@property
|
|
99
99
|
def history(self) -> Iterator[Event]:
|
|
@@ -113,7 +113,7 @@ class ModuleAdded(ModuleEvent):
|
|
|
113
113
|
priority: Priority
|
|
114
114
|
|
|
115
115
|
def __str__(self) -> str:
|
|
116
|
-
return f"`{self.
|
|
116
|
+
return f"`{self.module}` now uses `{self.module_added}`."
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
@dataclass(frozen=True, slots=True)
|
|
@@ -121,7 +121,7 @@ class ModuleRemoved(ModuleEvent):
|
|
|
121
121
|
module_removed: Module
|
|
122
122
|
|
|
123
123
|
def __str__(self) -> str:
|
|
124
|
-
return f"`{self.
|
|
124
|
+
return f"`{self.module}` no longer uses `{self.module_removed}`."
|
|
125
125
|
|
|
126
126
|
|
|
127
127
|
@dataclass(frozen=True, slots=True)
|
|
@@ -131,7 +131,7 @@ class ModulePriorityUpdated(ModuleEvent):
|
|
|
131
131
|
|
|
132
132
|
def __str__(self) -> str:
|
|
133
133
|
return (
|
|
134
|
-
f"In `{self.
|
|
134
|
+
f"In `{self.module}`, the priority `{self.priority}` "
|
|
135
135
|
f"has been applied to `{self.module_updated}`."
|
|
136
136
|
)
|
|
137
137
|
|
|
@@ -265,7 +265,7 @@ class Container(Broker):
|
|
|
265
265
|
|
|
266
266
|
def __getitem__[T](self, cls: type[T] | UnionType, /) -> Injectable[T]:
|
|
267
267
|
for report in analyze_types(cls):
|
|
268
|
-
for scoped_report in
|
|
268
|
+
for scoped_report in OrderedDict.fromkeys((report, report.no_args)):
|
|
269
269
|
try:
|
|
270
270
|
injectable, _ = self.__records[scoped_report]
|
|
271
271
|
except KeyError:
|
|
@@ -302,7 +302,7 @@ class Container(Broker):
|
|
|
302
302
|
if records:
|
|
303
303
|
event = ContainerDependenciesUpdated(self, records.keys(), mode)
|
|
304
304
|
|
|
305
|
-
with self.
|
|
305
|
+
with self.dispatch(event):
|
|
306
306
|
self.__records.update(records)
|
|
307
307
|
|
|
308
308
|
return self
|
|
@@ -318,7 +318,7 @@ class Container(Broker):
|
|
|
318
318
|
self.__channel.add_listener(listener)
|
|
319
319
|
return self
|
|
320
320
|
|
|
321
|
-
def
|
|
321
|
+
def dispatch(self, event: Event) -> ContextManager:
|
|
322
322
|
return self.__channel.dispatch(event)
|
|
323
323
|
|
|
324
324
|
def __prepare_reports_for_updating(
|
|
@@ -455,7 +455,7 @@ class Module(EventListener, Broker):
|
|
|
455
455
|
on: TypeInfo[T] = (),
|
|
456
456
|
*,
|
|
457
457
|
mode: Mode | ModeStr = Mode.get_default(),
|
|
458
|
-
) ->
|
|
458
|
+
) -> Self:
|
|
459
459
|
cls = type(instance)
|
|
460
460
|
self.injectable(
|
|
461
461
|
lambda: instance,
|
|
@@ -463,7 +463,7 @@ class Module(EventListener, Broker):
|
|
|
463
463
|
on=(cls, on),
|
|
464
464
|
mode=mode,
|
|
465
465
|
)
|
|
466
|
-
return
|
|
466
|
+
return self
|
|
467
467
|
|
|
468
468
|
def inject(
|
|
469
469
|
self,
|
|
@@ -544,7 +544,7 @@ class Module(EventListener, Broker):
|
|
|
544
544
|
priority = Priority(priority)
|
|
545
545
|
event = ModuleAdded(self, module, priority)
|
|
546
546
|
|
|
547
|
-
with self.
|
|
547
|
+
with self.dispatch(event):
|
|
548
548
|
self.__modules[module] = None
|
|
549
549
|
self.__move_module(module, priority)
|
|
550
550
|
module.add_listener(self)
|
|
@@ -555,7 +555,7 @@ class Module(EventListener, Broker):
|
|
|
555
555
|
event = ModuleRemoved(self, module)
|
|
556
556
|
|
|
557
557
|
with suppress(KeyError):
|
|
558
|
-
with self.
|
|
558
|
+
with self.dispatch(event):
|
|
559
559
|
self.__modules.pop(module)
|
|
560
560
|
module.remove_listener(self)
|
|
561
561
|
|
|
@@ -576,7 +576,7 @@ class Module(EventListener, Broker):
|
|
|
576
576
|
priority = Priority(priority)
|
|
577
577
|
event = ModulePriorityUpdated(self, module, priority)
|
|
578
578
|
|
|
579
|
-
with self.
|
|
579
|
+
with self.dispatch(event):
|
|
580
580
|
self.__move_module(module, priority)
|
|
581
581
|
|
|
582
582
|
return self
|
|
@@ -602,15 +602,20 @@ class Module(EventListener, Broker):
|
|
|
602
602
|
|
|
603
603
|
def on_event(self, event: Event, /) -> ContextManager:
|
|
604
604
|
self_event = ModuleEventProxy(self, event)
|
|
605
|
-
return self.
|
|
605
|
+
return self.dispatch(self_event)
|
|
606
606
|
|
|
607
607
|
@contextmanager
|
|
608
|
-
def
|
|
608
|
+
def dispatch(self, event: Event):
|
|
609
609
|
self.__check_locking()
|
|
610
610
|
|
|
611
611
|
with self.__channel.dispatch(event):
|
|
612
612
|
yield
|
|
613
|
-
|
|
613
|
+
message = str(event)
|
|
614
|
+
self.__debug(message)
|
|
615
|
+
|
|
616
|
+
def __debug(self, message: object):
|
|
617
|
+
for logger in tuple(self.__loggers):
|
|
618
|
+
logger.debug(message)
|
|
614
619
|
|
|
615
620
|
def __check_locking(self):
|
|
616
621
|
if self.is_locked:
|
|
@@ -626,10 +631,6 @@ class Module(EventListener, Broker):
|
|
|
626
631
|
f"`{module}` can't be found in the modules used by `{self}`."
|
|
627
632
|
) from exc
|
|
628
633
|
|
|
629
|
-
def __send_debug(self, message: object):
|
|
630
|
-
for logger in tuple(self.__loggers):
|
|
631
|
-
logger.debug(message)
|
|
632
|
-
|
|
633
634
|
@classmethod
|
|
634
635
|
def from_name(cls, name: str) -> Self:
|
|
635
636
|
with suppress(KeyError):
|
|
@@ -816,7 +817,7 @@ class InjectedFunction(EventListener):
|
|
|
816
817
|
@contextmanager
|
|
817
818
|
def _(self, event: ModuleEvent, /):
|
|
818
819
|
yield
|
|
819
|
-
self.update(event.
|
|
820
|
+
self.update(event.module)
|
|
820
821
|
|
|
821
822
|
def __setup(self):
|
|
822
823
|
queue = self.__setup_queue
|
|
@@ -22,7 +22,6 @@ class InjectionServices(ContainerProtocol):
|
|
|
22
22
|
|
|
23
23
|
def register(self, obj_type: type | Any, *args, **kwargs):
|
|
24
24
|
self.__module.injectable(obj_type)
|
|
25
|
-
return self
|
|
26
25
|
|
|
27
26
|
def resolve[T](self, obj_type: type[T] | Any, *args, **kwargs) -> T:
|
|
28
27
|
return self.__module.find_instance(obj_type)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from functools import partial
|
|
3
|
+
|
|
4
|
+
from injection import Module, ModulePriority, mod
|
|
5
|
+
|
|
6
|
+
__all__ = (
|
|
7
|
+
"set_test_constant",
|
|
8
|
+
"should_be_test_injectable",
|
|
9
|
+
"test_injectable",
|
|
10
|
+
"test_singleton",
|
|
11
|
+
"use_test_injectables",
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
tmod = partial(mod, "testing")
|
|
16
|
+
|
|
17
|
+
set_test_constant = tmod().set_constant
|
|
18
|
+
should_be_test_injectable = tmod().should_be_injectable
|
|
19
|
+
test_injectable = tmod().injectable
|
|
20
|
+
test_singleton = tmod().singleton
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@contextmanager
|
|
24
|
+
def use_test_injectables(*, module: Module = None, test_module: Module = None):
|
|
25
|
+
module = module or mod()
|
|
26
|
+
test_module = test_module or tmod()
|
|
27
|
+
|
|
28
|
+
for m in (module, test_module):
|
|
29
|
+
m.unlock()
|
|
30
|
+
|
|
31
|
+
del m
|
|
32
|
+
|
|
33
|
+
with module.use_temporarily(test_module, priority=ModulePriority.HIGH):
|
|
34
|
+
yield
|
|
35
|
+
module.unlock()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
1
|
+
from collections.abc import Callable, Iterator
|
|
2
2
|
from importlib import import_module
|
|
3
3
|
from pkgutil import walk_packages
|
|
4
4
|
from types import ModuleType
|
|
@@ -6,7 +6,10 @@ from types import ModuleType
|
|
|
6
6
|
__all__ = ("load_package",)
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def load_package(
|
|
9
|
+
def load_package(
|
|
10
|
+
package: ModuleType | str,
|
|
11
|
+
predicate: Callable[[str], bool] = lambda module_name: True,
|
|
12
|
+
) -> tuple[ModuleType, ...]:
|
|
10
13
|
"""
|
|
11
14
|
Function for importing all modules in a Python package.
|
|
12
15
|
Pass the `predicate` parameter if you want to filter the modules to be imported.
|
|
@@ -15,6 +18,13 @@ def load_package(package: ModuleType | str, predicate: Callable[[str], bool] = N
|
|
|
15
18
|
if isinstance(package, str):
|
|
16
19
|
package = import_module(package)
|
|
17
20
|
|
|
21
|
+
return tuple(__iter_modules(package, predicate))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def __iter_modules(
|
|
25
|
+
package: ModuleType,
|
|
26
|
+
predicate: Callable[[str], bool],
|
|
27
|
+
) -> Iterator[ModuleType]:
|
|
18
28
|
try:
|
|
19
29
|
path = package.__path__
|
|
20
30
|
except AttributeError as exc:
|
|
@@ -22,15 +32,10 @@ def load_package(package: ModuleType | str, predicate: Callable[[str], bool] = N
|
|
|
22
32
|
"Package has no `__path__` attribute, as it's probably a module."
|
|
23
33
|
) from exc
|
|
24
34
|
|
|
25
|
-
if predicate is None:
|
|
26
|
-
|
|
27
|
-
def predicate(_: str) -> bool:
|
|
28
|
-
return True
|
|
29
|
-
|
|
30
35
|
for info in walk_packages(path=path, prefix=f"{package.__name__}."):
|
|
31
36
|
name = info.name
|
|
32
37
|
|
|
33
38
|
if info.ispkg or not predicate(name):
|
|
34
39
|
continue
|
|
35
40
|
|
|
36
|
-
import_module(name)
|
|
41
|
+
yield import_module(name)
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-injection"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.5"
|
|
4
4
|
description = "Fast and easy dependency injection framework."
|
|
5
|
-
authors = ["remimd"]
|
|
6
|
-
keywords = ["dependencies", "inject", "injection"]
|
|
7
5
|
license = "MIT"
|
|
8
|
-
|
|
6
|
+
authors = ["remimd"]
|
|
9
7
|
readme = "documentation/basic-usage.md"
|
|
10
8
|
repository = "https://github.com/100nm/python-injection"
|
|
9
|
+
keywords = ["dependencies", "dependency", "inject", "injection"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Topic :: Software Development :: Libraries",
|
|
13
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
14
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
15
|
+
"Topic :: Software Development :: Testing",
|
|
16
|
+
"Programming Language :: Python",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Natural Language :: English",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
packages = [{ include = "injection" }]
|
|
11
25
|
|
|
12
26
|
[tool.poetry.dependencies]
|
|
13
27
|
python = ">=3.12, <4"
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
from contextlib import contextmanager
|
|
2
|
-
from functools import partial
|
|
3
|
-
|
|
4
|
-
from injection import Module, ModulePriority, mod
|
|
5
|
-
|
|
6
|
-
__all__ = (
|
|
7
|
-
"set_test_constant",
|
|
8
|
-
"should_be_test_injectable",
|
|
9
|
-
"test_injectable",
|
|
10
|
-
"test_singleton",
|
|
11
|
-
"use_test_injectables",
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
testing_mod = partial(mod, "testing")
|
|
16
|
-
|
|
17
|
-
set_test_constant = testing_mod().set_constant
|
|
18
|
-
should_be_test_injectable = testing_mod().should_be_injectable
|
|
19
|
-
test_injectable = testing_mod().injectable
|
|
20
|
-
test_singleton = testing_mod().singleton
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@contextmanager
|
|
24
|
-
def use_test_injectables(*, on: Module = None, test_module: Module = None):
|
|
25
|
-
on = on or mod()
|
|
26
|
-
test_module = test_module or testing_mod()
|
|
27
|
-
|
|
28
|
-
for module in (on, test_module):
|
|
29
|
-
module.unlock()
|
|
30
|
-
|
|
31
|
-
del module
|
|
32
|
-
|
|
33
|
-
with on.use_temporarily(test_module, priority=ModulePriority.HIGH):
|
|
34
|
-
yield
|
|
35
|
-
on.unlock()
|
|
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
|