python-injection 0.25.13__tar.gz → 0.25.15__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.
- {python_injection-0.25.13 → python_injection-0.25.15}/PKG-INFO +1 -1
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/type.py +6 -6
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/injectables.py +5 -26
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/module.py +7 -7
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/loaders.py +5 -2
- {python_injection-0.25.13 → python_injection-0.25.15}/pyproject.toml +1 -1
- {python_injection-0.25.13 → python_injection-0.25.15}/.gitignore +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/LICENSE +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/docs/index.md +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/__init__.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/__init__.pyi +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/__init__.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/asfunction.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/__init__.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/asynchronous.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/event.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/invertible.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/lazy.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/threading.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/descriptors.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/locator.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/scope.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/slots.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/entrypoint.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/exceptions.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/ext/__init__.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/ext/fastapi.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/ext/fastapi.pyi +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/py.typed +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/testing/__init__.py +0 -0
- {python_injection-0.25.13 → python_injection-0.25.15}/injection/testing/__init__.pyi +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-injection
|
|
3
|
-
Version: 0.25.
|
|
3
|
+
Version: 0.25.15
|
|
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
|
|
@@ -28,14 +28,14 @@ type TypeInfo[T] = (
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def
|
|
31
|
+
def get_return_type[T](function: Callable[..., T]) -> Any | None:
|
|
32
32
|
return get_type_hints(function).get("return")
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def
|
|
35
|
+
def get_yield_types[T](
|
|
36
36
|
function: Callable[..., Iterator[T]] | Callable[..., AsyncIterator[T]],
|
|
37
|
-
) -> tuple[
|
|
38
|
-
return_type =
|
|
37
|
+
) -> tuple[Any] | tuple[()]:
|
|
38
|
+
return_type = get_return_type(function)
|
|
39
39
|
|
|
40
40
|
if get_origin(return_type) in (
|
|
41
41
|
AsyncGenerator,
|
|
@@ -62,8 +62,8 @@ def iter_flat_types(*args: Any) -> Iterator[Any]:
|
|
|
62
62
|
|
|
63
63
|
def iter_return_types(*args: Any) -> Iterator[Any]:
|
|
64
64
|
for arg in args:
|
|
65
|
-
if isfunction(arg) and (return_type :=
|
|
66
|
-
yield
|
|
65
|
+
if isfunction(arg) and (return_type := get_return_type(arg)):
|
|
66
|
+
yield return_type
|
|
67
67
|
|
|
68
68
|
else:
|
|
69
69
|
yield arg
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from collections.abc import Awaitable, Callable,
|
|
3
|
-
from contextlib import
|
|
2
|
+
from collections.abc import Awaitable, Callable, MutableMapping
|
|
3
|
+
from contextlib import suppress
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import partial
|
|
6
6
|
from typing import (
|
|
@@ -53,13 +53,11 @@ class TransientInjectable[T](Injectable[T]):
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
class CacheLogic[T]:
|
|
56
|
-
__slots__ = ("
|
|
56
|
+
__slots__ = ("__semaphore",)
|
|
57
57
|
|
|
58
|
-
__is_instantiating: bool
|
|
59
58
|
__semaphore: AsyncContextManager[Any]
|
|
60
59
|
|
|
61
60
|
def __init__(self) -> None:
|
|
62
|
-
self.__is_instantiating = False
|
|
63
61
|
self.__semaphore = AsyncSemaphore(1)
|
|
64
62
|
|
|
65
63
|
async def aget_or_create[K](
|
|
@@ -68,14 +66,11 @@ class CacheLogic[T]:
|
|
|
68
66
|
key: K,
|
|
69
67
|
factory: Callable[..., Awaitable[T]],
|
|
70
68
|
) -> T:
|
|
71
|
-
self.__fail_if_instantiating()
|
|
72
69
|
async with self.__semaphore:
|
|
73
70
|
with suppress(KeyError):
|
|
74
71
|
return cache[key]
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
instance = await factory()
|
|
78
|
-
|
|
73
|
+
instance = await factory()
|
|
79
74
|
cache[key] = instance
|
|
80
75
|
|
|
81
76
|
return instance
|
|
@@ -86,29 +81,13 @@ class CacheLogic[T]:
|
|
|
86
81
|
key: K,
|
|
87
82
|
factory: Callable[..., T],
|
|
88
83
|
) -> T:
|
|
89
|
-
self.__fail_if_instantiating()
|
|
90
84
|
with suppress(KeyError):
|
|
91
85
|
return cache[key]
|
|
92
86
|
|
|
93
|
-
|
|
94
|
-
instance = factory()
|
|
95
|
-
|
|
87
|
+
instance = factory()
|
|
96
88
|
cache[key] = instance
|
|
97
89
|
return instance
|
|
98
90
|
|
|
99
|
-
def __fail_if_instantiating(self) -> None:
|
|
100
|
-
if self.__is_instantiating:
|
|
101
|
-
raise RecursionError("Recursive call detected during instantiation.")
|
|
102
|
-
|
|
103
|
-
@contextmanager
|
|
104
|
-
def __instantiating(self) -> Iterator[None]:
|
|
105
|
-
self.__is_instantiating = True
|
|
106
|
-
|
|
107
|
-
try:
|
|
108
|
-
yield
|
|
109
|
-
finally:
|
|
110
|
-
self.__is_instantiating = False
|
|
111
|
-
|
|
112
91
|
|
|
113
92
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
114
93
|
class SingletonInjectable[T](Injectable[T]):
|
|
@@ -52,7 +52,7 @@ from injection._core.common.threading import get_lock
|
|
|
52
52
|
from injection._core.common.type import (
|
|
53
53
|
InputType,
|
|
54
54
|
TypeInfo,
|
|
55
|
-
|
|
55
|
+
get_yield_types,
|
|
56
56
|
iter_flat_types,
|
|
57
57
|
iter_return_types,
|
|
58
58
|
)
|
|
@@ -264,14 +264,14 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
264
264
|
if isasyncgenfunction(wrapped):
|
|
265
265
|
ctx = _ScopedContext(
|
|
266
266
|
cls=AsyncCMScopedInjectable,
|
|
267
|
-
hints=() if ignore_type_hint else
|
|
267
|
+
hints=() if ignore_type_hint else get_yield_types(wrapped),
|
|
268
268
|
wrapper=asynccontextmanager(wrapped),
|
|
269
269
|
)
|
|
270
270
|
|
|
271
271
|
elif isgeneratorfunction(wrapped):
|
|
272
272
|
ctx = _ScopedContext(
|
|
273
273
|
cls=CMScopedInjectable,
|
|
274
|
-
hints=() if ignore_type_hint else
|
|
274
|
+
hints=() if ignore_type_hint else get_yield_types(wrapped),
|
|
275
275
|
wrapper=contextmanager(wrapped),
|
|
276
276
|
)
|
|
277
277
|
|
|
@@ -713,19 +713,19 @@ class Module(EventListener, InjectionProvider): # type: ignore[misc]
|
|
|
713
713
|
return cls.from_name("__default__")
|
|
714
714
|
|
|
715
715
|
@staticmethod
|
|
716
|
-
def __build_key_types(
|
|
716
|
+
def __build_key_types(input_class: Any) -> frozenset[Any]:
|
|
717
717
|
config = MatchingTypesConfig(ignore_none=True)
|
|
718
718
|
return frozenset(
|
|
719
719
|
matching_type
|
|
720
|
-
for cls in iter_flat_types(
|
|
720
|
+
for cls in iter_flat_types(input_class)
|
|
721
721
|
for return_type in iter_return_types(cls)
|
|
722
722
|
for matching_type in iter_matching_types(return_type, config)
|
|
723
723
|
)
|
|
724
724
|
|
|
725
725
|
@staticmethod
|
|
726
|
-
def __matching_key_types(
|
|
726
|
+
def __matching_key_types(input_class: Any) -> tuple[Any, ...]:
|
|
727
727
|
config = MatchingTypesConfig(with_origin=True, with_type_alias_value=True)
|
|
728
|
-
return matching_types(
|
|
728
|
+
return matching_types(input_class, config)
|
|
729
729
|
|
|
730
730
|
|
|
731
731
|
def mod(name: str | None = None, /) -> Module:
|
|
@@ -150,8 +150,11 @@ class ProfileLoader:
|
|
|
150
150
|
return not self.module_subsets
|
|
151
151
|
|
|
152
152
|
def required_module_names(self, name: str | None = None, /) -> frozenset[str]:
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
subsets = (
|
|
154
|
+
self.__walk_subsets_for(module_name)
|
|
155
|
+
for module_name in (self.module.name, name)
|
|
156
|
+
if module_name is not None
|
|
157
|
+
)
|
|
155
158
|
return frozenset(itertools.chain.from_iterable(subsets))
|
|
156
159
|
|
|
157
160
|
def init(self) -> 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
|
{python_injection-0.25.13 → python_injection-0.25.15}/injection/_core/common/asynchronous.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|