anydi 0.45.1__tar.gz → 0.46.0rc1__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.
- {anydi-0.45.1 → anydi-0.46.0rc1}/PKG-INFO +1 -1
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/__init__.py +2 -2
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_container.py +20 -15
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_scan.py +2 -2
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_typing.py +6 -7
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/_utils.py +13 -9
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/ninja/_signature.py +6 -3
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/fastapi.py +2 -1
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/faststream.py +2 -1
- {anydi-0.45.1 → anydi-0.46.0rc1}/pyproject.toml +2 -2
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/fastapi/test_ext.py +0 -1
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/faststream/test_ext.py +0 -1
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/test_container.py +1 -2
- {anydi-0.45.1 → anydi-0.46.0rc1}/uv.lock +1 -1
- {anydi-0.45.1 → anydi-0.46.0rc1}/.editorconfig +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/.github/workflows/ci.yml +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/.gitignore +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/.readthedocs.yaml +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/LICENSE +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/Makefile +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/README.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_async.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_context.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_decorators.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_module.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_provider.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/_scope.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/_container.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/_settings.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/_utils.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/apps.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/middleware.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/ninja/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/django/ninja/_operation.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/pydantic_settings.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/pytest_plugin.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/starlette/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/ext/starlette/middleware.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/py.typed +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/anydi/testing.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/examples/basic.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/extensions/django.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/extensions/fastapi.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/extensions/faststream.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/extensions/pydantic_settings.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/index.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/docs/usage.md +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/mkdocs.yml +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/conftest.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/api/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/api/router.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/api/test_router.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/api/urls.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/conftest.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/container.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/scan/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/services.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/settings.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/test_views.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/urls.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/django/views.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/fastapi/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/fastapi/app.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/fastapi/conftest.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/fastapi/test_routes.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/faststream/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/faststream/test_subscribers.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/fixtures.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/starlette/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/starlette/app.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/starlette/conftest.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/starlette/test_routes.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/test_pydantic.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/ext/test_pytest_plugin.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/fixtures.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a1/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a1/handlers.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a2/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a2/a21/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a2/a21/handlers.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a3/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/a/a3/handlers.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/b/__init__.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/scan_app/b/handlers.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/test_decorators.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/test_module.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/test_scan.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/test_testing.py +0 -0
- {anydi-0.45.1 → anydi-0.46.0rc1}/tests/test_utils.py +0 -0
|
@@ -5,10 +5,10 @@ from ._decorators import injectable, provided, provider, request, singleton, tra
|
|
|
5
5
|
from ._module import Module
|
|
6
6
|
from ._provider import ProviderDef as Provider
|
|
7
7
|
from ._scope import Scope
|
|
8
|
-
from ._typing import
|
|
8
|
+
from ._typing import InjectMarker
|
|
9
9
|
|
|
10
10
|
# Alias for dependency auto marker
|
|
11
|
-
auto =
|
|
11
|
+
auto = InjectMarker()
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
@@ -31,8 +31,8 @@ from ._typing import (
|
|
|
31
31
|
is_builtin_type,
|
|
32
32
|
is_context_manager,
|
|
33
33
|
is_event_type,
|
|
34
|
+
is_inject_marker,
|
|
34
35
|
is_iterator_type,
|
|
35
|
-
is_marker,
|
|
36
36
|
is_none_type,
|
|
37
37
|
type_repr,
|
|
38
38
|
)
|
|
@@ -806,29 +806,34 @@ class Container:
|
|
|
806
806
|
"""Get the injected parameters of a callable object."""
|
|
807
807
|
injected_params: dict[str, Any] = {}
|
|
808
808
|
for parameter in get_typed_parameters(call):
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
809
|
+
interface, should_inject = self._validate_injected_parameter(
|
|
810
|
+
parameter, call=call
|
|
811
|
+
)
|
|
812
|
+
if should_inject:
|
|
813
|
+
injected_params[parameter.name] = interface
|
|
813
814
|
return injected_params
|
|
814
815
|
|
|
815
816
|
def _validate_injected_parameter(
|
|
816
|
-
self, call: Callable[..., Any]
|
|
817
|
-
) ->
|
|
817
|
+
self, parameter: inspect.Parameter, *, call: Callable[..., Any]
|
|
818
|
+
) -> tuple[Any, bool]:
|
|
818
819
|
"""Validate an injected parameter."""
|
|
819
|
-
|
|
820
|
-
|
|
820
|
+
interface, should_inject = parameter.annotation, False
|
|
821
|
+
if is_inject_marker(parameter.default):
|
|
822
|
+
if parameter.annotation is inspect.Parameter.empty:
|
|
823
|
+
raise TypeError(
|
|
824
|
+
f"Missing `{type_repr(call)}` "
|
|
825
|
+
f"parameter `{parameter.name}` annotation."
|
|
826
|
+
)
|
|
827
|
+
should_inject = True
|
|
821
828
|
|
|
822
|
-
|
|
823
|
-
raise TypeError(
|
|
824
|
-
f"Missing `{type_repr(call)}` parameter `{parameter.name}` annotation."
|
|
825
|
-
)
|
|
829
|
+
return interface, should_inject
|
|
826
830
|
|
|
827
|
-
|
|
831
|
+
# TODO: temporary disable until strict is enforced
|
|
832
|
+
if not self.has_provider_for(interface):
|
|
828
833
|
raise LookupError(
|
|
829
834
|
f"`{type_repr(call)}` has an unknown dependency parameter "
|
|
830
835
|
f"`{parameter.name}` with an annotation of "
|
|
831
|
-
f"`{type_repr(
|
|
836
|
+
f"`{type_repr(interface)}`."
|
|
832
837
|
)
|
|
833
838
|
|
|
834
839
|
############################
|
|
@@ -9,7 +9,7 @@ from types import ModuleType
|
|
|
9
9
|
from typing import TYPE_CHECKING, Any, Callable, Union
|
|
10
10
|
|
|
11
11
|
from ._decorators import is_injectable
|
|
12
|
-
from ._typing import get_typed_parameters,
|
|
12
|
+
from ._typing import get_typed_parameters, is_inject_marker
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from ._container import Container
|
|
@@ -104,7 +104,7 @@ class Scanner:
|
|
|
104
104
|
# check for parameter markers
|
|
105
105
|
if not tags:
|
|
106
106
|
for param in get_typed_parameters(member):
|
|
107
|
-
if
|
|
107
|
+
if is_inject_marker(param.default):
|
|
108
108
|
return True
|
|
109
109
|
|
|
110
110
|
return False
|
|
@@ -93,8 +93,8 @@ def get_typed_parameters(obj: Callable[..., Any]) -> list[inspect.Parameter]:
|
|
|
93
93
|
]
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
class
|
|
97
|
-
"""A marker
|
|
96
|
+
class _InjectMarker:
|
|
97
|
+
"""A marker object for declaring injectable dependencies."""
|
|
98
98
|
|
|
99
99
|
__slots__ = ()
|
|
100
100
|
|
|
@@ -102,13 +102,12 @@ class _Marker:
|
|
|
102
102
|
return self
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
def
|
|
106
|
-
return
|
|
105
|
+
def InjectMarker() -> Any:
|
|
106
|
+
return _InjectMarker()
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
def
|
|
110
|
-
|
|
111
|
-
return isinstance(obj, _Marker)
|
|
109
|
+
def is_inject_marker(obj: Any) -> bool:
|
|
110
|
+
return isinstance(obj, _InjectMarker)
|
|
112
111
|
|
|
113
112
|
|
|
114
113
|
class Event:
|
|
@@ -8,13 +8,17 @@ from typing import Annotated, Any, Callable
|
|
|
8
8
|
|
|
9
9
|
from typing_extensions import get_args, get_origin
|
|
10
10
|
|
|
11
|
-
from anydi
|
|
11
|
+
from anydi import Container
|
|
12
|
+
from anydi._typing import _InjectMarker
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
class HasInterface:
|
|
17
|
-
|
|
17
|
+
class HasInterface(_InjectMarker):
|
|
18
|
+
__slots__ = ("_interface",)
|
|
19
|
+
|
|
20
|
+
def __init__(self, interface: Any = None) -> None:
|
|
21
|
+
self._interface = interface
|
|
18
22
|
|
|
19
23
|
@property
|
|
20
24
|
def interface(self) -> Any:
|
|
@@ -65,9 +69,9 @@ def patch_call_parameter(
|
|
|
65
69
|
"""Patch a parameter to inject dependencies using AnyDI."""
|
|
66
70
|
parameter = patch_annotated_parameter(parameter)
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
interface, should_inject = container._validate_injected_parameter(
|
|
73
|
+
parameter, call=call
|
|
74
|
+
) # noqa
|
|
75
|
+
if should_inject:
|
|
76
|
+
parameter.default.interface = interface
|
|
77
|
+
return None
|
|
@@ -11,7 +11,8 @@ from ninja.signature.details import (
|
|
|
11
11
|
)
|
|
12
12
|
from ninja.signature.utils import get_path_param_names, get_typed_signature
|
|
13
13
|
|
|
14
|
-
from anydi._typing import
|
|
14
|
+
from anydi._typing import is_inject_marker # noqa
|
|
15
|
+
from anydi.ext.django import container
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class ViewSignature(BaseViewSignature):
|
|
@@ -45,8 +46,10 @@ class ViewSignature(BaseViewSignature):
|
|
|
45
46
|
self.response_arg = name
|
|
46
47
|
continue
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
interface, should_inject = container._validate_injected_parameter(
|
|
50
|
+
arg, call=self.view_func
|
|
51
|
+
)
|
|
52
|
+
if should_inject:
|
|
50
53
|
self.dependencies.append((name, arg.annotation))
|
|
51
54
|
continue
|
|
52
55
|
|
|
@@ -49,11 +49,12 @@ def get_container(request: Request) -> Container:
|
|
|
49
49
|
return cast(Container, request.app.state.container)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
class Resolver(
|
|
52
|
+
class Resolver(params.Depends, HasInterface):
|
|
53
53
|
"""Parameter dependency class for injecting dependencies using AnyDI."""
|
|
54
54
|
|
|
55
55
|
def __init__(self) -> None:
|
|
56
56
|
super().__init__(dependency=self._dependency, use_cache=True)
|
|
57
|
+
HasInterface.__init__(self)
|
|
57
58
|
|
|
58
59
|
async def _dependency(self, container: Container = Depends(get_container)) -> Any:
|
|
59
60
|
return await container.aresolve(self.interface)
|
|
@@ -43,11 +43,12 @@ def get_container(broker: BrokerUsecase[Any, Any]) -> Container:
|
|
|
43
43
|
return cast(Container, getattr(broker, "_container")) # noqa
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
class Resolver(
|
|
46
|
+
class Resolver(Depends, HasInterface):
|
|
47
47
|
"""Parameter dependency class for injecting dependencies using AnyDI."""
|
|
48
48
|
|
|
49
49
|
def __init__(self) -> None:
|
|
50
50
|
super().__init__(dependency=self._dependency, use_cache=True, cast=True)
|
|
51
|
+
HasInterface.__init__(self)
|
|
51
52
|
|
|
52
53
|
async def _dependency(self, context: ContextRepo) -> Any:
|
|
53
54
|
container = get_container(context.get("broker"))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "anydi"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.46.0rc1"
|
|
4
4
|
description = "Dependency Injection library"
|
|
5
5
|
authors = [{ name = "Anton Ruhlov", email = "antonruhlov@gmail.com" }]
|
|
6
6
|
requires-python = "~=3.9"
|
|
@@ -137,7 +137,7 @@ omit = [
|
|
|
137
137
|
]
|
|
138
138
|
|
|
139
139
|
[tool.bumpversion]
|
|
140
|
-
current_version = "0.
|
|
140
|
+
current_version = "0.46.0rc1"
|
|
141
141
|
parse = """(?x)
|
|
142
142
|
(?P<major>0|[1-9]\\d*)\\.
|
|
143
143
|
(?P<minor>0|[1-9]\\d*)\\.
|
|
@@ -1420,7 +1420,6 @@ class TestContainerInjector:
|
|
|
1420
1420
|
|
|
1421
1421
|
assert result == "service ident = 1000"
|
|
1422
1422
|
|
|
1423
|
-
@pytest.mark.skip(reason="disable until strict is enforced")
|
|
1424
1423
|
def test_inject_missing_annotation(self, container: Container) -> None:
|
|
1425
1424
|
def handler(name=auto) -> str: # type: ignore
|
|
1426
1425
|
return name # type: ignore
|
|
@@ -1431,7 +1430,7 @@ class TestContainerInjector:
|
|
|
1431
1430
|
container.inject(handler)
|
|
1432
1431
|
|
|
1433
1432
|
@pytest.mark.skip(reason="disable until strict is enforced")
|
|
1434
|
-
def
|
|
1433
|
+
def test_inject_unknown_dependency(self) -> None:
|
|
1435
1434
|
container = Container()
|
|
1436
1435
|
|
|
1437
1436
|
def handler(message: str = auto) -> None:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|