anydi 0.69.0__py3-none-any.whl → 0.70.1__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/_container.py +70 -7
- anydi/_decorators.py +22 -30
- anydi/_graph.py +27 -16
- anydi/_resolver.py +19 -2
- anydi/_scanner.py +6 -3
- anydi/_types.py +9 -0
- {anydi-0.69.0.dist-info → anydi-0.70.1.dist-info}/METADATA +1 -1
- {anydi-0.69.0.dist-info → anydi-0.70.1.dist-info}/RECORD +10 -10
- {anydi-0.69.0.dist-info → anydi-0.70.1.dist-info}/WHEEL +0 -0
- {anydi-0.69.0.dist-info → anydi-0.70.1.dist-info}/entry_points.txt +0 -0
anydi/_container.py
CHANGED
|
@@ -25,7 +25,15 @@ from ._module import ModuleDef, ModuleRegistrar
|
|
|
25
25
|
from ._provider import Provider, ProviderDef, ProviderKind, ProviderParameter
|
|
26
26
|
from ._resolver import Resolver
|
|
27
27
|
from ._scanner import PackageOrIterable, Scanner
|
|
28
|
-
from ._types import
|
|
28
|
+
from ._types import (
|
|
29
|
+
NOT_SET,
|
|
30
|
+
Event,
|
|
31
|
+
Scope,
|
|
32
|
+
is_event_type,
|
|
33
|
+
is_iterator_type,
|
|
34
|
+
is_none_type,
|
|
35
|
+
to_list,
|
|
36
|
+
)
|
|
29
37
|
|
|
30
38
|
T = TypeVar("T", bound=Any)
|
|
31
39
|
P = ParamSpec("P")
|
|
@@ -49,6 +57,7 @@ class Container:
|
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
self._resources: dict[str, list[Any]] = defaultdict(list)
|
|
60
|
+
self._aliases: dict[Any, Any] = {} # alias_type → canonical_type
|
|
52
61
|
self._singleton_context = InstanceContext()
|
|
53
62
|
self._scoped_context: dict[str, ContextVar[InstanceContext]] = {}
|
|
54
63
|
|
|
@@ -95,6 +104,11 @@ class Container:
|
|
|
95
104
|
"""Get the registered providers."""
|
|
96
105
|
return self._providers
|
|
97
106
|
|
|
107
|
+
@property
|
|
108
|
+
def aliases(self) -> dict[Any, Any]:
|
|
109
|
+
"""Get the registered aliases."""
|
|
110
|
+
return self._aliases
|
|
111
|
+
|
|
98
112
|
@property
|
|
99
113
|
def ready(self) -> bool:
|
|
100
114
|
"""Check if the container is ready."""
|
|
@@ -339,6 +353,7 @@ class Container:
|
|
|
339
353
|
scope: Scope = "singleton",
|
|
340
354
|
from_context: bool = False,
|
|
341
355
|
override: bool = False,
|
|
356
|
+
alias: Any = NOT_SET,
|
|
342
357
|
interface: Any = NOT_SET,
|
|
343
358
|
call: Callable[..., Any] = NOT_SET,
|
|
344
359
|
) -> Provider:
|
|
@@ -366,13 +381,40 @@ class Container:
|
|
|
366
381
|
dependency_type = interface
|
|
367
382
|
if factory is NOT_SET:
|
|
368
383
|
factory = call if call is not NOT_SET else dependency_type
|
|
369
|
-
|
|
384
|
+
provider = self._register_provider(
|
|
370
385
|
dependency_type, factory, scope, from_context, override, None
|
|
371
386
|
)
|
|
372
387
|
|
|
388
|
+
# Register aliases if specified
|
|
389
|
+
for alias_type in to_list(alias):
|
|
390
|
+
self.alias(alias_type, provider.dependency_type)
|
|
391
|
+
|
|
392
|
+
return provider
|
|
393
|
+
|
|
394
|
+
def alias(self, alias_type: Any, canonical_type: Any, /) -> None:
|
|
395
|
+
"""Register an alias for a dependency type."""
|
|
396
|
+
if self.ready:
|
|
397
|
+
raise RuntimeError(
|
|
398
|
+
"Cannot register aliases after build() has been called. "
|
|
399
|
+
"All aliases must be registered before building the container."
|
|
400
|
+
)
|
|
401
|
+
if alias_type == canonical_type:
|
|
402
|
+
raise ValueError("Alias type cannot be the same as canonical type.")
|
|
403
|
+
if alias_type in self._aliases:
|
|
404
|
+
raise ValueError(
|
|
405
|
+
f"Alias `{type_repr(alias_type)}` is already registered "
|
|
406
|
+
f"for `{type_repr(self._aliases[alias_type])}`."
|
|
407
|
+
)
|
|
408
|
+
self._aliases[alias_type] = canonical_type
|
|
409
|
+
|
|
410
|
+
def _resolve_alias(self, dependency_type: Any) -> Any:
|
|
411
|
+
"""Resolve an alias to its canonical type."""
|
|
412
|
+
return self._aliases.get(dependency_type, dependency_type)
|
|
413
|
+
|
|
373
414
|
def is_registered(self, dependency_type: Any, /) -> bool:
|
|
374
415
|
"""Check if a provider is registered for the specified dependency type."""
|
|
375
|
-
|
|
416
|
+
canonical = self._resolve_alias(dependency_type)
|
|
417
|
+
return canonical in self._providers
|
|
376
418
|
|
|
377
419
|
def has_provider_for(self, dependency_type: Any, /) -> bool:
|
|
378
420
|
"""Check if a provider exists for the specified dependency type."""
|
|
@@ -400,12 +442,19 @@ class Container:
|
|
|
400
442
|
self._delete_provider(provider)
|
|
401
443
|
|
|
402
444
|
def provider(
|
|
403
|
-
self, *, scope: Scope, override: bool = False
|
|
445
|
+
self, *, scope: Scope, override: bool = False, alias: Any = NOT_SET
|
|
404
446
|
) -> Callable[[Callable[P, T]], Callable[P, T]]:
|
|
405
447
|
"""Decorator to register a provider function with the specified scope."""
|
|
406
448
|
|
|
407
449
|
def decorator(call: Callable[P, T]) -> Callable[P, T]:
|
|
408
|
-
self._register_provider(
|
|
450
|
+
provider = self._register_provider(
|
|
451
|
+
NOT_SET, call, scope, False, override, None
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
# Register aliases if specified
|
|
455
|
+
for alias_type in to_list(alias):
|
|
456
|
+
self.alias(alias_type, provider.dependency_type)
|
|
457
|
+
|
|
409
458
|
return call
|
|
410
459
|
|
|
411
460
|
return decorator
|
|
@@ -570,9 +619,10 @@ class Container:
|
|
|
570
619
|
return provider
|
|
571
620
|
|
|
572
621
|
def _get_provider(self, dependency_type: Any) -> Provider:
|
|
573
|
-
"""Get provider by dependency type."""
|
|
622
|
+
"""Get provider by dependency type, resolving aliases."""
|
|
623
|
+
canonical = self._resolve_alias(dependency_type)
|
|
574
624
|
try:
|
|
575
|
-
return self._providers[
|
|
625
|
+
return self._providers[canonical]
|
|
576
626
|
except KeyError:
|
|
577
627
|
raise LookupError(
|
|
578
628
|
f"The provider for `{type_repr(dependency_type)}` has "
|
|
@@ -597,6 +647,11 @@ class Container:
|
|
|
597
647
|
False,
|
|
598
648
|
defaults,
|
|
599
649
|
)
|
|
650
|
+
# Register aliases if specified
|
|
651
|
+
if not self.ready:
|
|
652
|
+
aliases = to_list(dependency_type.__provided__.get("alias"))
|
|
653
|
+
for alias_type in aliases:
|
|
654
|
+
self.alias(alias_type, dependency_type)
|
|
600
655
|
registered = True
|
|
601
656
|
else:
|
|
602
657
|
raise LookupError(
|
|
@@ -677,6 +732,10 @@ class Container:
|
|
|
677
732
|
False,
|
|
678
733
|
None,
|
|
679
734
|
)
|
|
735
|
+
# Register aliases if specified
|
|
736
|
+
aliases = to_list(dependency_type.__provided__.get("alias"))
|
|
737
|
+
for alias_type in aliases:
|
|
738
|
+
self._aliases[alias_type] = dependency_type
|
|
680
739
|
# Recursively ensure the @provided class is resolved
|
|
681
740
|
dep_provider = self._ensure_provider_resolved(
|
|
682
741
|
dep_provider, resolving
|
|
@@ -977,6 +1036,10 @@ class Container:
|
|
|
977
1036
|
False,
|
|
978
1037
|
None,
|
|
979
1038
|
)
|
|
1039
|
+
# Register aliases if specified
|
|
1040
|
+
provided_meta = param_dependency_type.__provided__
|
|
1041
|
+
for alias_type in to_list(provided_meta.get("alias")):
|
|
1042
|
+
self._aliases[alias_type] = param_dependency_type
|
|
980
1043
|
elif param.has_default:
|
|
981
1044
|
# Has default, can be missing
|
|
982
1045
|
resolved_params.append(param)
|
anydi/_decorators.py
CHANGED
|
@@ -29,32 +29,20 @@ ModuleT = TypeVar("ModuleT", bound="Module")
|
|
|
29
29
|
class ProvidedMetadata(TypedDict):
|
|
30
30
|
"""Metadata for classes marked as provided by AnyDI."""
|
|
31
31
|
|
|
32
|
-
dependency_type: NotRequired[Any]
|
|
33
32
|
scope: Scope
|
|
33
|
+
alias: NotRequired[Any]
|
|
34
34
|
from_context: NotRequired[bool]
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
@overload
|
|
38
|
-
def provided(
|
|
39
|
-
dependency_type: Any, /, *, scope: Scope, from_context: bool = False
|
|
40
|
-
) -> Callable[[ClassT], ClassT]: ...
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@overload
|
|
44
|
-
def provided(
|
|
45
|
-
*, scope: Scope, from_context: bool = False
|
|
46
|
-
) -> Callable[[ClassT], ClassT]: ...
|
|
47
|
-
|
|
48
|
-
|
|
49
37
|
def provided(
|
|
50
|
-
|
|
38
|
+
*, scope: Scope, alias: Any = NOT_SET, from_context: bool = False
|
|
51
39
|
) -> Callable[[ClassT], ClassT]:
|
|
52
40
|
"""Decorator for marking a class as provided by AnyDI with a specific scope."""
|
|
53
41
|
|
|
54
42
|
def decorator(cls: ClassT) -> ClassT:
|
|
55
43
|
metadata: ProvidedMetadata = {"scope": scope}
|
|
56
|
-
if
|
|
57
|
-
metadata["
|
|
44
|
+
if alias is not NOT_SET:
|
|
45
|
+
metadata["alias"] = alias
|
|
58
46
|
if from_context:
|
|
59
47
|
metadata["from_context"] = from_context
|
|
60
48
|
cls.__provided__ = metadata # type: ignore[attr-defined]
|
|
@@ -69,19 +57,19 @@ def singleton(cls: ClassT, /) -> ClassT: ...
|
|
|
69
57
|
|
|
70
58
|
@overload
|
|
71
59
|
def singleton(
|
|
72
|
-
cls: None = None, /, *,
|
|
60
|
+
cls: None = None, /, *, alias: Any = NOT_SET
|
|
73
61
|
) -> Callable[[ClassT], ClassT]: ...
|
|
74
62
|
|
|
75
63
|
|
|
76
64
|
def singleton(
|
|
77
|
-
cls: ClassT | None = None, /, *,
|
|
65
|
+
cls: ClassT | None = None, /, *, alias: Any = NOT_SET
|
|
78
66
|
) -> Callable[[ClassT], ClassT] | ClassT:
|
|
79
67
|
"""Decorator for marking a class as a singleton dependency."""
|
|
80
68
|
|
|
81
69
|
def decorator(c: ClassT) -> ClassT:
|
|
82
70
|
metadata: ProvidedMetadata = {"scope": "singleton"}
|
|
83
|
-
if
|
|
84
|
-
metadata["
|
|
71
|
+
if alias is not NOT_SET:
|
|
72
|
+
metadata["alias"] = alias
|
|
85
73
|
c.__provided__ = metadata # type: ignore[attr-defined]
|
|
86
74
|
return c
|
|
87
75
|
|
|
@@ -97,19 +85,19 @@ def transient(cls: ClassT, /) -> ClassT: ...
|
|
|
97
85
|
|
|
98
86
|
@overload
|
|
99
87
|
def transient(
|
|
100
|
-
cls: None = None, /, *,
|
|
88
|
+
cls: None = None, /, *, alias: Any = NOT_SET
|
|
101
89
|
) -> Callable[[ClassT], ClassT]: ...
|
|
102
90
|
|
|
103
91
|
|
|
104
92
|
def transient(
|
|
105
|
-
cls: ClassT | None = None, /, *,
|
|
93
|
+
cls: ClassT | None = None, /, *, alias: Any = NOT_SET
|
|
106
94
|
) -> Callable[[ClassT], ClassT] | ClassT:
|
|
107
95
|
"""Decorator for marking a class as a transient dependency."""
|
|
108
96
|
|
|
109
97
|
def decorator(c: ClassT) -> ClassT:
|
|
110
98
|
metadata: ProvidedMetadata = {"scope": "transient"}
|
|
111
|
-
if
|
|
112
|
-
metadata["
|
|
99
|
+
if alias is not NOT_SET:
|
|
100
|
+
metadata["alias"] = alias
|
|
113
101
|
c.__provided__ = metadata # type: ignore[attr-defined]
|
|
114
102
|
return c
|
|
115
103
|
|
|
@@ -125,7 +113,7 @@ def request(cls: ClassT, /, *, from_context: bool = False) -> ClassT: ...
|
|
|
125
113
|
|
|
126
114
|
@overload
|
|
127
115
|
def request(
|
|
128
|
-
cls: None = None, /, *,
|
|
116
|
+
cls: None = None, /, *, alias: Any = NOT_SET, from_context: bool = False
|
|
129
117
|
) -> Callable[[ClassT], ClassT]: ...
|
|
130
118
|
|
|
131
119
|
|
|
@@ -133,15 +121,15 @@ def request(
|
|
|
133
121
|
cls: ClassT | None = None,
|
|
134
122
|
/,
|
|
135
123
|
*,
|
|
136
|
-
|
|
124
|
+
alias: Any = NOT_SET,
|
|
137
125
|
from_context: bool = False,
|
|
138
126
|
) -> Callable[[ClassT], ClassT] | ClassT:
|
|
139
127
|
"""Decorator for marking a class as a request-scoped dependency."""
|
|
140
128
|
|
|
141
129
|
def decorator(c: ClassT) -> ClassT:
|
|
142
130
|
metadata: ProvidedMetadata = {"scope": "request"}
|
|
143
|
-
if
|
|
144
|
-
metadata["
|
|
131
|
+
if alias is not NOT_SET:
|
|
132
|
+
metadata["alias"] = alias
|
|
145
133
|
if from_context:
|
|
146
134
|
metadata["from_context"] = from_context
|
|
147
135
|
c.__provided__ = metadata # type: ignore[attr-defined]
|
|
@@ -164,10 +152,11 @@ def is_provided(cls: Any) -> TypeGuard[type[Provided]]:
|
|
|
164
152
|
class ProviderMetadata(TypedDict):
|
|
165
153
|
scope: Scope
|
|
166
154
|
override: bool
|
|
155
|
+
alias: NotRequired[Any]
|
|
167
156
|
|
|
168
157
|
|
|
169
158
|
def provider(
|
|
170
|
-
*, scope: Scope, override: bool = False
|
|
159
|
+
*, scope: Scope, override: bool = False, alias: Any = NOT_SET
|
|
171
160
|
) -> Callable[
|
|
172
161
|
[Callable[Concatenate[ModuleT, P], T]], Callable[Concatenate[ModuleT, P], T]
|
|
173
162
|
]:
|
|
@@ -176,7 +165,10 @@ def provider(
|
|
|
176
165
|
def decorator(
|
|
177
166
|
target: Callable[Concatenate[ModuleT, P], T],
|
|
178
167
|
) -> Callable[Concatenate[ModuleT, P], T]:
|
|
179
|
-
|
|
168
|
+
metadata: ProviderMetadata = {"scope": scope, "override": override}
|
|
169
|
+
if alias is not NOT_SET:
|
|
170
|
+
metadata["alias"] = alias
|
|
171
|
+
target.__provider__ = metadata # type: ignore
|
|
180
172
|
return target
|
|
181
173
|
|
|
182
174
|
return decorator
|
anydi/_graph.py
CHANGED
|
@@ -19,6 +19,14 @@ class Graph:
|
|
|
19
19
|
def __init__(self, container: Container) -> None:
|
|
20
20
|
self._container = container
|
|
21
21
|
|
|
22
|
+
def _get_aliases_for(self, dependency_type: Any) -> list[str]:
|
|
23
|
+
"""Get list of alias names that point to a dependency type."""
|
|
24
|
+
aliases: list[str] = []
|
|
25
|
+
for alias, canonical in self._container.aliases.items():
|
|
26
|
+
if canonical == dependency_type:
|
|
27
|
+
aliases.append(type_repr(alias).rsplit(".", 1)[-1])
|
|
28
|
+
return aliases
|
|
29
|
+
|
|
22
30
|
def draw(
|
|
23
31
|
self,
|
|
24
32
|
output_format: Literal["tree", "mermaid", "dot", "json"] = "tree",
|
|
@@ -127,14 +135,16 @@ class Graph:
|
|
|
127
135
|
}
|
|
128
136
|
)
|
|
129
137
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
aliases = self._get_aliases_for(provider.dependency_type)
|
|
139
|
+
provider_data: dict[str, Any] = {
|
|
140
|
+
"type": self._get_name(provider, full_path),
|
|
141
|
+
"scope": provider.scope,
|
|
142
|
+
"from_context": provider.from_context,
|
|
143
|
+
"dependencies": dependencies,
|
|
144
|
+
}
|
|
145
|
+
if aliases:
|
|
146
|
+
provider_data["aliases"] = aliases
|
|
147
|
+
providers.append(provider_data)
|
|
138
148
|
|
|
139
149
|
return json.dumps({"providers": providers}, indent=ident)
|
|
140
150
|
|
|
@@ -167,19 +177,20 @@ class Graph:
|
|
|
167
177
|
|
|
168
178
|
return "\n".join(lines)
|
|
169
179
|
|
|
170
|
-
@classmethod
|
|
171
180
|
def _format_tree_node(
|
|
172
|
-
|
|
181
|
+
self, provider: Provider, full_path: bool, param_name: str | None = None
|
|
173
182
|
) -> str:
|
|
174
|
-
name =
|
|
183
|
+
name = self._get_name(provider, full_path)
|
|
175
184
|
scope_label = Graph._get_scope_label(provider.scope, provider.from_context)
|
|
176
185
|
context_marker = " [context]" if provider.from_context else ""
|
|
186
|
+
aliases = self._get_aliases_for(provider.dependency_type)
|
|
187
|
+
alias_marker = f" [alias: {', '.join(aliases)}]" if aliases else ""
|
|
177
188
|
if param_name:
|
|
178
|
-
return f"{param_name}: {name} ({scope_label}){context_marker}"
|
|
179
|
-
return f"{name} ({scope_label}){context_marker}"
|
|
189
|
+
return f"{param_name}: {name} ({scope_label}){context_marker}{alias_marker}"
|
|
190
|
+
return f"{name} ({scope_label}){context_marker}{alias_marker}"
|
|
180
191
|
|
|
181
|
-
@staticmethod
|
|
182
192
|
def _render_tree_children(
|
|
193
|
+
self,
|
|
183
194
|
provider: Provider,
|
|
184
195
|
prefix: str,
|
|
185
196
|
visited: set[Any],
|
|
@@ -197,10 +208,10 @@ class Graph:
|
|
|
197
208
|
continue
|
|
198
209
|
is_last = i == len(deps) - 1
|
|
199
210
|
connector = "└── " if is_last else "├── "
|
|
200
|
-
node_text =
|
|
211
|
+
node_text = self._format_tree_node(dep_provider, full_path, param.name)
|
|
201
212
|
lines.append(f"{prefix}{connector}{node_text}")
|
|
202
213
|
extension = " " if is_last else "│ "
|
|
203
|
-
|
|
214
|
+
self._render_tree_children(
|
|
204
215
|
dep_provider, prefix + extension, visited, lines, full_path
|
|
205
216
|
)
|
|
206
217
|
|
anydi/_resolver.py
CHANGED
|
@@ -51,12 +51,24 @@ class Resolver:
|
|
|
51
51
|
return bool(self._overrides) or getattr(self._container, "_test_mode", False)
|
|
52
52
|
|
|
53
53
|
def add_override(self, dependency_type: Any, instance: Any) -> None:
|
|
54
|
-
"""Add an override
|
|
54
|
+
"""Add an override for a type, its canonical type, and all aliases."""
|
|
55
55
|
self._overrides[dependency_type] = instance
|
|
56
|
+
canonical = self._container.aliases.get(dependency_type)
|
|
57
|
+
if canonical is not None:
|
|
58
|
+
self._overrides[canonical] = instance
|
|
59
|
+
for alias, canon in self._container.aliases.items():
|
|
60
|
+
if canon == dependency_type:
|
|
61
|
+
self._overrides[alias] = instance
|
|
56
62
|
|
|
57
63
|
def remove_override(self, dependency_type: Any) -> None:
|
|
58
|
-
"""Remove an override
|
|
64
|
+
"""Remove an override for a type, its canonical type, and all aliases."""
|
|
59
65
|
self._overrides.pop(dependency_type, None)
|
|
66
|
+
canonical = self._container.aliases.get(dependency_type)
|
|
67
|
+
if canonical is not None:
|
|
68
|
+
self._overrides.pop(canonical, None)
|
|
69
|
+
for alias, canon in self._container.aliases.items():
|
|
70
|
+
if canon == dependency_type:
|
|
71
|
+
self._overrides.pop(alias, None)
|
|
60
72
|
|
|
61
73
|
def clear_caches(self) -> None:
|
|
62
74
|
"""Clear all cached resolvers."""
|
|
@@ -105,6 +117,11 @@ class Resolver:
|
|
|
105
117
|
# Store the compiled functions in the cache
|
|
106
118
|
cache[provider.dependency_type] = compiled
|
|
107
119
|
|
|
120
|
+
# Also store under all aliases that point to this type
|
|
121
|
+
for alias, canonical in self._container.aliases.items():
|
|
122
|
+
if canonical == provider.dependency_type:
|
|
123
|
+
cache[alias] = compiled
|
|
124
|
+
|
|
108
125
|
return compiled
|
|
109
126
|
|
|
110
127
|
def _add_override_check(
|
anydi/_scanner.py
CHANGED
|
@@ -9,6 +9,7 @@ from types import ModuleType
|
|
|
9
9
|
from typing import TYPE_CHECKING, Any
|
|
10
10
|
|
|
11
11
|
from ._decorators import Provided, is_injectable, is_provided
|
|
12
|
+
from ._types import to_list
|
|
12
13
|
|
|
13
14
|
if TYPE_CHECKING:
|
|
14
15
|
from ._container import Container
|
|
@@ -58,13 +59,15 @@ class Scanner:
|
|
|
58
59
|
|
|
59
60
|
# First: register @provided classes
|
|
60
61
|
for cls in provided_classes:
|
|
61
|
-
|
|
62
|
-
if not self._container.is_registered(dependency_type):
|
|
62
|
+
if not self._container.is_registered(cls):
|
|
63
63
|
scope = cls.__provided__["scope"]
|
|
64
64
|
from_context = cls.__provided__.get("from_context", False)
|
|
65
65
|
self._container.register(
|
|
66
|
-
|
|
66
|
+
cls, cls, scope=scope, from_context=from_context
|
|
67
67
|
)
|
|
68
|
+
# Create aliases if specified (alias → cls)
|
|
69
|
+
for alias_type in to_list(cls.__provided__.get("alias")):
|
|
70
|
+
self._container.alias(alias_type, cls)
|
|
68
71
|
|
|
69
72
|
# Second: inject @injectable functions
|
|
70
73
|
for dependency in injectable_dependencies:
|
anydi/_types.py
CHANGED
|
@@ -43,3 +43,12 @@ def is_none_type(tp: Any) -> bool:
|
|
|
43
43
|
def is_iterator_type(tp: Any) -> bool:
|
|
44
44
|
"""Check if the given object is an iterator type."""
|
|
45
45
|
return tp in (Iterator, AsyncIterator)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def to_list(value: Any) -> list[Any]:
|
|
49
|
+
"""Convert a value to a list, handling None and sequences."""
|
|
50
|
+
if value is None or value is NOT_SET:
|
|
51
|
+
return []
|
|
52
|
+
if isinstance(value, list | tuple):
|
|
53
|
+
return list(value) # type: ignore[arg-type]
|
|
54
|
+
return [value]
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
anydi/__init__.py,sha256=KFX8OthKXwBuYDPCV61t-044DpJ88tAOzIxeUWRC5OA,633
|
|
2
2
|
anydi/_async_lock.py,sha256=3dwZr0KthXFYha0XKMyXf8jMmGb1lYoNC0O5w29V9ic,1104
|
|
3
3
|
anydi/_cli.py,sha256=0BhNvWPyuIGzUkDELIBm_nsEMWk7MtLi3oTvgXj5oko,2072
|
|
4
|
-
anydi/_container.py,sha256=
|
|
4
|
+
anydi/_container.py,sha256=7c96X4hrN9-OZglUedvdKjoKcYJKFMy7IeTAHF9dOUs,49203
|
|
5
5
|
anydi/_context.py,sha256=ZQWxtBXWkrMsCk_L7K_A7-e09v5Mv9HApPH3LZ6ZF9k,3648
|
|
6
|
-
anydi/_decorators.py,sha256=
|
|
7
|
-
anydi/_graph.py,sha256=
|
|
6
|
+
anydi/_decorators.py,sha256=27AQBzp_P_ajO_bRk1ybgwuxTy9PMWGMJmfBvjriJ-8,5435
|
|
7
|
+
anydi/_graph.py,sha256=WN_N1nNNPp74YU1mqxM-dJlf0rWF9ooGNTIv87DJpKI,8619
|
|
8
8
|
anydi/_injector.py,sha256=RvnPEYOgkg-WOIW1ItvVsoAZaSC9wmCnWQrfXad_86A,4507
|
|
9
9
|
anydi/_marker.py,sha256=yXSPbIVU-X-jMSawtCHWFMKke5VpWMiBRZlEH8PlUqE,3373
|
|
10
10
|
anydi/_module.py,sha256=2kN5uEXLd2Dsc58gz5IWK43wJewr_QgIVGSO3iWp798,2609
|
|
11
11
|
anydi/_provider.py,sha256=5pMXyiGwBo2j6OHaoOktLQfiX2rkCf5aYXFlFi65JlQ,2898
|
|
12
|
-
anydi/_resolver.py,sha256=
|
|
13
|
-
anydi/_scanner.py,sha256=
|
|
14
|
-
anydi/_types.py,sha256=
|
|
12
|
+
anydi/_resolver.py,sha256=xpBgFhUTMdHeNjqmUfOZMU5J8PviVkc5q_ckgwrdAhs,33603
|
|
13
|
+
anydi/_scanner.py,sha256=gLs6Gdv12VVgT-J1vfCVOQ515drGtZQ4QNI8Bs0fqE0,5916
|
|
14
|
+
anydi/_types.py,sha256=QQY_WG6-e2VuqH2AqrStiM1bg2ACQMHaPtdOQVsDimU,1439
|
|
15
15
|
anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
anydi/ext/django/__init__.py,sha256=Ve8lncLU9dPY_Vjt4zihPgsSxwAtFHACn0XvBM5JG8k,367
|
|
17
17
|
anydi/ext/fastapi.py,sha256=NowHc-z_Sw069YDv9vP98Mehum5vHsIIcqvDkRmicmc,2964
|
|
@@ -23,7 +23,7 @@ anydi/ext/starlette/middleware.py,sha256=n_JJ7BcG2Mg2M5HwM_SBboxZ-mnnD6WWJn4khq7
|
|
|
23
23
|
anydi/ext/typer.py,sha256=c7HapXQfKhnLJQcHNncJAGd8jZ3crX5it6-MRCJjyPM,6268
|
|
24
24
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
anydi/testing.py,sha256=cHg3mMScZbEep9smRqSNQ81BZMQOkyugHe8TvKdPnEg,1347
|
|
26
|
-
anydi-0.
|
|
27
|
-
anydi-0.
|
|
28
|
-
anydi-0.
|
|
29
|
-
anydi-0.
|
|
26
|
+
anydi-0.70.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
27
|
+
anydi-0.70.1.dist-info/entry_points.txt,sha256=oDl_yEX12KlWcDzsZBTg85GG1Jl1rpiYOG4C7EJvebs,87
|
|
28
|
+
anydi-0.70.1.dist-info/METADATA,sha256=fSe7AsDMguaUHD6hCEELMRKVFx7Ge5B7gQjs3t5jbUA,8061
|
|
29
|
+
anydi-0.70.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|