anydi 0.27.1__py3-none-any.whl → 0.29.0__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/_context.py +16 -0
- anydi/ext/django/_utils.py +48 -35
- anydi/ext/pydantic_settings.py +48 -0
- {anydi-0.27.1.dist-info → anydi-0.29.0.dist-info}/METADATA +2 -2
- {anydi-0.27.1.dist-info → anydi-0.29.0.dist-info}/RECORD +8 -7
- {anydi-0.27.1.dist-info → anydi-0.29.0.dist-info}/LICENSE +0 -0
- {anydi-0.27.1.dist-info → anydi-0.29.0.dist-info}/WHEEL +0 -0
- {anydi-0.27.1.dist-info → anydi-0.29.0.dist-info}/entry_points.txt +0 -0
anydi/_context.py
CHANGED
|
@@ -195,6 +195,14 @@ class ResourceScopedContext(ScopedContext):
|
|
|
195
195
|
"""
|
|
196
196
|
return interface in self._instances
|
|
197
197
|
|
|
198
|
+
def _create_instance(self, provider: Provider) -> Any:
|
|
199
|
+
"""Create an instance using the provider."""
|
|
200
|
+
instance = super()._create_instance(provider)
|
|
201
|
+
# Enter the context manager if the instance is closable.
|
|
202
|
+
if hasattr(instance, "__enter__") and hasattr(instance, "__exit__"):
|
|
203
|
+
self._stack.enter_context(instance)
|
|
204
|
+
return instance
|
|
205
|
+
|
|
198
206
|
def _create_resource(self, provider: Provider) -> Any:
|
|
199
207
|
"""Create a resource using the provider.
|
|
200
208
|
|
|
@@ -208,6 +216,14 @@ class ResourceScopedContext(ScopedContext):
|
|
|
208
216
|
cm = contextlib.contextmanager(provider.obj)(*args, **kwargs)
|
|
209
217
|
return self._stack.enter_context(cm)
|
|
210
218
|
|
|
219
|
+
async def _acreate_instance(self, provider: Provider) -> Any:
|
|
220
|
+
"""Create an instance asynchronously using the provider."""
|
|
221
|
+
instance = await super()._acreate_instance(provider)
|
|
222
|
+
# Enter the context manager if the instance is closable.
|
|
223
|
+
if hasattr(instance, "__aenter__") and hasattr(instance, "__aexit__"):
|
|
224
|
+
await self._async_stack.enter_async_context(instance)
|
|
225
|
+
return instance
|
|
226
|
+
|
|
211
227
|
async def _acreate_resource(self, provider: Provider) -> Any:
|
|
212
228
|
"""Create a resource asynchronously using the provider.
|
|
213
229
|
|
anydi/ext/django/_utils.py
CHANGED
|
@@ -11,16 +11,17 @@ from django.db.backends.base.base import BaseDatabaseWrapper
|
|
|
11
11
|
from django.urls import URLPattern, URLResolver, get_resolver
|
|
12
12
|
from typing_extensions import Annotated, get_origin
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
from anydi import Container
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def register_settings(
|
|
18
|
-
container:
|
|
18
|
+
container: Container, prefix: str = "django.conf.setting."
|
|
19
19
|
) -> None:
|
|
20
20
|
"""Register Django settings into the container."""
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
# Ensure prefix ends with a dot
|
|
23
|
+
if prefix[-1] != ".":
|
|
24
|
+
prefix += "."
|
|
24
25
|
|
|
25
26
|
for setting_name in dir(settings):
|
|
26
27
|
setting_value = getattr(settings, setting_name)
|
|
@@ -33,38 +34,11 @@ def register_settings(
|
|
|
33
34
|
scope="singleton",
|
|
34
35
|
)
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def wrapper(interface: Any) -> Any:
|
|
39
|
-
return resolve(_aware_settings(interface, prefix))
|
|
40
|
-
|
|
41
|
-
return wrapper
|
|
42
|
-
|
|
43
|
-
def _aresolve(resolve: Any) -> Any:
|
|
44
|
-
@wraps(resolve)
|
|
45
|
-
async def wrapper(interface: Any) -> Any:
|
|
46
|
-
return await resolve(_aware_settings(interface, prefix))
|
|
47
|
-
|
|
48
|
-
return wrapper
|
|
37
|
+
# Patch AnyDI to resolve Any types for annotated settings
|
|
38
|
+
_patch_any_typed_annotated(container, prefix=prefix)
|
|
49
39
|
|
|
50
|
-
# Patch resolvers
|
|
51
|
-
container.resolve = _resolve(container.resolve) # type: ignore[method-assign] # noqa
|
|
52
|
-
container.aresolve = _aresolve(container.aresolve) # type: ignore[method-assign] # noqa
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
def _aware_settings(interface: Any, prefix: str) -> Any:
|
|
56
|
-
origin = get_origin(interface)
|
|
57
|
-
if origin is not Annotated:
|
|
58
|
-
return interface # pragma: no cover
|
|
59
|
-
named = interface.__metadata__[-1]
|
|
60
|
-
|
|
61
|
-
if isinstance(named, str) and named.startswith(prefix):
|
|
62
|
-
_, setting_name = named.rsplit(prefix, maxsplit=1)
|
|
63
|
-
return Annotated[Any, f"{prefix}{setting_name}"]
|
|
64
|
-
return interface
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def register_components(container: anydi.Container) -> None:
|
|
41
|
+
def register_components(container: Container) -> None:
|
|
68
42
|
"""Register Django components into the container."""
|
|
69
43
|
|
|
70
44
|
# Register caches
|
|
@@ -90,7 +64,7 @@ def register_components(container: anydi.Container) -> None:
|
|
|
90
64
|
)
|
|
91
65
|
|
|
92
66
|
|
|
93
|
-
def inject_urlpatterns(container:
|
|
67
|
+
def inject_urlpatterns(container: Container, *, urlconf: str) -> None:
|
|
94
68
|
"""Auto-inject the container into views."""
|
|
95
69
|
resolver = get_resolver(urlconf)
|
|
96
70
|
for pattern in iter_urlpatterns(resolver.url_patterns):
|
|
@@ -113,3 +87,42 @@ def iter_urlpatterns(
|
|
|
113
87
|
yield from iter_urlpatterns(url_pattern.url_patterns)
|
|
114
88
|
else:
|
|
115
89
|
yield url_pattern
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _get_setting_value(value: Any) -> Any:
|
|
93
|
+
return lambda: value
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _any_typed_interface(interface: Any, prefix: str) -> Any:
|
|
97
|
+
origin = get_origin(interface)
|
|
98
|
+
if origin is not Annotated:
|
|
99
|
+
return interface # pragma: no cover
|
|
100
|
+
named = interface.__metadata__[-1]
|
|
101
|
+
|
|
102
|
+
if isinstance(named, str) and named.startswith(prefix):
|
|
103
|
+
_, setting_name = named.rsplit(prefix, maxsplit=1)
|
|
104
|
+
return Annotated[Any, f"{prefix}{setting_name}"]
|
|
105
|
+
return interface
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _patch_any_typed_annotated(container: Container, *, prefix: str) -> None:
|
|
109
|
+
def _patch_resolve(resolve: Any) -> Any:
|
|
110
|
+
@wraps(resolve)
|
|
111
|
+
def wrapper(interface: Any) -> Any:
|
|
112
|
+
return resolve(_any_typed_interface(interface, prefix))
|
|
113
|
+
|
|
114
|
+
return wrapper
|
|
115
|
+
|
|
116
|
+
def _patch_aresolve(resolve: Any) -> Any:
|
|
117
|
+
@wraps(resolve)
|
|
118
|
+
async def wrapper(interface: Any) -> Any:
|
|
119
|
+
return await resolve(_any_typed_interface(interface, prefix))
|
|
120
|
+
|
|
121
|
+
return wrapper
|
|
122
|
+
|
|
123
|
+
container.resolve = _patch_resolve( # type: ignore[method-assign]
|
|
124
|
+
container.resolve
|
|
125
|
+
)
|
|
126
|
+
container.aresolve = _patch_aresolve( # type: ignore[method-assign]
|
|
127
|
+
container.aresolve
|
|
128
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, Iterable
|
|
4
|
+
|
|
5
|
+
from pydantic.fields import ComputedFieldInfo, FieldInfo # noqa
|
|
6
|
+
from pydantic_settings import BaseSettings
|
|
7
|
+
from typing_extensions import Annotated
|
|
8
|
+
|
|
9
|
+
from anydi import Container
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def install(
|
|
13
|
+
settings: BaseSettings | Iterable[BaseSettings],
|
|
14
|
+
container: Container,
|
|
15
|
+
*,
|
|
16
|
+
prefix: str = ".settings",
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Install Pydantic settings into an AnyDI container."""
|
|
19
|
+
|
|
20
|
+
# Ensure prefix ends with a dot
|
|
21
|
+
if prefix[-1] != ".":
|
|
22
|
+
prefix += "."
|
|
23
|
+
|
|
24
|
+
def _register_settings(_settings: BaseSettings) -> None:
|
|
25
|
+
all_fields = {**_settings.model_fields, **_settings.model_computed_fields}
|
|
26
|
+
for setting_name, field_info in all_fields.items():
|
|
27
|
+
if isinstance(field_info, ComputedFieldInfo):
|
|
28
|
+
interface = field_info.return_type
|
|
29
|
+
elif isinstance(field_info, FieldInfo):
|
|
30
|
+
interface = field_info.annotation
|
|
31
|
+
else:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
container.register(
|
|
35
|
+
Annotated[interface, f"{prefix}{setting_name}"],
|
|
36
|
+
_get_setting_value(getattr(_settings, setting_name)),
|
|
37
|
+
scope="singleton",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if isinstance(settings, BaseSettings):
|
|
41
|
+
_register_settings(settings)
|
|
42
|
+
else:
|
|
43
|
+
for _settings in settings:
|
|
44
|
+
_register_settings(_settings)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _get_setting_value(setting_value: Any) -> Callable[[], Any]:
|
|
48
|
+
return lambda: setting_value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anydi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.29.0
|
|
4
4
|
Summary: Dependency Injection library
|
|
5
5
|
Home-page: https://github.com/antonrh/anydi
|
|
6
6
|
License: MIT
|
|
@@ -32,7 +32,7 @@ Provides-Extra: async
|
|
|
32
32
|
Provides-Extra: docs
|
|
33
33
|
Requires-Dist: anyio (>=3.6.2,<4.0.0) ; extra == "async"
|
|
34
34
|
Requires-Dist: mkdocs (>=1.4.2,<2.0.0) ; extra == "docs"
|
|
35
|
-
Requires-Dist: mkdocs-material (>=9.5.
|
|
35
|
+
Requires-Dist: mkdocs-material (>=9.5.29,<10.0.0) ; extra == "docs"
|
|
36
36
|
Requires-Dist: typing-extensions (>=4.12.1,<5.0.0)
|
|
37
37
|
Project-URL: Repository, https://github.com/antonrh/anydi
|
|
38
38
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
|
|
2
2
|
anydi/_container.py,sha256=-vpiYl2Tx2QK9wl74DiF5qLFRudJ3e78TqEyuyOrthE,29055
|
|
3
|
-
anydi/_context.py,sha256=
|
|
3
|
+
anydi/_context.py,sha256=Wm4DT8Ie_TPchWmIBe8Q9f90dQrGd5lY8H5K85rStgY,12706
|
|
4
4
|
anydi/_logger.py,sha256=UpubJUnW83kffFxkhUlObm2DmZX1Pjqoz9YFKS-JOPg,52
|
|
5
5
|
anydi/_module.py,sha256=E1TfLud_Af-MPB83PxIzHVA1jlDW2FGaRP_il1a6y3Y,3675
|
|
6
6
|
anydi/_scanner.py,sha256=cyEk-K2Q8ssZStq8GrxMeEcCuAZMw-RXrjlgWEevKCs,6667
|
|
@@ -11,7 +11,7 @@ anydi/ext/_utils.py,sha256=2kxLPTMM9Ro3s6-knbqYzONlqRB3hMcwZFFRQGHcFUg,2691
|
|
|
11
11
|
anydi/ext/django/__init__.py,sha256=QI1IABCVgSDTUoh7M9WMECKXwB3xvh04HfQ9TOWw1Mk,223
|
|
12
12
|
anydi/ext/django/_container.py,sha256=cxVoYQG16WP0S_Yv4TnLwuaaT7NVEOhLWO-YdALJUb4,418
|
|
13
13
|
anydi/ext/django/_settings.py,sha256=cKzFBGtPCsexZ2ZcInubBukIebhxzNfa3F0KuwoZYaA,844
|
|
14
|
-
anydi/ext/django/_utils.py,sha256=
|
|
14
|
+
anydi/ext/django/_utils.py,sha256=E0GGxsEJiSJsA4-8AcEwfdUi_iK7qGpKfGNRDKmDqEg,3976
|
|
15
15
|
anydi/ext/django/apps.py,sha256=-gj_tqb6goeYMNItr6nwWHYXZwDOdiH8anby0YwnUmw,2866
|
|
16
16
|
anydi/ext/django/middleware.py,sha256=iVHWtE829khMY-BXbNNt0g2FrIApKprna7dCG9ObEis,823
|
|
17
17
|
anydi/ext/django/ninja/__init__.py,sha256=kW3grUgWp_nkWSG_-39ADHMrZLGNcj9TsJ9OW8iWWrk,546
|
|
@@ -19,12 +19,13 @@ anydi/ext/django/ninja/_operation.py,sha256=wSWa7D73XTVlOibmOciv2l6JHPe1ERZcXrqI
|
|
|
19
19
|
anydi/ext/django/ninja/_signature.py,sha256=2cSzKxBIxXLqtwNuH6GSlmjVJFftoGmleWfyk_NVEWw,2207
|
|
20
20
|
anydi/ext/fastapi.py,sha256=vhfSyovXuCjvSkx6AiLOTNU975i8wDg72C5fqXQiFLw,2896
|
|
21
21
|
anydi/ext/faststream.py,sha256=L4rkWYIO4ZZuWH-8M8NT6_J0bT0Dz_EWO3B6Oj1iFBI,2024
|
|
22
|
+
anydi/ext/pydantic_settings.py,sha256=UwJWByusXLKvlIp5gBHslgUom2bK93QZwwFhJgzY1gg,1490
|
|
22
23
|
anydi/ext/pytest_plugin.py,sha256=3OWphc4nEzla46_8KR7LXtwGns5eol_YlUWfTf4Cr2Q,3952
|
|
23
24
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
25
|
anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
|
|
25
26
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
anydi-0.
|
|
27
|
-
anydi-0.
|
|
28
|
-
anydi-0.
|
|
29
|
-
anydi-0.
|
|
30
|
-
anydi-0.
|
|
27
|
+
anydi-0.29.0.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
28
|
+
anydi-0.29.0.dist-info/METADATA,sha256=HgsJLUAb-SP361yfEM5mI4Y7Q6MWNiA2sL1m1RIccl4,5111
|
|
29
|
+
anydi-0.29.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
30
|
+
anydi-0.29.0.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
|
|
31
|
+
anydi-0.29.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|