anydi 0.46.0__py3-none-any.whl → 0.47.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/__init__.py +5 -3
- anydi/_container.py +46 -14
- anydi/_typing.py +41 -28
- anydi/ext/django/ninja/_signature.py +2 -2
- anydi/ext/fastapi.py +10 -12
- anydi/ext/faststream.py +6 -8
- {anydi-0.46.0.dist-info → anydi-0.47.0.dist-info}/METADATA +1 -1
- {anydi-0.46.0.dist-info → anydi-0.47.0.dist-info}/RECORD +11 -12
- anydi/ext/_utils.py +0 -77
- {anydi-0.46.0.dist-info → anydi-0.47.0.dist-info}/WHEEL +0 -0
- {anydi-0.46.0.dist-info → anydi-0.47.0.dist-info}/entry_points.txt +0 -0
- {anydi-0.46.0.dist-info → anydi-0.47.0.dist-info}/licenses/LICENSE +0 -0
anydi/__init__.py
CHANGED
|
@@ -5,22 +5,24 @@ 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 Inject
|
|
9
9
|
|
|
10
10
|
# Alias for dependency auto marker
|
|
11
|
-
|
|
11
|
+
# TODO: deprecate it
|
|
12
|
+
auto = Inject()
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
__all__ = [
|
|
15
16
|
"Container",
|
|
17
|
+
"Inject",
|
|
16
18
|
"Module",
|
|
17
19
|
"Provider",
|
|
18
20
|
"Scope",
|
|
19
21
|
"auto",
|
|
20
22
|
"injectable",
|
|
23
|
+
"provided",
|
|
21
24
|
"provider",
|
|
22
25
|
"request",
|
|
23
26
|
"singleton",
|
|
24
27
|
"transient",
|
|
25
|
-
"provided",
|
|
26
28
|
]
|
anydi/_container.py
CHANGED
|
@@ -11,7 +11,7 @@ import uuid
|
|
|
11
11
|
from collections import defaultdict
|
|
12
12
|
from collections.abc import AsyncIterator, Iterable, Iterator
|
|
13
13
|
from contextvars import ContextVar
|
|
14
|
-
from typing import Any, Callable, TypeVar, cast, overload
|
|
14
|
+
from typing import Annotated, Any, Callable, TypeVar, cast, overload
|
|
15
15
|
|
|
16
16
|
from typing_extensions import ParamSpec, Self, get_args, get_origin
|
|
17
17
|
|
|
@@ -806,36 +806,68 @@ 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
|
-
interface, should_inject = self.
|
|
809
|
+
interface, should_inject = self.validate_injected_parameter(
|
|
810
810
|
parameter, call=call
|
|
811
811
|
)
|
|
812
812
|
if should_inject:
|
|
813
813
|
injected_params[parameter.name] = interface
|
|
814
814
|
return injected_params
|
|
815
815
|
|
|
816
|
-
|
|
816
|
+
@staticmethod
|
|
817
|
+
def _unwrap_injected_parameter(parameter: inspect.Parameter) -> inspect.Parameter:
|
|
818
|
+
if get_origin(parameter.annotation) is not Annotated:
|
|
819
|
+
return parameter
|
|
820
|
+
|
|
821
|
+
origin, *metadata = get_args(parameter.annotation)
|
|
822
|
+
|
|
823
|
+
if not metadata or not is_inject_marker(metadata[-1]):
|
|
824
|
+
return parameter
|
|
825
|
+
|
|
826
|
+
if is_inject_marker(parameter.default):
|
|
827
|
+
raise TypeError(
|
|
828
|
+
"Cannot specify `Inject` in `Annotated` and "
|
|
829
|
+
f"default value together for '{parameter.name}'"
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
if parameter.default is not inspect.Parameter.empty:
|
|
833
|
+
return parameter
|
|
834
|
+
|
|
835
|
+
marker = metadata[-1]
|
|
836
|
+
new_metadata = metadata[:-1]
|
|
837
|
+
if new_metadata:
|
|
838
|
+
new_annotation = Annotated.__class_getitem__((origin, *new_metadata)) # type: ignore
|
|
839
|
+
else:
|
|
840
|
+
new_annotation = origin
|
|
841
|
+
return parameter.replace(annotation=new_annotation, default=marker)
|
|
842
|
+
|
|
843
|
+
def validate_injected_parameter(
|
|
817
844
|
self, parameter: inspect.Parameter, *, call: Callable[..., Any]
|
|
818
845
|
) -> tuple[Any, bool]:
|
|
819
846
|
"""Validate an injected parameter."""
|
|
820
|
-
|
|
821
|
-
|
|
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
|
|
847
|
+
parameter = self._unwrap_injected_parameter(parameter)
|
|
848
|
+
interface = parameter.annotation
|
|
828
849
|
|
|
829
|
-
|
|
850
|
+
if not is_inject_marker(parameter.default):
|
|
851
|
+
return interface, False
|
|
830
852
|
|
|
831
|
-
|
|
832
|
-
|
|
853
|
+
if interface is inspect.Parameter.empty:
|
|
854
|
+
raise TypeError(
|
|
855
|
+
f"Missing `{type_repr(call)}` parameter `{parameter.name}` annotation."
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
# Set inject marker interface
|
|
859
|
+
parameter.default.interface = interface
|
|
860
|
+
|
|
861
|
+
# TODO: temporary disable until strict is enforced (remove False)
|
|
862
|
+
if False and not self.has_provider_for(interface):
|
|
833
863
|
raise LookupError(
|
|
834
864
|
f"`{type_repr(call)}` has an unknown dependency parameter "
|
|
835
865
|
f"`{parameter.name}` with an annotation of "
|
|
836
866
|
f"`{type_repr(interface)}`."
|
|
837
867
|
)
|
|
838
868
|
|
|
869
|
+
return interface, True
|
|
870
|
+
|
|
839
871
|
############################
|
|
840
872
|
# Module Methods
|
|
841
873
|
############################
|
anydi/_typing.py
CHANGED
|
@@ -7,9 +7,9 @@ import inspect
|
|
|
7
7
|
import re
|
|
8
8
|
import sys
|
|
9
9
|
from collections.abc import AsyncIterator, Iterator
|
|
10
|
-
from typing import Any, Callable, ForwardRef
|
|
10
|
+
from typing import Any, Callable, ForwardRef, TypeVar
|
|
11
11
|
|
|
12
|
-
from typing_extensions import
|
|
12
|
+
from typing_extensions import get_args, get_origin
|
|
13
13
|
|
|
14
14
|
try:
|
|
15
15
|
from types import NoneType
|
|
@@ -17,6 +17,9 @@ except ImportError:
|
|
|
17
17
|
NoneType = type(None)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
T = TypeVar("T")
|
|
21
|
+
|
|
22
|
+
|
|
20
23
|
def type_repr(obj: Any) -> str:
|
|
21
24
|
"""Get a string representation of a type or object."""
|
|
22
25
|
if isinstance(obj, str):
|
|
@@ -93,48 +96,58 @@ def get_typed_parameters(obj: Callable[..., Any]) -> list[inspect.Parameter]:
|
|
|
93
96
|
]
|
|
94
97
|
|
|
95
98
|
|
|
96
|
-
class
|
|
97
|
-
|
|
99
|
+
class _Sentinel:
|
|
100
|
+
__slots__ = ("_name",)
|
|
98
101
|
|
|
99
|
-
|
|
102
|
+
def __init__(self, name: str) -> None:
|
|
103
|
+
self._name = name
|
|
100
104
|
|
|
101
|
-
def
|
|
102
|
-
return self
|
|
105
|
+
def __repr__(self) -> str:
|
|
106
|
+
return f"<{self._name}>"
|
|
103
107
|
|
|
108
|
+
def __eq__(self, other: object) -> bool:
|
|
109
|
+
return self is other
|
|
104
110
|
|
|
105
|
-
def
|
|
106
|
-
|
|
111
|
+
def __hash__(self) -> int:
|
|
112
|
+
return id(self)
|
|
107
113
|
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
return isinstance(obj, _InjectMarker)
|
|
115
|
+
NOT_SET = _Sentinel("NOT_SET")
|
|
111
116
|
|
|
112
117
|
|
|
113
|
-
class
|
|
114
|
-
"""
|
|
118
|
+
class InjectMarker:
|
|
119
|
+
"""A marker object for declaring injectable dependencies."""
|
|
115
120
|
|
|
116
|
-
__slots__ = ()
|
|
121
|
+
__slots__ = ("_interface",)
|
|
117
122
|
|
|
123
|
+
def __init__(self, interface: Any = NOT_SET) -> None:
|
|
124
|
+
self._interface = interface
|
|
118
125
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
@property
|
|
127
|
+
def interface(self) -> Any:
|
|
128
|
+
if self._interface is NOT_SET:
|
|
129
|
+
raise TypeError("Interface is not set.")
|
|
130
|
+
return self._interface
|
|
122
131
|
|
|
132
|
+
@interface.setter
|
|
133
|
+
def interface(self, interface: Any) -> None:
|
|
134
|
+
self._interface = interface
|
|
123
135
|
|
|
124
|
-
class _Sentinel:
|
|
125
|
-
__slots__ = ("_name",)
|
|
126
136
|
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
def is_inject_marker(obj: Any) -> bool:
|
|
138
|
+
return isinstance(obj, InjectMarker)
|
|
129
139
|
|
|
130
|
-
def __repr__(self) -> str:
|
|
131
|
-
return f"<{self._name}>"
|
|
132
140
|
|
|
133
|
-
|
|
134
|
-
|
|
141
|
+
def Inject() -> Any:
|
|
142
|
+
return InjectMarker()
|
|
135
143
|
|
|
136
|
-
def __hash__(self) -> int:
|
|
137
|
-
return id(self)
|
|
138
144
|
|
|
145
|
+
class Event:
|
|
146
|
+
"""Represents an event object."""
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
__slots__ = ()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def is_event_type(obj: Any) -> bool:
|
|
152
|
+
"""Checks if an object is an event type."""
|
|
153
|
+
return inspect.isclass(obj) and issubclass(obj, Event)
|
|
@@ -46,11 +46,11 @@ class ViewSignature(BaseViewSignature):
|
|
|
46
46
|
self.response_arg = name
|
|
47
47
|
continue
|
|
48
48
|
|
|
49
|
-
interface, should_inject = container.
|
|
49
|
+
interface, should_inject = container.validate_injected_parameter(
|
|
50
50
|
arg, call=self.view_func
|
|
51
51
|
)
|
|
52
52
|
if should_inject:
|
|
53
|
-
self.dependencies.append((name,
|
|
53
|
+
self.dependencies.append((name, interface))
|
|
54
54
|
continue
|
|
55
55
|
|
|
56
56
|
func_param = self._get_param_type(name, arg)
|
anydi/ext/fastapi.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from collections.abc import Iterator
|
|
6
|
-
from typing import Any, cast
|
|
6
|
+
from typing import Annotated, Any, cast
|
|
7
7
|
|
|
8
8
|
from fastapi import Depends, FastAPI, params
|
|
9
9
|
from fastapi.dependencies.models import Dependant
|
|
@@ -11,9 +11,8 @@ from fastapi.routing import APIRoute
|
|
|
11
11
|
from starlette.requests import Request
|
|
12
12
|
|
|
13
13
|
from anydi._container import Container
|
|
14
|
-
from anydi._typing import get_typed_parameters
|
|
14
|
+
from anydi._typing import InjectMarker, get_typed_parameters
|
|
15
15
|
|
|
16
|
-
from ._utils import HasInterface, patch_call_parameter
|
|
17
16
|
from .starlette.middleware import RequestScopedMiddleware
|
|
18
17
|
|
|
19
18
|
__all__ = ["RequestScopedMiddleware", "install", "get_container", "Inject"]
|
|
@@ -41,7 +40,7 @@ def install(app: FastAPI, container: Container) -> None:
|
|
|
41
40
|
if not call:
|
|
42
41
|
continue # pragma: no cover
|
|
43
42
|
for parameter in get_typed_parameters(call):
|
|
44
|
-
|
|
43
|
+
container.validate_injected_parameter(parameter, call=call)
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
def get_container(request: Request) -> Container:
|
|
@@ -49,20 +48,19 @@ def get_container(request: Request) -> Container:
|
|
|
49
48
|
return cast(Container, request.app.state.container)
|
|
50
49
|
|
|
51
50
|
|
|
52
|
-
class
|
|
53
|
-
"""Parameter dependency class for injecting dependencies using AnyDI."""
|
|
54
|
-
|
|
51
|
+
class _Inject(params.Depends, InjectMarker):
|
|
55
52
|
def __init__(self) -> None:
|
|
56
53
|
super().__init__(dependency=self._dependency, use_cache=True)
|
|
57
|
-
|
|
54
|
+
InjectMarker.__init__(self)
|
|
58
55
|
|
|
59
|
-
async def _dependency(
|
|
56
|
+
async def _dependency(
|
|
57
|
+
self, container: Annotated[Container, Depends(get_container)]
|
|
58
|
+
) -> Any:
|
|
60
59
|
return await container.aresolve(self.interface)
|
|
61
60
|
|
|
62
61
|
|
|
63
|
-
def Inject() -> Any:
|
|
64
|
-
|
|
65
|
-
return Resolver()
|
|
62
|
+
def Inject() -> Any:
|
|
63
|
+
return _Inject()
|
|
66
64
|
|
|
67
65
|
|
|
68
66
|
def _iter_dependencies(dependant: Dependant) -> Iterator[Dependant]:
|
anydi/ext/faststream.py
CHANGED
|
@@ -9,9 +9,7 @@ from faststream import ContextRepo
|
|
|
9
9
|
from faststream.broker.core.usecase import BrokerUsecase
|
|
10
10
|
|
|
11
11
|
from anydi import Container
|
|
12
|
-
from anydi._typing import get_typed_parameters
|
|
13
|
-
|
|
14
|
-
from ._utils import HasInterface, patch_call_parameter
|
|
12
|
+
from anydi._typing import InjectMarker, get_typed_parameters
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
def install(broker: BrokerUsecase[Any, Any], container: Container) -> None:
|
|
@@ -26,7 +24,7 @@ def install(broker: BrokerUsecase[Any, Any], container: Container) -> None:
|
|
|
26
24
|
for handler in _get_broken_handlers(broker):
|
|
27
25
|
call = handler._original_call # noqa
|
|
28
26
|
for parameter in get_typed_parameters(call):
|
|
29
|
-
|
|
27
|
+
container.validate_injected_parameter(parameter, call=call)
|
|
30
28
|
|
|
31
29
|
|
|
32
30
|
def _get_broken_handlers(broker: BrokerUsecase[Any, Any]) -> list[Any]:
|
|
@@ -43,17 +41,17 @@ def get_container(broker: BrokerUsecase[Any, Any]) -> Container:
|
|
|
43
41
|
return cast(Container, getattr(broker, "_container")) # noqa
|
|
44
42
|
|
|
45
43
|
|
|
46
|
-
class
|
|
44
|
+
class _Inject(Depends, InjectMarker):
|
|
47
45
|
"""Parameter dependency class for injecting dependencies using AnyDI."""
|
|
48
46
|
|
|
49
47
|
def __init__(self) -> None:
|
|
50
48
|
super().__init__(dependency=self._dependency, use_cache=True, cast=True)
|
|
51
|
-
|
|
49
|
+
InjectMarker.__init__(self)
|
|
52
50
|
|
|
53
51
|
async def _dependency(self, context: ContextRepo) -> Any:
|
|
54
52
|
container = get_container(context.get("broker"))
|
|
55
53
|
return await container.aresolve(self.interface)
|
|
56
54
|
|
|
57
55
|
|
|
58
|
-
def Inject() -> Any:
|
|
59
|
-
return
|
|
56
|
+
def Inject() -> Any:
|
|
57
|
+
return _Inject()
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
anydi/__init__.py,sha256=
|
|
1
|
+
anydi/__init__.py,sha256=KjjYm-1yAFxiPYaMs1WRJMtxE0q_vdX7ZRLQR1fFGs8,567
|
|
2
2
|
anydi/_async.py,sha256=KhRd3RmZFcwNDzrMm8ctA1gwrg-6m_7laECTYsZdF5k,1445
|
|
3
|
-
anydi/_container.py,sha256=
|
|
3
|
+
anydi/_container.py,sha256=Ug0TVOuNQ1cpwUQiHSNtAiZB-qJHv8ECd89WcK6ZwWg,32350
|
|
4
4
|
anydi/_context.py,sha256=_Xy8cTpRskb4cxTd-Fe-5NnIZyBe1DnovkofhdeUfmw,3020
|
|
5
5
|
anydi/_decorators.py,sha256=F3yBeGQSz1EsulZaEvYn3cd6FEjJRMoyA6u1QCbEwcs,2813
|
|
6
6
|
anydi/_module.py,sha256=QPvP27JndZkwl-FYUZWscJm6yfkNzjwoFGURyDhb6Pc,2582
|
|
7
7
|
anydi/_provider.py,sha256=ig2ecn-STmFGcpkLE5A5OM35XHtU2NsxFVrGp2CvuvM,2123
|
|
8
8
|
anydi/_scan.py,sha256=nOpspmceVucdwf8nUv1QVFsz2sRVWCVUb0QTH9EbWr4,3653
|
|
9
9
|
anydi/_scope.py,sha256=PFHjPb2-n0vhRo9mvD_craTFfoJBzR3y-N3_0apL5Q0,258
|
|
10
|
-
anydi/_typing.py,sha256=
|
|
10
|
+
anydi/_typing.py,sha256=7Nhg4ezPgvFmdGOd2SI_9y5iQv8j-QkNOohXRGNAaIE,4057
|
|
11
11
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
anydi/testing.py,sha256=ex9grqKpQmmJWwhIVnzq6aHaUAGLu2-7fwLyYTUuKHE,5678
|
|
13
13
|
anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
anydi/ext/
|
|
15
|
-
anydi/ext/
|
|
16
|
-
anydi/ext/faststream.py,sha256=Ewfj9hXbCSr5x7QWoLEORmc3uPcbr7PEcCcG1wM-6XM,1946
|
|
14
|
+
anydi/ext/fastapi.py,sha256=L9VGPHGy23se1sflmJqTE7LNfQuElVdYEogoT1f5-4A,2324
|
|
15
|
+
anydi/ext/faststream.py,sha256=Dy81Vf34CP6pEIbZ-41vh_-Dn6Qc-rcf14U5poebjxI,1905
|
|
17
16
|
anydi/ext/pydantic_settings.py,sha256=8IXXLuG_OvKbvKlBkBRQUHcXgbTpgQUxeWyoMcRIUQM,1488
|
|
18
17
|
anydi/ext/pytest_plugin.py,sha256=IoP6XKuGLGLd2Xlpfttc3mI4pxCm2WQLE7x_a7asbv4,4732
|
|
19
18
|
anydi/ext/django/__init__.py,sha256=QI1IABCVgSDTUoh7M9WMECKXwB3xvh04HfQ9TOWw1Mk,223
|
|
@@ -24,11 +23,11 @@ anydi/ext/django/apps.py,sha256=YLL1uU6dSQ3uf3GB0VHzPW_eLuB1j9h6pv8EdAutMqo,2725
|
|
|
24
23
|
anydi/ext/django/middleware.py,sha256=5OUdp0OWRozyW338Sq04BDhacaFlyUTTOduS_7EwCTA,854
|
|
25
24
|
anydi/ext/django/ninja/__init__.py,sha256=4J0zoHPK9itbTVrjjvLX6Ftrsb2ND8bITqNDIJzEhks,520
|
|
26
25
|
anydi/ext/django/ninja/_operation.py,sha256=wk5EOjLY3KVIHk9jMCGsFsja9-dQmMOpLpHXciqxQdk,2680
|
|
27
|
-
anydi/ext/django/ninja/_signature.py,sha256=
|
|
26
|
+
anydi/ext/django/ninja/_signature.py,sha256=p7JtyMdFhX4fWQOvAhvZNss6iURNERcdsTsQADTHkMY,2358
|
|
28
27
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
28
|
anydi/ext/starlette/middleware.py,sha256=MxnzshAs-CMvjJp0r457k52MzBL8O4KAuClnF6exBdU,803
|
|
30
|
-
anydi-0.
|
|
31
|
-
anydi-0.
|
|
32
|
-
anydi-0.
|
|
33
|
-
anydi-0.
|
|
34
|
-
anydi-0.
|
|
29
|
+
anydi-0.47.0.dist-info/METADATA,sha256=PBlr12YCEaTNpURekET6v25gNR9mixOyyYqtVW3y75E,4957
|
|
30
|
+
anydi-0.47.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
31
|
+
anydi-0.47.0.dist-info/entry_points.txt,sha256=Nklo9f3Oe4AkNsEgC4g43nCJ-23QDngZSVDNRMdaILI,43
|
|
32
|
+
anydi-0.47.0.dist-info/licenses/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
33
|
+
anydi-0.47.0.dist-info/RECORD,,
|
anydi/ext/_utils.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
"""AnyDI FastAPI extension."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import inspect
|
|
6
|
-
import logging
|
|
7
|
-
from typing import Annotated, Any, Callable
|
|
8
|
-
|
|
9
|
-
from typing_extensions import get_args, get_origin
|
|
10
|
-
|
|
11
|
-
from anydi import Container
|
|
12
|
-
from anydi._typing import _InjectMarker
|
|
13
|
-
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class HasInterface(_InjectMarker):
|
|
18
|
-
__slots__ = ("_interface",)
|
|
19
|
-
|
|
20
|
-
def __init__(self, interface: Any = None) -> None:
|
|
21
|
-
self._interface = interface
|
|
22
|
-
|
|
23
|
-
@property
|
|
24
|
-
def interface(self) -> Any:
|
|
25
|
-
if self._interface is None:
|
|
26
|
-
raise TypeError("Interface is not set.")
|
|
27
|
-
return self._interface
|
|
28
|
-
|
|
29
|
-
@interface.setter
|
|
30
|
-
def interface(self, interface: Any) -> None:
|
|
31
|
-
self._interface = interface
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def patch_annotated_parameter(parameter: inspect.Parameter) -> inspect.Parameter:
|
|
35
|
-
"""Patch an annotated parameter to resolve the default value."""
|
|
36
|
-
if not (
|
|
37
|
-
get_origin(parameter.annotation) is Annotated
|
|
38
|
-
and parameter.default is inspect.Parameter.empty
|
|
39
|
-
):
|
|
40
|
-
return parameter
|
|
41
|
-
|
|
42
|
-
tp_origin, *tp_metadata = get_args(parameter.annotation)
|
|
43
|
-
default = tp_metadata[-1]
|
|
44
|
-
|
|
45
|
-
if not isinstance(default, HasInterface):
|
|
46
|
-
return parameter
|
|
47
|
-
|
|
48
|
-
if (num := len(tp_metadata[:-1])) == 0:
|
|
49
|
-
interface = tp_origin
|
|
50
|
-
elif num == 1:
|
|
51
|
-
interface = Annotated[tp_origin, tp_metadata[0]]
|
|
52
|
-
elif num == 2:
|
|
53
|
-
interface = Annotated[tp_origin, tp_metadata[0], tp_metadata[1]]
|
|
54
|
-
elif num == 3:
|
|
55
|
-
interface = Annotated[
|
|
56
|
-
tp_origin,
|
|
57
|
-
tp_metadata[0],
|
|
58
|
-
tp_metadata[1],
|
|
59
|
-
tp_metadata[2],
|
|
60
|
-
]
|
|
61
|
-
else:
|
|
62
|
-
raise TypeError("Too many annotated arguments.") # pragma: no cover
|
|
63
|
-
return parameter.replace(annotation=interface, default=default)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def patch_call_parameter(
|
|
67
|
-
container: Container, call: Callable[..., Any], parameter: inspect.Parameter
|
|
68
|
-
) -> None:
|
|
69
|
-
"""Patch a parameter to inject dependencies using AnyDI."""
|
|
70
|
-
parameter = patch_annotated_parameter(parameter)
|
|
71
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|