anydi 0.25.0a0__py3-none-any.whl → 0.25.0a1__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 +2 -2
- anydi/_container.py +2 -2
- anydi/_scanner.py +2 -2
- anydi/_types.py +9 -1
- anydi/ext/django/apps.py +54 -15
- anydi/ext/django/ninja/__init__.py +1 -1
- anydi/ext/django/ninja/_signature.py +2 -2
- {anydi-0.25.0a0.dist-info → anydi-0.25.0a1.dist-info}/METADATA +3 -3
- {anydi-0.25.0a0.dist-info → anydi-0.25.0a1.dist-info}/RECORD +12 -12
- {anydi-0.25.0a0.dist-info → anydi-0.25.0a1.dist-info}/LICENSE +0 -0
- {anydi-0.25.0a0.dist-info → anydi-0.25.0a1.dist-info}/WHEEL +0 -0
- {anydi-0.25.0a0.dist-info → anydi-0.25.0a1.dist-info}/entry_points.txt +0 -0
anydi/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AnyDI public objects and functions."""
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any, cast
|
|
4
4
|
|
|
5
5
|
from ._container import Container, request, singleton, transient
|
|
6
6
|
from ._module import Module, provider
|
|
@@ -14,7 +14,7 @@ def dep() -> Any:
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
# Alias for dependency auto marker
|
|
17
|
-
auto =
|
|
17
|
+
auto = cast(Any, Marker())
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
__all__ = [
|
anydi/_container.py
CHANGED
|
@@ -47,7 +47,7 @@ from ._context import (
|
|
|
47
47
|
from ._logger import logger
|
|
48
48
|
from ._module import Module, ModuleRegistry
|
|
49
49
|
from ._scanner import Scanner
|
|
50
|
-
from ._types import AnyInterface, Interface,
|
|
50
|
+
from ._types import AnyInterface, Interface, Provider, Scope, is_marker
|
|
51
51
|
from ._utils import get_full_qualname, get_signature, is_builtin_type
|
|
52
52
|
|
|
53
53
|
T = TypeVar("T", bound=Any)
|
|
@@ -760,7 +760,7 @@ class Container:
|
|
|
760
760
|
"""
|
|
761
761
|
injected_params = {}
|
|
762
762
|
for parameter in get_signature(obj).parameters.values():
|
|
763
|
-
if not
|
|
763
|
+
if not is_marker(parameter.default):
|
|
764
764
|
continue
|
|
765
765
|
try:
|
|
766
766
|
self._validate_injected_parameter(obj, parameter)
|
anydi/_scanner.py
CHANGED
|
@@ -21,7 +21,7 @@ from typing import (
|
|
|
21
21
|
|
|
22
22
|
from typing_extensions import NamedTuple, ParamSpec
|
|
23
23
|
|
|
24
|
-
from ._types import
|
|
24
|
+
from ._types import is_marker
|
|
25
25
|
from ._utils import get_signature
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
@@ -163,7 +163,7 @@ class Scanner:
|
|
|
163
163
|
else:
|
|
164
164
|
signature = get_signature(member)
|
|
165
165
|
for parameter in signature.parameters.values():
|
|
166
|
-
if
|
|
166
|
+
if is_marker(parameter.default):
|
|
167
167
|
dependencies.append(
|
|
168
168
|
self._create_dependency(member=member, module=module)
|
|
169
169
|
)
|
anydi/_types.py
CHANGED
|
@@ -3,7 +3,7 @@ from dataclasses import dataclass
|
|
|
3
3
|
from functools import cached_property
|
|
4
4
|
from typing import Any, Callable, Type, TypeVar, Union
|
|
5
5
|
|
|
6
|
-
from typing_extensions import Annotated, Literal, Mapping, TypeAlias
|
|
6
|
+
from typing_extensions import Annotated, Literal, Mapping, Self, TypeAlias
|
|
7
7
|
|
|
8
8
|
from ._utils import get_full_qualname, get_signature
|
|
9
9
|
|
|
@@ -19,6 +19,14 @@ class Marker:
|
|
|
19
19
|
|
|
20
20
|
__slots__ = ()
|
|
21
21
|
|
|
22
|
+
def __call__(self) -> Self:
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_marker(obj: Any) -> bool:
|
|
27
|
+
"""Checks if an object is a marker."""
|
|
28
|
+
return isinstance(obj, Marker)
|
|
29
|
+
|
|
22
30
|
|
|
23
31
|
@dataclass(frozen=True)
|
|
24
32
|
class Provider:
|
anydi/ext/django/apps.py
CHANGED
|
@@ -1,35 +1,53 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import types
|
|
3
|
+
from asyncio import get_running_loop
|
|
2
4
|
from functools import wraps
|
|
3
|
-
from typing import
|
|
5
|
+
from typing import Any, Callable, cast
|
|
4
6
|
|
|
5
7
|
from django.apps import AppConfig
|
|
6
8
|
from django.conf import settings
|
|
7
9
|
from django.core.cache import BaseCache, caches
|
|
10
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
8
11
|
from django.db import connections
|
|
9
12
|
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
10
13
|
from django.urls import get_resolver
|
|
11
14
|
from django.utils.module_loading import import_string
|
|
15
|
+
from typing_extensions import Annotated, get_origin
|
|
12
16
|
|
|
13
17
|
import anydi
|
|
14
18
|
|
|
15
19
|
from ._utils import iter_urlpatterns
|
|
16
20
|
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
17
23
|
|
|
18
24
|
class ContainerConfig(AppConfig): # type: ignore[misc]
|
|
19
25
|
name = "anydi.ext.django"
|
|
20
26
|
label = "anydi_django"
|
|
21
27
|
|
|
22
28
|
# Prefix for Django settings
|
|
23
|
-
settings_prefix = "django.conf.settings"
|
|
29
|
+
settings_prefix = "django.conf.settings."
|
|
24
30
|
|
|
25
31
|
def __init__(self, app_name: str, app_module: types.ModuleType | None) -> None:
|
|
26
32
|
super().__init__(app_name, app_module)
|
|
27
33
|
# Create a container
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
container_getter_path = getattr(settings, "ANYDI_CONTAINER_GETTER", None)
|
|
35
|
+
if container_getter_path:
|
|
36
|
+
try:
|
|
37
|
+
container_getter = cast(
|
|
38
|
+
Callable[[], anydi.Container], import_string(container_getter_path)
|
|
39
|
+
)
|
|
40
|
+
except ImportError as exc:
|
|
41
|
+
raise ImproperlyConfigured(
|
|
42
|
+
f"Cannot import container getter '{container_getter_path}'."
|
|
43
|
+
) from exc
|
|
44
|
+
self.container = container_getter()
|
|
45
|
+
else:
|
|
46
|
+
self.container = anydi.Container(
|
|
47
|
+
strict=getattr(settings, "ANYDI_STRICT_MODE", False),
|
|
48
|
+
)
|
|
31
49
|
|
|
32
|
-
def ready(self) -> None:
|
|
50
|
+
def ready(self) -> None: # noqa: C901
|
|
33
51
|
# Register Django settings
|
|
34
52
|
if getattr(settings, "ANYDI_REGISTER_SETTINGS", False):
|
|
35
53
|
self.register_settings()
|
|
@@ -40,7 +58,12 @@ class ContainerConfig(AppConfig): # type: ignore[misc]
|
|
|
40
58
|
|
|
41
59
|
# Register modules
|
|
42
60
|
for module_path in getattr(settings, "ANYDI_MODULES", []):
|
|
43
|
-
|
|
61
|
+
try:
|
|
62
|
+
module_cls = import_string(module_path)
|
|
63
|
+
except ImportError as exc:
|
|
64
|
+
raise ImproperlyConfigured(
|
|
65
|
+
f"Cannot import module '{module_path}'."
|
|
66
|
+
) from exc
|
|
44
67
|
self.container.register_module(module_cls)
|
|
45
68
|
|
|
46
69
|
# Patching the django-ninja framework if it installed
|
|
@@ -51,30 +74,47 @@ class ContainerConfig(AppConfig): # type: ignore[misc]
|
|
|
51
74
|
if urlconf := getattr(settings, "ANYDI_AUTO_INJECT_URLCONF", None):
|
|
52
75
|
self.auto_inject_urlconf(urlconf)
|
|
53
76
|
|
|
77
|
+
# Scan packages
|
|
78
|
+
for scan_package in getattr(settings, "ANYDI_SCAN_PACKAGES", []):
|
|
79
|
+
self.container.scan(scan_package)
|
|
80
|
+
|
|
81
|
+
# Start the container
|
|
82
|
+
if getattr(settings, "ANYDI_START_CONTAINER", False):
|
|
83
|
+
try:
|
|
84
|
+
get_running_loop()
|
|
85
|
+
except RuntimeError:
|
|
86
|
+
logger.warning(
|
|
87
|
+
"Starting the container is only supported in an async context."
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
self.container.start()
|
|
91
|
+
|
|
54
92
|
def register_settings(self) -> None: # noqa: C901
|
|
55
93
|
"""Register Django settings into the container."""
|
|
56
94
|
|
|
57
95
|
def _get_setting_value(value: Any) -> Any:
|
|
58
96
|
return lambda: value
|
|
59
97
|
|
|
60
|
-
for setting_name
|
|
98
|
+
for setting_name in dir(settings):
|
|
99
|
+
setting_value = getattr(settings, setting_name)
|
|
61
100
|
if not setting_name.isupper():
|
|
62
101
|
continue
|
|
102
|
+
|
|
63
103
|
self.container.register(
|
|
64
|
-
Annotated[Any, f"{self.settings_prefix}
|
|
65
|
-
_get_setting_value(
|
|
104
|
+
Annotated[Any, f"{self.settings_prefix}{setting_name}"],
|
|
105
|
+
_get_setting_value(setting_value),
|
|
66
106
|
scope="singleton",
|
|
67
107
|
)
|
|
68
108
|
|
|
69
109
|
def _aware_settings(interface: Any) -> Any:
|
|
70
110
|
origin = get_origin(interface)
|
|
71
111
|
if origin is not Annotated:
|
|
72
|
-
return interface
|
|
112
|
+
return interface # pragma: no cover
|
|
73
113
|
named = interface.__metadata__[-1]
|
|
74
114
|
|
|
75
|
-
if isinstance(named, str):
|
|
115
|
+
if isinstance(named, str) and named.startswith(self.settings_prefix):
|
|
76
116
|
_, setting_name = named.rsplit(self.settings_prefix, maxsplit=1)
|
|
77
|
-
return Annotated[Any, f"{self.settings_prefix}
|
|
117
|
+
return Annotated[Any, f"{self.settings_prefix}{setting_name}"]
|
|
78
118
|
return interface
|
|
79
119
|
|
|
80
120
|
def _resolve(resolve: Any) -> Any:
|
|
@@ -110,7 +150,6 @@ class ContainerConfig(AppConfig): # type: ignore[misc]
|
|
|
110
150
|
)
|
|
111
151
|
|
|
112
152
|
# Register database connections
|
|
113
|
-
|
|
114
153
|
def _get_connection(alias: str) -> Any:
|
|
115
154
|
return lambda: connections[alias]
|
|
116
155
|
|
|
@@ -127,7 +166,7 @@ class ContainerConfig(AppConfig): # type: ignore[misc]
|
|
|
127
166
|
for pattern in iter_urlpatterns(resolver.url_patterns):
|
|
128
167
|
# Skip django-ninja views
|
|
129
168
|
if pattern.lookup_str.startswith("ninja."):
|
|
130
|
-
continue
|
|
169
|
+
continue # pragma: no cover
|
|
131
170
|
pattern.callback = self.container.inject(pattern.callback)
|
|
132
171
|
|
|
133
172
|
@staticmethod
|
|
@@ -3,8 +3,8 @@ from collections.abc import Callable
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from django.http import HttpResponse
|
|
6
|
-
from ninja.signature.details import (
|
|
7
|
-
FuncParam,
|
|
6
|
+
from ninja.signature.details import (
|
|
7
|
+
FuncParam, # noqa
|
|
8
8
|
ViewSignature as BaseViewSignature,
|
|
9
9
|
)
|
|
10
10
|
from ninja.signature.utils import get_path_param_names, get_typed_signature
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anydi
|
|
3
|
-
Version: 0.25.
|
|
3
|
+
Version: 0.25.0a1
|
|
4
4
|
Summary: Dependency Injection library
|
|
5
5
|
Home-page: https://github.com/antonrh/anydi
|
|
6
6
|
License: MIT
|
|
@@ -89,7 +89,7 @@ pip install anydi
|
|
|
89
89
|
*app.py*
|
|
90
90
|
|
|
91
91
|
```python
|
|
92
|
-
from anydi import
|
|
92
|
+
from anydi import auto, Container
|
|
93
93
|
|
|
94
94
|
container = Container()
|
|
95
95
|
|
|
@@ -100,7 +100,7 @@ def message() -> str:
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
@container.inject
|
|
103
|
-
def say_hello(message: str =
|
|
103
|
+
def say_hello(message: str = auto) -> None:
|
|
104
104
|
print(message)
|
|
105
105
|
|
|
106
106
|
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
anydi/__init__.py,sha256=
|
|
2
|
-
anydi/_container.py,sha256=
|
|
1
|
+
anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
|
|
2
|
+
anydi/_container.py,sha256=LeGrujx8zMzBuR8PD7qNqVJmmLB-frAG74gihX0lxNc,28341
|
|
3
3
|
anydi/_context.py,sha256=btGJzvTMkj5v95rAw6kjOclISKcSugC4wzrHlWlCk_I,10258
|
|
4
4
|
anydi/_logger.py,sha256=UpubJUnW83kffFxkhUlObm2DmZX1Pjqoz9YFKS-JOPg,52
|
|
5
5
|
anydi/_module.py,sha256=1fBo9-RWxo7TeyP0Y2uJokT-NXP2pjik6CXNoeo3l-8,3712
|
|
6
|
-
anydi/_scanner.py,sha256=
|
|
7
|
-
anydi/_types.py,sha256=
|
|
6
|
+
anydi/_scanner.py,sha256=9S3XbNVFAnHClT3FBo2CWeDBzCLG58i93a1ZJgaMNIo,6775
|
|
7
|
+
anydi/_types.py,sha256=TfqJ7TfudOzGMG4_OliAMMJplu42mXZcZmgmtK2oz14,3412
|
|
8
8
|
anydi/_utils.py,sha256=haRwC6YTTFf6CNTfwsRQ4NZsNByoUkEmE4-rh1-VYLs,3152
|
|
9
9
|
anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
anydi/ext/django/__init__.py,sha256=wsFBQP2j76Ui_0SJlN_8LKhZvEEdxA-w_yoyRAcaM58,59
|
|
11
11
|
anydi/ext/django/_container.py,sha256=cxVoYQG16WP0S_Yv4TnLwuaaT7NVEOhLWO-YdALJUb4,418
|
|
12
12
|
anydi/ext/django/_utils.py,sha256=C-1UabpwgCHUryAT-Pv8vU5QFfBahQlqhjecvihjtgY,430
|
|
13
|
-
anydi/ext/django/apps.py,sha256=
|
|
14
|
-
anydi/ext/django/ninja/__init__.py,sha256=
|
|
13
|
+
anydi/ext/django/apps.py,sha256=qjzKqYIB00qjsSv2RQNVnFMi0lCljmaGtMIy3JMAE0U,6326
|
|
14
|
+
anydi/ext/django/ninja/__init__.py,sha256=FckjVqzXTzlBllFg2PZ62wi432-ydZFyWq6ZkF2LJ9I,540
|
|
15
15
|
anydi/ext/django/ninja/_operation.py,sha256=A_RbMbJyVaafoeBhZpmPQ96l1RQFLA1FchkJC_uRKnM,2660
|
|
16
|
-
anydi/ext/django/ninja/_signature.py,sha256=
|
|
16
|
+
anydi/ext/django/ninja/_signature.py,sha256=kdPU0QL3_oloWi43ehi2QJVn_WaRm1klZ6D7sA-SQYo,2177
|
|
17
17
|
anydi/ext/fastapi.py,sha256=zKuo7nNpcMXppUsime5LLKTkAiNrlEtcLRFK4FRur0c,5311
|
|
18
18
|
anydi/ext/pytest_plugin.py,sha256=tmncz2IbIR7FGlgmAtcf00yDKg9SQP9lCFnJBmtHx3A,3976
|
|
19
19
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
20
|
anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
|
|
21
21
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
anydi-0.25.
|
|
23
|
-
anydi-0.25.
|
|
24
|
-
anydi-0.25.
|
|
25
|
-
anydi-0.25.
|
|
26
|
-
anydi-0.25.
|
|
22
|
+
anydi-0.25.0a1.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
23
|
+
anydi-0.25.0a1.dist-info/METADATA,sha256=WvjurCb1o4pBgxTvNh-7KY3-6qocjK0euML7cVagy2E,4373
|
|
24
|
+
anydi-0.25.0a1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
25
|
+
anydi-0.25.0a1.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
|
|
26
|
+
anydi-0.25.0a1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|