anydi 0.34.0__py3-none-any.whl → 0.34.1__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.
- anydi/__init__.py +9 -3
- anydi/_container.py +466 -82
- anydi/_context.py +29 -268
- anydi/_provider.py +32 -4
- anydi/_types.py +19 -3
- anydi/ext/django/middleware.py +4 -4
- anydi/ext/starlette/middleware.py +2 -2
- {anydi-0.34.0.dist-info → anydi-0.34.1.dist-info}/METADATA +2 -2
- {anydi-0.34.0.dist-info → anydi-0.34.1.dist-info}/RECORD +12 -14
- anydi/_module.py +0 -94
- anydi/_scanner.py +0 -171
- {anydi-0.34.0.dist-info → anydi-0.34.1.dist-info}/LICENSE +0 -0
- {anydi-0.34.0.dist-info → anydi-0.34.1.dist-info}/WHEEL +0 -0
- {anydi-0.34.0.dist-info → anydi-0.34.1.dist-info}/entry_points.txt +0 -0
anydi/_scanner.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import importlib
|
|
4
|
-
import inspect
|
|
5
|
-
import pkgutil
|
|
6
|
-
from collections.abc import Iterable
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from types import ModuleType
|
|
9
|
-
from typing import (
|
|
10
|
-
TYPE_CHECKING,
|
|
11
|
-
Any,
|
|
12
|
-
Callable,
|
|
13
|
-
TypeVar,
|
|
14
|
-
Union,
|
|
15
|
-
cast,
|
|
16
|
-
final,
|
|
17
|
-
overload,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
from typing_extensions import NamedTuple, ParamSpec
|
|
21
|
-
|
|
22
|
-
from ._types import is_marker
|
|
23
|
-
from ._utils import get_typed_parameters
|
|
24
|
-
|
|
25
|
-
if TYPE_CHECKING:
|
|
26
|
-
from ._container import Container
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
T = TypeVar("T")
|
|
30
|
-
P = ParamSpec("P")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@dataclass(frozen=True)
|
|
34
|
-
class Dependency:
|
|
35
|
-
member: Any
|
|
36
|
-
module: ModuleType
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@final
|
|
40
|
-
class Scanner:
|
|
41
|
-
"""A class for scanning packages or modules for decorated objects
|
|
42
|
-
and injecting dependencies."""
|
|
43
|
-
|
|
44
|
-
def __init__(self, container: Container) -> None:
|
|
45
|
-
self.container = container
|
|
46
|
-
|
|
47
|
-
def scan(
|
|
48
|
-
self,
|
|
49
|
-
/,
|
|
50
|
-
packages: ModuleType | str | Iterable[ModuleType | str],
|
|
51
|
-
*,
|
|
52
|
-
tags: Iterable[str] | None = None,
|
|
53
|
-
) -> None:
|
|
54
|
-
"""Scan packages or modules for decorated members and inject dependencies."""
|
|
55
|
-
dependencies: list[Dependency] = []
|
|
56
|
-
|
|
57
|
-
if isinstance(packages, Iterable) and not isinstance(packages, str):
|
|
58
|
-
scan_packages: Iterable[ModuleType | str] = packages
|
|
59
|
-
else:
|
|
60
|
-
scan_packages = cast(Iterable[Union[ModuleType, str]], [packages])
|
|
61
|
-
|
|
62
|
-
for package in scan_packages:
|
|
63
|
-
dependencies.extend(self._scan_package(package, tags=tags))
|
|
64
|
-
|
|
65
|
-
for dependency in dependencies:
|
|
66
|
-
decorator = self.container.inject()(dependency.member)
|
|
67
|
-
setattr(dependency.module, dependency.member.__name__, decorator)
|
|
68
|
-
|
|
69
|
-
def _scan_package(
|
|
70
|
-
self,
|
|
71
|
-
package: ModuleType | str,
|
|
72
|
-
*,
|
|
73
|
-
tags: Iterable[str] | None = None,
|
|
74
|
-
) -> list[Dependency]:
|
|
75
|
-
"""Scan a package or module for decorated members."""
|
|
76
|
-
tags = tags or []
|
|
77
|
-
if isinstance(package, str):
|
|
78
|
-
package = importlib.import_module(package)
|
|
79
|
-
|
|
80
|
-
package_path = getattr(package, "__path__", None)
|
|
81
|
-
|
|
82
|
-
if not package_path:
|
|
83
|
-
return self._scan_module(package, tags=tags)
|
|
84
|
-
|
|
85
|
-
dependencies: list[Dependency] = []
|
|
86
|
-
|
|
87
|
-
for module_info in pkgutil.walk_packages(
|
|
88
|
-
path=package_path, prefix=package.__name__ + "."
|
|
89
|
-
):
|
|
90
|
-
module = importlib.import_module(module_info.name)
|
|
91
|
-
dependencies.extend(self._scan_module(module, tags=tags))
|
|
92
|
-
|
|
93
|
-
return dependencies
|
|
94
|
-
|
|
95
|
-
def _scan_module(
|
|
96
|
-
self, module: ModuleType, *, tags: Iterable[str]
|
|
97
|
-
) -> list[Dependency]:
|
|
98
|
-
"""Scan a module for decorated members."""
|
|
99
|
-
dependencies: list[Dependency] = []
|
|
100
|
-
|
|
101
|
-
for _, member in inspect.getmembers(module):
|
|
102
|
-
if getattr(member, "__module__", None) != module.__name__ or not callable(
|
|
103
|
-
member
|
|
104
|
-
):
|
|
105
|
-
continue
|
|
106
|
-
|
|
107
|
-
decorator_args: InjectDecoratorArgs = getattr(
|
|
108
|
-
member,
|
|
109
|
-
"__injectable__",
|
|
110
|
-
InjectDecoratorArgs(wrapped=False, tags=[]),
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
if tags and (
|
|
114
|
-
decorator_args.tags
|
|
115
|
-
and not set(decorator_args.tags).intersection(tags)
|
|
116
|
-
or not decorator_args.tags
|
|
117
|
-
):
|
|
118
|
-
continue
|
|
119
|
-
|
|
120
|
-
if decorator_args.wrapped:
|
|
121
|
-
dependencies.append(
|
|
122
|
-
self._create_dependency(member=member, module=module)
|
|
123
|
-
)
|
|
124
|
-
continue
|
|
125
|
-
|
|
126
|
-
# Get by Marker
|
|
127
|
-
for parameter in get_typed_parameters(member):
|
|
128
|
-
if is_marker(parameter.default):
|
|
129
|
-
dependencies.append(
|
|
130
|
-
self._create_dependency(member=member, module=module)
|
|
131
|
-
)
|
|
132
|
-
continue
|
|
133
|
-
|
|
134
|
-
return dependencies
|
|
135
|
-
|
|
136
|
-
def _create_dependency(self, member: Any, module: ModuleType) -> Dependency:
|
|
137
|
-
"""Create a `Dependency` object from the scanned member and module."""
|
|
138
|
-
if hasattr(member, "__wrapped__"):
|
|
139
|
-
member = member.__wrapped__
|
|
140
|
-
return Dependency(member=member, module=module)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class InjectDecoratorArgs(NamedTuple):
|
|
144
|
-
wrapped: bool
|
|
145
|
-
tags: Iterable[str] | None
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
@overload
|
|
149
|
-
def injectable(func: Callable[P, T]) -> Callable[P, T]: ...
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
@overload
|
|
153
|
-
def injectable(
|
|
154
|
-
*, tags: Iterable[str] | None = None
|
|
155
|
-
) -> Callable[[Callable[P, T]], Callable[P, T]]: ...
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def injectable(
|
|
159
|
-
func: Callable[P, T] | None = None,
|
|
160
|
-
tags: Iterable[str] | None = None,
|
|
161
|
-
) -> Callable[[Callable[P, T]], Callable[P, T]] | Callable[P, T]:
|
|
162
|
-
"""Decorator for marking a function or method as requiring dependency injection."""
|
|
163
|
-
|
|
164
|
-
def decorator(inner: Callable[P, T]) -> Callable[P, T]:
|
|
165
|
-
setattr(inner, "__injectable__", InjectDecoratorArgs(wrapped=True, tags=tags))
|
|
166
|
-
return inner
|
|
167
|
-
|
|
168
|
-
if func is None:
|
|
169
|
-
return decorator
|
|
170
|
-
|
|
171
|
-
return decorator(func)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|