anydi 0.38.0__py3-none-any.whl → 0.38.2rc0__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 +1 -2
- anydi/_container.py +414 -270
- anydi/_types.py +80 -2
- anydi/ext/pytest_plugin.py +6 -21
- {anydi-0.38.0.dist-info → anydi-0.38.2rc0.dist-info}/METADATA +1 -1
- {anydi-0.38.0.dist-info → anydi-0.38.2rc0.dist-info}/RECORD +9 -10
- anydi/_provider.py +0 -232
- {anydi-0.38.0.dist-info → anydi-0.38.2rc0.dist-info}/WHEEL +0 -0
- {anydi-0.38.0.dist-info → anydi-0.38.2rc0.dist-info}/entry_points.txt +0 -0
- {anydi-0.38.0.dist-info → anydi-0.38.2rc0.dist-info}/licenses/LICENSE +0 -0
anydi/_types.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import enum
|
|
3
4
|
import inspect
|
|
4
5
|
from collections.abc import Iterable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from functools import cached_property
|
|
5
8
|
from types import ModuleType
|
|
6
|
-
from typing import Annotated, Any, NamedTuple, Union
|
|
9
|
+
from typing import Annotated, Any, Callable, NamedTuple, Union
|
|
7
10
|
|
|
8
11
|
import wrapt
|
|
9
12
|
from typing_extensions import Literal, Self, TypeAlias
|
|
@@ -12,6 +15,8 @@ Scope = Literal["transient", "singleton", "request"]
|
|
|
12
15
|
|
|
13
16
|
AnyInterface: TypeAlias = Union[type[Any], Annotated[Any, ...]]
|
|
14
17
|
|
|
18
|
+
NOT_SET = object()
|
|
19
|
+
|
|
15
20
|
|
|
16
21
|
class Marker:
|
|
17
22
|
"""A marker class for marking dependencies."""
|
|
@@ -53,12 +58,85 @@ class InstanceProxy(wrapt.ObjectProxy): # type: ignore[misc]
|
|
|
53
58
|
return object.__getattribute__(self, item)
|
|
54
59
|
|
|
55
60
|
|
|
61
|
+
class ProviderKind(enum.IntEnum):
|
|
62
|
+
CLASS = 1
|
|
63
|
+
FUNCTION = 2
|
|
64
|
+
COROUTINE = 3
|
|
65
|
+
GENERATOR = 4
|
|
66
|
+
ASYNC_GENERATOR = 5
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def from_call(cls, call: Callable[..., Any]) -> ProviderKind:
|
|
70
|
+
if inspect.isclass(call):
|
|
71
|
+
return cls.CLASS
|
|
72
|
+
elif inspect.iscoroutinefunction(call):
|
|
73
|
+
return cls.COROUTINE
|
|
74
|
+
elif inspect.isasyncgenfunction(call):
|
|
75
|
+
return cls.ASYNC_GENERATOR
|
|
76
|
+
elif inspect.isgeneratorfunction(call):
|
|
77
|
+
return cls.GENERATOR
|
|
78
|
+
elif inspect.isfunction(call) or inspect.ismethod(call):
|
|
79
|
+
return cls.FUNCTION
|
|
80
|
+
raise TypeError(
|
|
81
|
+
f"The provider `{call}` is invalid because it is not a callable "
|
|
82
|
+
"object. Only callable providers are allowed."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass(kw_only=True, frozen=True)
|
|
87
|
+
class ProviderParameter:
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass(kw_only=True, frozen=True)
|
|
92
|
+
class Provider:
|
|
93
|
+
call: Callable[..., Any]
|
|
94
|
+
scope: Scope
|
|
95
|
+
interface: Any
|
|
96
|
+
name: str
|
|
97
|
+
parameters: list[inspect.Parameter]
|
|
98
|
+
kind: ProviderKind
|
|
99
|
+
|
|
100
|
+
def __str__(self) -> str:
|
|
101
|
+
return self.name
|
|
102
|
+
|
|
103
|
+
@cached_property
|
|
104
|
+
def is_class(self) -> bool:
|
|
105
|
+
return self.kind == ProviderKind.CLASS
|
|
106
|
+
|
|
107
|
+
@cached_property
|
|
108
|
+
def is_coroutine(self) -> bool:
|
|
109
|
+
return self.kind == ProviderKind.COROUTINE
|
|
110
|
+
|
|
111
|
+
@cached_property
|
|
112
|
+
def is_generator(self) -> bool:
|
|
113
|
+
return self.kind == ProviderKind.GENERATOR
|
|
114
|
+
|
|
115
|
+
@cached_property
|
|
116
|
+
def is_async_generator(self) -> bool:
|
|
117
|
+
return self.kind == ProviderKind.ASYNC_GENERATOR
|
|
118
|
+
|
|
119
|
+
@cached_property
|
|
120
|
+
def is_async(self) -> bool:
|
|
121
|
+
return self.is_coroutine or self.is_async_generator
|
|
122
|
+
|
|
123
|
+
@cached_property
|
|
124
|
+
def is_resource(self) -> bool:
|
|
125
|
+
return self.is_generator or self.is_async_generator
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class ProviderArgs(NamedTuple):
|
|
129
|
+
call: Callable[..., Any]
|
|
130
|
+
scope: Scope
|
|
131
|
+
interface: Any | None = None
|
|
132
|
+
|
|
133
|
+
|
|
56
134
|
class ProviderDecoratorArgs(NamedTuple):
|
|
57
135
|
scope: Scope
|
|
58
136
|
override: bool
|
|
59
137
|
|
|
60
138
|
|
|
61
|
-
class
|
|
139
|
+
class ScannedDependency(NamedTuple):
|
|
62
140
|
member: Any
|
|
63
141
|
module: ModuleType
|
|
64
142
|
|
anydi/ext/pytest_plugin.py
CHANGED
|
@@ -35,11 +35,9 @@ CONTAINER_FIXTURE_NAME = "container"
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
@pytest.fixture
|
|
38
|
-
def anydi_setup_container(
|
|
39
|
-
request: pytest.FixtureRequest,
|
|
40
|
-
) -> Iterator[Container]:
|
|
38
|
+
def anydi_setup_container(request: pytest.FixtureRequest) -> Container:
|
|
41
39
|
try:
|
|
42
|
-
|
|
40
|
+
return cast(Container, request.getfixturevalue(CONTAINER_FIXTURE_NAME))
|
|
43
41
|
except pytest.FixtureLookupError as exc:
|
|
44
42
|
exc.msg = (
|
|
45
43
|
"`container` fixture is not found. Make sure to define it in your test "
|
|
@@ -47,8 +45,6 @@ def anydi_setup_container(
|
|
|
47
45
|
)
|
|
48
46
|
raise exc
|
|
49
47
|
|
|
50
|
-
yield container
|
|
51
|
-
|
|
52
48
|
|
|
53
49
|
@pytest.fixture
|
|
54
50
|
def _anydi_should_inject(request: pytest.FixtureRequest) -> bool:
|
|
@@ -57,27 +53,20 @@ def _anydi_should_inject(request: pytest.FixtureRequest) -> bool:
|
|
|
57
53
|
return marker is not None or inject_all
|
|
58
54
|
|
|
59
55
|
|
|
60
|
-
@pytest.fixture(scope="session")
|
|
61
|
-
def _anydi_unresolved() -> Iterator[list[Any]]:
|
|
62
|
-
unresolved: list[Any] = []
|
|
63
|
-
yield unresolved
|
|
64
|
-
unresolved.clear()
|
|
65
|
-
|
|
66
|
-
|
|
67
56
|
@pytest.fixture
|
|
68
57
|
def _anydi_injected_parameter_iterator(
|
|
69
58
|
request: pytest.FixtureRequest,
|
|
70
|
-
_anydi_unresolved: list[str],
|
|
71
59
|
) -> Callable[[], Iterator[tuple[str, Any]]]:
|
|
72
|
-
|
|
60
|
+
fixturenames = set(request.node._fixtureinfo.initialnames) - set(
|
|
61
|
+
request.node._fixtureinfo.name2fixturedefs.keys()
|
|
62
|
+
)
|
|
73
63
|
|
|
74
64
|
def _iterator() -> Iterator[tuple[str, inspect.Parameter]]:
|
|
75
65
|
for parameter in get_typed_parameters(request.function):
|
|
76
66
|
interface = parameter.annotation
|
|
77
67
|
if (
|
|
78
68
|
interface is inspect.Parameter.empty
|
|
79
|
-
or
|
|
80
|
-
or parameter.name in registered_fixtures
|
|
69
|
+
or parameter.name not in fixturenames
|
|
81
70
|
):
|
|
82
71
|
continue
|
|
83
72
|
yield parameter.name, interface
|
|
@@ -90,7 +79,6 @@ def _anydi_inject(
|
|
|
90
79
|
request: pytest.FixtureRequest,
|
|
91
80
|
_anydi_should_inject: bool,
|
|
92
81
|
_anydi_injected_parameter_iterator: Callable[[], Iterator[tuple[str, Any]]],
|
|
93
|
-
_anydi_unresolved: list[str],
|
|
94
82
|
) -> None:
|
|
95
83
|
"""Inject dependencies into the test function."""
|
|
96
84
|
|
|
@@ -111,7 +99,6 @@ def _anydi_inject(
|
|
|
111
99
|
logger.warning(
|
|
112
100
|
f"Failed to resolve dependency for argument '{argname}'.", exc_info=exc
|
|
113
101
|
)
|
|
114
|
-
_anydi_unresolved.append(interface)
|
|
115
102
|
|
|
116
103
|
|
|
117
104
|
@pytest.fixture(autouse=True)
|
|
@@ -119,7 +106,6 @@ def _anydi_ainject(
|
|
|
119
106
|
request: pytest.FixtureRequest,
|
|
120
107
|
_anydi_should_inject: bool,
|
|
121
108
|
_anydi_injected_parameter_iterator: Callable[[], Iterator[tuple[str, Any]]],
|
|
122
|
-
_anydi_unresolved: list[str],
|
|
123
109
|
) -> None:
|
|
124
110
|
"""Inject dependencies into the test function."""
|
|
125
111
|
if (
|
|
@@ -149,7 +135,6 @@ def _anydi_ainject(
|
|
|
149
135
|
f"Failed to resolve dependency for argument '{argname}'.",
|
|
150
136
|
exc_info=exc,
|
|
151
137
|
)
|
|
152
|
-
_anydi_unresolved.append(interface)
|
|
153
138
|
|
|
154
139
|
anyio_backend = request.getfixturevalue("anyio_backend")
|
|
155
140
|
backend_name, backend_options = extract_backend_and_options(anyio_backend)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
anydi/__init__.py,sha256=
|
|
2
|
-
anydi/_container.py,sha256=
|
|
1
|
+
anydi/__init__.py,sha256=aAq10a1V_zQ3_Me3p_pll5d1O77PIgqotkOm3pshORI,495
|
|
2
|
+
anydi/_container.py,sha256=BqpvUPeYt6OW7TLIDm-OvMGCbcxnvXA6KyOF9XBmi7M,43072
|
|
3
3
|
anydi/_context.py,sha256=7LV_SL4QWkJeiG7_4D9PZ5lmU-MPzhofxC95zCgY9Gc,2651
|
|
4
|
-
anydi/
|
|
5
|
-
anydi/_types.py,sha256=fdO4xNXtGMxVArmlfDkFYbyR895ixkBTW6V8lMceN7Q,1562
|
|
4
|
+
anydi/_types.py,sha256=oFyx6jxkEsz5FZk6tdRjUmBBQ2tX7eA_bLaa2elq7Mg,3586
|
|
6
5
|
anydi/_utils.py,sha256=INI0jNIXrJ6LS4zqJymMO2yUEobpxmBGASf4G_vR6AU,4378
|
|
7
6
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
7
|
anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -10,7 +9,7 @@ anydi/ext/_utils.py,sha256=U6sRqWzccWUu7eMhbXX1NrwcaxitQF9cO1KxnKF37gw,2566
|
|
|
10
9
|
anydi/ext/fastapi.py,sha256=AEL3ubu-LxUPHMMt1YIn3En_JZC7nyBKmKxmhka3O3c,2436
|
|
11
10
|
anydi/ext/faststream.py,sha256=qXnNGvAqWWp9kbhbQUE6EF_OPUiYQmtOH211_O7BI_0,1898
|
|
12
11
|
anydi/ext/pydantic_settings.py,sha256=8IXXLuG_OvKbvKlBkBRQUHcXgbTpgQUxeWyoMcRIUQM,1488
|
|
13
|
-
anydi/ext/pytest_plugin.py,sha256=
|
|
12
|
+
anydi/ext/pytest_plugin.py,sha256=yR_vos8qt8uFS9uy_G_HJjNgudzJIXawrtpWnn3Pu_s,4613
|
|
14
13
|
anydi/ext/django/__init__.py,sha256=QI1IABCVgSDTUoh7M9WMECKXwB3xvh04HfQ9TOWw1Mk,223
|
|
15
14
|
anydi/ext/django/_container.py,sha256=cxVoYQG16WP0S_Yv4TnLwuaaT7NVEOhLWO-YdALJUb4,418
|
|
16
15
|
anydi/ext/django/_settings.py,sha256=Z0RlAuXoO73oahWeMkK10w8c-4uCBde-DBpeKTV5USY,853
|
|
@@ -22,8 +21,8 @@ anydi/ext/django/ninja/_operation.py,sha256=wSWa7D73XTVlOibmOciv2l6JHPe1ERZcXrqI
|
|
|
22
21
|
anydi/ext/django/ninja/_signature.py,sha256=2cSzKxBIxXLqtwNuH6GSlmjVJFftoGmleWfyk_NVEWw,2207
|
|
23
22
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
23
|
anydi/ext/starlette/middleware.py,sha256=9CQtGg5ZzUz2gFSzJr8U4BWzwNjK8XMctm3n52M77Z0,792
|
|
25
|
-
anydi-0.38.
|
|
26
|
-
anydi-0.38.
|
|
27
|
-
anydi-0.38.
|
|
28
|
-
anydi-0.38.
|
|
29
|
-
anydi-0.38.
|
|
24
|
+
anydi-0.38.2rc0.dist-info/METADATA,sha256=t8FL1ILCUK37XUFQ_gqgAlwX77UytT5FeP4QueIDX50,4920
|
|
25
|
+
anydi-0.38.2rc0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
26
|
+
anydi-0.38.2rc0.dist-info/entry_points.txt,sha256=Nklo9f3Oe4AkNsEgC4g43nCJ-23QDngZSVDNRMdaILI,43
|
|
27
|
+
anydi-0.38.2rc0.dist-info/licenses/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
28
|
+
anydi-0.38.2rc0.dist-info/RECORD,,
|
anydi/_provider.py
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import inspect
|
|
4
|
-
import uuid
|
|
5
|
-
from collections.abc import AsyncIterator, Iterator
|
|
6
|
-
from enum import IntEnum
|
|
7
|
-
from typing import Any, Callable
|
|
8
|
-
|
|
9
|
-
from typing_extensions import get_args, get_origin
|
|
10
|
-
|
|
11
|
-
try:
|
|
12
|
-
from types import NoneType
|
|
13
|
-
except ImportError:
|
|
14
|
-
NoneType = type(None) # type: ignore[misc]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from ._types import Event, Scope
|
|
18
|
-
from ._utils import get_full_qualname, get_typed_annotation
|
|
19
|
-
|
|
20
|
-
_sentinel = object()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class CallableKind(IntEnum):
|
|
24
|
-
CLASS = 1
|
|
25
|
-
FUNCTION = 2
|
|
26
|
-
COROUTINE = 3
|
|
27
|
-
GENERATOR = 4
|
|
28
|
-
ASYNC_GENERATOR = 5
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class Provider:
|
|
32
|
-
__slots__ = (
|
|
33
|
-
"_call",
|
|
34
|
-
"_call_module",
|
|
35
|
-
"_call_globals",
|
|
36
|
-
"_scope",
|
|
37
|
-
"_qualname",
|
|
38
|
-
"_kind",
|
|
39
|
-
"_interface",
|
|
40
|
-
"_parameters",
|
|
41
|
-
"_is_class",
|
|
42
|
-
"_is_coroutine",
|
|
43
|
-
"_is_generator",
|
|
44
|
-
"_is_async_generator",
|
|
45
|
-
"_is_async",
|
|
46
|
-
"_is_resource",
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
def __init__(
|
|
50
|
-
self, call: Callable[..., Any], *, scope: Scope, interface: Any = _sentinel
|
|
51
|
-
) -> None:
|
|
52
|
-
self._call = call
|
|
53
|
-
self._call_module = getattr(call, "__module__", None)
|
|
54
|
-
self._call_globals = getattr(call, "__globals__", {})
|
|
55
|
-
self._scope = scope
|
|
56
|
-
self._qualname = get_full_qualname(call)
|
|
57
|
-
|
|
58
|
-
# Detect the kind of callable provider
|
|
59
|
-
self._detect_kind()
|
|
60
|
-
|
|
61
|
-
self._is_class = self._kind == CallableKind.CLASS
|
|
62
|
-
self._is_coroutine = self._kind == CallableKind.COROUTINE
|
|
63
|
-
self._is_generator = self._kind == CallableKind.GENERATOR
|
|
64
|
-
self._is_async_generator = self._kind == CallableKind.ASYNC_GENERATOR
|
|
65
|
-
self._is_async = self._is_coroutine or self._is_async_generator
|
|
66
|
-
self._is_resource = self._is_generator or self._is_async_generator
|
|
67
|
-
|
|
68
|
-
# Validate the scope of the provider
|
|
69
|
-
self._validate_scope()
|
|
70
|
-
|
|
71
|
-
# Get the signature
|
|
72
|
-
signature = inspect.signature(call)
|
|
73
|
-
|
|
74
|
-
# Detect the interface
|
|
75
|
-
self._detect_interface(interface, signature)
|
|
76
|
-
|
|
77
|
-
# Detect the parameters
|
|
78
|
-
self._detect_parameters(signature)
|
|
79
|
-
|
|
80
|
-
def __str__(self) -> str:
|
|
81
|
-
return self._qualname
|
|
82
|
-
|
|
83
|
-
def __eq__(self, other: object) -> bool:
|
|
84
|
-
if not isinstance(other, Provider):
|
|
85
|
-
return NotImplemented # pragma: no cover
|
|
86
|
-
return (
|
|
87
|
-
self._call == other._call
|
|
88
|
-
and self._scope == other._scope
|
|
89
|
-
and self._interface == other._interface
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
@property
|
|
93
|
-
def call(self) -> Callable[..., Any]:
|
|
94
|
-
return self._call
|
|
95
|
-
|
|
96
|
-
@property
|
|
97
|
-
def kind(self) -> CallableKind:
|
|
98
|
-
return self._kind
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def scope(self) -> Scope:
|
|
102
|
-
return self._scope
|
|
103
|
-
|
|
104
|
-
@property
|
|
105
|
-
def interface(self) -> Any:
|
|
106
|
-
return self._interface
|
|
107
|
-
|
|
108
|
-
@property
|
|
109
|
-
def parameters(self) -> list[inspect.Parameter]:
|
|
110
|
-
return self._parameters
|
|
111
|
-
|
|
112
|
-
@property
|
|
113
|
-
def is_class(self) -> bool:
|
|
114
|
-
"""Check if the provider is a class."""
|
|
115
|
-
return self._is_class
|
|
116
|
-
|
|
117
|
-
@property
|
|
118
|
-
def is_coroutine(self) -> bool:
|
|
119
|
-
"""Check if the provider is a coroutine."""
|
|
120
|
-
return self._is_coroutine
|
|
121
|
-
|
|
122
|
-
@property
|
|
123
|
-
def is_generator(self) -> bool:
|
|
124
|
-
"""Check if the provider is a generator."""
|
|
125
|
-
return self._is_generator
|
|
126
|
-
|
|
127
|
-
@property
|
|
128
|
-
def is_async_generator(self) -> bool:
|
|
129
|
-
"""Check if the provider is an async generator."""
|
|
130
|
-
return self._is_async_generator
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def is_async(self) -> bool:
|
|
134
|
-
"""Check if the provider is an async callable."""
|
|
135
|
-
return self._is_async
|
|
136
|
-
|
|
137
|
-
@property
|
|
138
|
-
def is_resource(self) -> bool:
|
|
139
|
-
"""Check if the provider is a resource."""
|
|
140
|
-
return self._is_resource
|
|
141
|
-
|
|
142
|
-
def _validate_scope(self) -> None:
|
|
143
|
-
"""Validate the scope of the provider."""
|
|
144
|
-
if self.scope not in get_args(Scope):
|
|
145
|
-
raise ValueError(
|
|
146
|
-
"The scope provided is invalid. Only the following scopes are "
|
|
147
|
-
f"supported: {', '.join(get_args(Scope))}. Please use one of the "
|
|
148
|
-
"supported scopes when registering a provider."
|
|
149
|
-
)
|
|
150
|
-
if self.is_resource and self.scope == "transient":
|
|
151
|
-
raise TypeError(
|
|
152
|
-
f"The resource provider `{self}` is attempting to register "
|
|
153
|
-
"with a transient scope, which is not allowed."
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
def _detect_kind(self) -> None:
|
|
157
|
-
"""Detect the kind of callable provider."""
|
|
158
|
-
if inspect.isclass(self.call):
|
|
159
|
-
self._kind = CallableKind.CLASS
|
|
160
|
-
elif inspect.iscoroutinefunction(self.call):
|
|
161
|
-
self._kind = CallableKind.COROUTINE
|
|
162
|
-
elif inspect.isasyncgenfunction(self.call):
|
|
163
|
-
self._kind = CallableKind.ASYNC_GENERATOR
|
|
164
|
-
elif inspect.isgeneratorfunction(self.call):
|
|
165
|
-
self._kind = CallableKind.GENERATOR
|
|
166
|
-
elif inspect.isfunction(self.call) or inspect.ismethod(self.call):
|
|
167
|
-
self._kind = CallableKind.FUNCTION
|
|
168
|
-
else:
|
|
169
|
-
raise TypeError(
|
|
170
|
-
f"The provider `{self.call}` is invalid because it is not a callable "
|
|
171
|
-
"object. Only callable providers are allowed."
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
def _detect_interface(self, interface: Any, signature: inspect.Signature) -> None:
|
|
175
|
-
"""Detect the interface of callable provider."""
|
|
176
|
-
# If the callable is a class, return the class itself
|
|
177
|
-
if self._kind == CallableKind.CLASS:
|
|
178
|
-
self._interface = self._call
|
|
179
|
-
return
|
|
180
|
-
|
|
181
|
-
if interface is _sentinel:
|
|
182
|
-
interface = self._resolve_interface(interface, signature)
|
|
183
|
-
|
|
184
|
-
# If the callable is an iterator, return the actual type
|
|
185
|
-
iterator_types = {Iterator, AsyncIterator}
|
|
186
|
-
if interface in iterator_types or get_origin(interface) in iterator_types:
|
|
187
|
-
if args := get_args(interface):
|
|
188
|
-
interface = args[0]
|
|
189
|
-
# If the callable is a generator, return the resource type
|
|
190
|
-
if interface is NoneType or interface is None:
|
|
191
|
-
self._interface = type(f"Event_{uuid.uuid4().hex}", (Event,), {})
|
|
192
|
-
return
|
|
193
|
-
else:
|
|
194
|
-
raise TypeError(
|
|
195
|
-
f"Cannot use `{self}` resource type annotation "
|
|
196
|
-
"without actual type argument."
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
# None interface is not allowed
|
|
200
|
-
if interface in {None, NoneType}:
|
|
201
|
-
raise TypeError(f"Missing `{self}` provider return annotation.")
|
|
202
|
-
|
|
203
|
-
# Set the interface
|
|
204
|
-
self._interface = interface
|
|
205
|
-
|
|
206
|
-
def _resolve_interface(self, interface: Any, signature: inspect.Signature) -> Any:
|
|
207
|
-
"""Resolve the interface of the callable provider."""
|
|
208
|
-
interface = signature.return_annotation
|
|
209
|
-
if interface is inspect.Signature.empty:
|
|
210
|
-
return None
|
|
211
|
-
return get_typed_annotation(
|
|
212
|
-
interface,
|
|
213
|
-
self._call_globals,
|
|
214
|
-
module=self._call_module,
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
def _detect_parameters(self, signature: inspect.Signature) -> None:
|
|
218
|
-
"""Detect the parameters of the callable provider."""
|
|
219
|
-
parameters = []
|
|
220
|
-
for parameter in signature.parameters.values():
|
|
221
|
-
if parameter.kind == inspect.Parameter.POSITIONAL_ONLY:
|
|
222
|
-
raise TypeError(
|
|
223
|
-
f"Positional-only parameter `{parameter.name}` is not allowed "
|
|
224
|
-
f"in the provider `{self}`."
|
|
225
|
-
)
|
|
226
|
-
annotation = get_typed_annotation(
|
|
227
|
-
parameter.annotation,
|
|
228
|
-
self._call_globals,
|
|
229
|
-
module=self._call_module,
|
|
230
|
-
)
|
|
231
|
-
parameters.append(parameter.replace(annotation=annotation))
|
|
232
|
-
self._parameters = parameters
|
|
File without changes
|
|
File without changes
|
|
File without changes
|