anydi 0.34.1a1__py3-none-any.whl → 0.35.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/_container.py +165 -102
- anydi/_provider.py +12 -8
- anydi/_types.py +11 -8
- {anydi-0.34.1a1.dist-info → anydi-0.35.0.dist-info}/METADATA +1 -1
- {anydi-0.34.1a1.dist-info → anydi-0.35.0.dist-info}/RECORD +8 -9
- anydi/_logger.py +0 -3
- {anydi-0.34.1a1.dist-info → anydi-0.35.0.dist-info}/LICENSE +0 -0
- {anydi-0.34.1a1.dist-info → anydi-0.35.0.dist-info}/WHEEL +0 -0
- {anydi-0.34.1a1.dist-info → anydi-0.35.0.dist-info}/entry_points.txt +0 -0
anydi/_container.py
CHANGED
|
@@ -6,6 +6,7 @@ import contextlib
|
|
|
6
6
|
import functools
|
|
7
7
|
import importlib
|
|
8
8
|
import inspect
|
|
9
|
+
import logging
|
|
9
10
|
import pkgutil
|
|
10
11
|
import threading
|
|
11
12
|
import types
|
|
@@ -19,13 +20,12 @@ from weakref import WeakKeyDictionary
|
|
|
19
20
|
from typing_extensions import Concatenate, ParamSpec, Self, final
|
|
20
21
|
|
|
21
22
|
from ._context import InstanceContext
|
|
22
|
-
from ._logger import logger
|
|
23
23
|
from ._provider import Provider
|
|
24
24
|
from ._types import (
|
|
25
25
|
AnyInterface,
|
|
26
26
|
Dependency,
|
|
27
|
-
DependencyWrapper,
|
|
28
27
|
InjectableDecoratorArgs,
|
|
28
|
+
InstanceProxy,
|
|
29
29
|
ProviderDecoratorArgs,
|
|
30
30
|
Scope,
|
|
31
31
|
is_event_type,
|
|
@@ -74,6 +74,7 @@ class Module(metaclass=ModuleMeta):
|
|
|
74
74
|
"""Configure the AnyDI container with providers and their dependencies."""
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
# noinspection PyShadowingNames
|
|
77
78
|
@final
|
|
78
79
|
class Container:
|
|
79
80
|
"""AnyDI is a dependency injection container."""
|
|
@@ -86,8 +87,12 @@ class Container:
|
|
|
86
87
|
| None = None,
|
|
87
88
|
strict: bool = False,
|
|
88
89
|
testing: bool = False,
|
|
90
|
+
logger: logging.Logger | None = None,
|
|
89
91
|
) -> None:
|
|
90
92
|
self._providers: dict[type[Any], Provider] = {}
|
|
93
|
+
self._strict = strict
|
|
94
|
+
self._testing = testing
|
|
95
|
+
self._logger = logger or logging.getLogger(__name__)
|
|
91
96
|
self._resources: dict[str, list[type[Any]]] = defaultdict(list)
|
|
92
97
|
self._singleton_context = InstanceContext()
|
|
93
98
|
self._singleton_lock = threading.RLock()
|
|
@@ -96,8 +101,6 @@ class Container:
|
|
|
96
101
|
"request_context", default=None
|
|
97
102
|
)
|
|
98
103
|
self._override_instances: dict[type[Any], Any] = {}
|
|
99
|
-
self._strict = strict
|
|
100
|
-
self._testing = testing
|
|
101
104
|
self._unresolved_interfaces: set[type[Any]] = set()
|
|
102
105
|
self._inject_cache: WeakKeyDictionary[
|
|
103
106
|
Callable[..., Any], Callable[..., Any]
|
|
@@ -106,7 +109,7 @@ class Container:
|
|
|
106
109
|
# Register providers
|
|
107
110
|
providers = providers or []
|
|
108
111
|
for provider in providers:
|
|
109
|
-
self._register_provider(provider)
|
|
112
|
+
self._register_provider(provider, False)
|
|
110
113
|
|
|
111
114
|
# Register modules
|
|
112
115
|
modules = modules or []
|
|
@@ -128,6 +131,11 @@ class Container:
|
|
|
128
131
|
"""Get the registered providers."""
|
|
129
132
|
return self._providers
|
|
130
133
|
|
|
134
|
+
@property
|
|
135
|
+
def logger(self) -> logging.Logger:
|
|
136
|
+
"""Get the logger instance."""
|
|
137
|
+
return self._logger
|
|
138
|
+
|
|
131
139
|
def is_registered(self, interface: AnyInterface) -> bool:
|
|
132
140
|
"""Check if a provider is registered for the specified interface."""
|
|
133
141
|
return interface in self._providers
|
|
@@ -142,10 +150,10 @@ class Container:
|
|
|
142
150
|
) -> Provider:
|
|
143
151
|
"""Register a provider for the specified interface."""
|
|
144
152
|
provider = Provider(call=call, scope=scope, interface=interface)
|
|
145
|
-
return self._register_provider(provider, override
|
|
153
|
+
return self._register_provider(provider, override)
|
|
146
154
|
|
|
147
155
|
def _register_provider(
|
|
148
|
-
self, provider: Provider,
|
|
156
|
+
self, provider: Provider, override: bool, /, **defaults: Any
|
|
149
157
|
) -> Provider:
|
|
150
158
|
"""Register a provider."""
|
|
151
159
|
if provider.interface in self._providers:
|
|
@@ -158,7 +166,7 @@ class Container:
|
|
|
158
166
|
"already registered."
|
|
159
167
|
)
|
|
160
168
|
|
|
161
|
-
self._validate_sub_providers(provider)
|
|
169
|
+
self._validate_sub_providers(provider, **defaults)
|
|
162
170
|
self._set_provider(provider)
|
|
163
171
|
return provider
|
|
164
172
|
|
|
@@ -196,7 +204,7 @@ class Container:
|
|
|
196
204
|
) from exc
|
|
197
205
|
|
|
198
206
|
def _get_or_register_provider(
|
|
199
|
-
self, interface: AnyInterface, parent_scope: Scope | None
|
|
207
|
+
self, interface: AnyInterface, parent_scope: Scope | None, /, **defaults: Any
|
|
200
208
|
) -> Provider:
|
|
201
209
|
"""Get or register a provider by interface."""
|
|
202
210
|
try:
|
|
@@ -212,8 +220,10 @@ class Container:
|
|
|
212
220
|
scope = getattr(interface, "__scope__", parent_scope)
|
|
213
221
|
# Try to detect scope
|
|
214
222
|
if scope is None:
|
|
215
|
-
scope = self._detect_scope(interface)
|
|
216
|
-
|
|
223
|
+
scope = self._detect_scope(interface, **defaults)
|
|
224
|
+
scope = scope or "transient"
|
|
225
|
+
provider = Provider(call=interface, scope=scope, interface=interface)
|
|
226
|
+
return self._register_provider(provider, False, **defaults)
|
|
217
227
|
raise
|
|
218
228
|
|
|
219
229
|
def _set_provider(self, provider: Provider) -> None:
|
|
@@ -229,13 +239,11 @@ class Container:
|
|
|
229
239
|
if provider.is_resource:
|
|
230
240
|
self._resources[provider.scope].remove(provider.interface)
|
|
231
241
|
|
|
232
|
-
def _validate_sub_providers(self, provider: Provider) -> None:
|
|
242
|
+
def _validate_sub_providers(self, provider: Provider, /, **defaults: Any) -> None:
|
|
233
243
|
"""Validate the sub-providers of a provider."""
|
|
234
244
|
|
|
235
245
|
for parameter in provider.parameters:
|
|
236
|
-
annotation
|
|
237
|
-
|
|
238
|
-
if annotation is inspect.Parameter.empty:
|
|
246
|
+
if parameter.annotation is inspect.Parameter.empty:
|
|
239
247
|
raise TypeError(
|
|
240
248
|
f"Missing provider `{provider}` "
|
|
241
249
|
f"dependency `{parameter.name}` annotation."
|
|
@@ -243,11 +251,10 @@ class Container:
|
|
|
243
251
|
|
|
244
252
|
try:
|
|
245
253
|
sub_provider = self._get_or_register_provider(
|
|
246
|
-
annotation,
|
|
254
|
+
parameter.annotation, provider.scope
|
|
247
255
|
)
|
|
248
256
|
except LookupError:
|
|
249
|
-
|
|
250
|
-
if not self.strict and parameter.default is not inspect.Parameter.empty:
|
|
257
|
+
if self._parameter_has_default(parameter, **defaults):
|
|
251
258
|
continue
|
|
252
259
|
|
|
253
260
|
if provider.scope not in {"singleton", "transient"}:
|
|
@@ -255,7 +262,7 @@ class Container:
|
|
|
255
262
|
continue
|
|
256
263
|
raise ValueError(
|
|
257
264
|
f"The provider `{provider}` depends on `{parameter.name}` of type "
|
|
258
|
-
f"`{get_full_qualname(annotation)}`, which "
|
|
265
|
+
f"`{get_full_qualname(parameter.annotation)}`, which "
|
|
259
266
|
"has not been registered or set. To resolve this, ensure that "
|
|
260
267
|
f"`{parameter.name}` is registered before attempting to use it."
|
|
261
268
|
) from None
|
|
@@ -268,15 +275,17 @@ class Container:
|
|
|
268
275
|
"Please ensure all providers are registered with matching scopes."
|
|
269
276
|
)
|
|
270
277
|
|
|
271
|
-
def _detect_scope(self, call: Callable[..., Any]) -> Scope | None:
|
|
278
|
+
def _detect_scope(self, call: Callable[..., Any], **defaults: Any) -> Scope | None:
|
|
272
279
|
"""Detect the scope for a callable."""
|
|
273
280
|
scopes = set()
|
|
274
281
|
|
|
275
282
|
for parameter in get_typed_parameters(call):
|
|
276
283
|
try:
|
|
277
|
-
sub_provider = self._get_or_register_provider(
|
|
284
|
+
sub_provider = self._get_or_register_provider(
|
|
285
|
+
parameter.annotation, None
|
|
286
|
+
)
|
|
278
287
|
except LookupError:
|
|
279
|
-
if
|
|
288
|
+
if self._parameter_has_default(parameter, **defaults):
|
|
280
289
|
continue
|
|
281
290
|
raise
|
|
282
291
|
scope = sub_provider.scope
|
|
@@ -297,6 +306,13 @@ class Container:
|
|
|
297
306
|
|
|
298
307
|
return None
|
|
299
308
|
|
|
309
|
+
def _parameter_has_default(
|
|
310
|
+
self, parameter: inspect.Parameter, /, **defaults: Any
|
|
311
|
+
) -> bool:
|
|
312
|
+
return (defaults and parameter.name in defaults) or (
|
|
313
|
+
not self.strict and parameter.default is not inspect.Parameter.empty
|
|
314
|
+
)
|
|
315
|
+
|
|
300
316
|
def register_module(
|
|
301
317
|
self, module: Module | type[Module] | Callable[[Container], None] | str
|
|
302
318
|
) -> None:
|
|
@@ -436,9 +452,9 @@ class Container:
|
|
|
436
452
|
if interface in self._override_instances:
|
|
437
453
|
return cast(T, self._override_instances[interface])
|
|
438
454
|
|
|
439
|
-
provider = self._get_or_register_provider(interface)
|
|
455
|
+
provider = self._get_or_register_provider(interface, None)
|
|
440
456
|
if provider.scope == "transient":
|
|
441
|
-
instance, created = self._create_instance(provider), True
|
|
457
|
+
instance, created = self._create_instance(provider, None), True
|
|
442
458
|
else:
|
|
443
459
|
context = self._get_scoped_context(provider.scope)
|
|
444
460
|
if provider.scope == "singleton":
|
|
@@ -465,9 +481,9 @@ class Container:
|
|
|
465
481
|
if interface in self._override_instances:
|
|
466
482
|
return cast(T, self._override_instances[interface])
|
|
467
483
|
|
|
468
|
-
provider = self._get_or_register_provider(interface)
|
|
484
|
+
provider = self._get_or_register_provider(interface, None)
|
|
469
485
|
if provider.scope == "transient":
|
|
470
|
-
instance, created = await self._acreate_instance(provider), True
|
|
486
|
+
instance, created = await self._acreate_instance(provider, None), True
|
|
471
487
|
else:
|
|
472
488
|
context = self._get_scoped_context(provider.scope)
|
|
473
489
|
if provider.scope == "singleton":
|
|
@@ -483,13 +499,43 @@ class Container:
|
|
|
483
499
|
self._patch_test_resolver(instance)
|
|
484
500
|
return cast(T, instance)
|
|
485
501
|
|
|
502
|
+
def create(self, interface: type[T], **defaults: Any) -> T:
|
|
503
|
+
"""Create an instance by interface."""
|
|
504
|
+
provider = self._get_or_register_provider(interface, None, **defaults)
|
|
505
|
+
if provider.scope == "transient":
|
|
506
|
+
instance = self._create_instance(provider, None, **defaults)
|
|
507
|
+
else:
|
|
508
|
+
context = self._get_scoped_context(provider.scope)
|
|
509
|
+
if provider.scope == "singleton":
|
|
510
|
+
with self._singleton_lock:
|
|
511
|
+
instance = self._create_instance(provider, context, **defaults)
|
|
512
|
+
else:
|
|
513
|
+
instance = self._create_instance(provider, context, **defaults)
|
|
514
|
+
return cast(T, instance)
|
|
515
|
+
|
|
516
|
+
async def acreate(self, interface: type[T], **defaults: Any) -> T:
|
|
517
|
+
"""Create an instance by interface."""
|
|
518
|
+
provider = self._get_or_register_provider(interface, None, **defaults)
|
|
519
|
+
if provider.scope == "transient":
|
|
520
|
+
instance = await self._acreate_instance(provider, None, **defaults)
|
|
521
|
+
else:
|
|
522
|
+
context = self._get_scoped_context(provider.scope)
|
|
523
|
+
if provider.scope == "singleton":
|
|
524
|
+
async with self._singleton_async_lock:
|
|
525
|
+
instance = await self._acreate_instance(
|
|
526
|
+
provider, context, **defaults
|
|
527
|
+
)
|
|
528
|
+
else:
|
|
529
|
+
instance = await self._acreate_instance(provider, context, **defaults)
|
|
530
|
+
return cast(T, instance)
|
|
531
|
+
|
|
486
532
|
def _get_or_create_instance(
|
|
487
533
|
self, provider: Provider, context: InstanceContext
|
|
488
534
|
) -> tuple[Any, bool]:
|
|
489
535
|
"""Get an instance of a dependency from the scoped context."""
|
|
490
536
|
instance = context.get(provider.interface)
|
|
491
537
|
if instance is None:
|
|
492
|
-
instance = self._create_instance(provider, context
|
|
538
|
+
instance = self._create_instance(provider, context)
|
|
493
539
|
context.set(provider.interface, instance)
|
|
494
540
|
return instance, True
|
|
495
541
|
return instance, False
|
|
@@ -500,15 +546,13 @@ class Container:
|
|
|
500
546
|
"""Get an async instance of a dependency from the scoped context."""
|
|
501
547
|
instance = context.get(provider.interface)
|
|
502
548
|
if instance is None:
|
|
503
|
-
instance = await self._acreate_instance(provider, context
|
|
549
|
+
instance = await self._acreate_instance(provider, context)
|
|
504
550
|
context.set(provider.interface, instance)
|
|
505
551
|
return instance, True
|
|
506
552
|
return instance, False
|
|
507
553
|
|
|
508
554
|
def _create_instance(
|
|
509
|
-
self,
|
|
510
|
-
provider: Provider,
|
|
511
|
-
context: InstanceContext | None = None,
|
|
555
|
+
self, provider: Provider, context: InstanceContext | None, /, **defaults: Any
|
|
512
556
|
) -> Any:
|
|
513
557
|
"""Create an instance using the provider."""
|
|
514
558
|
if provider.is_async:
|
|
@@ -517,29 +561,29 @@ class Container:
|
|
|
517
561
|
"synchronous mode."
|
|
518
562
|
)
|
|
519
563
|
|
|
520
|
-
|
|
564
|
+
provider_kwargs = self._get_provided_kwargs(provider, context, **defaults)
|
|
521
565
|
|
|
522
566
|
if provider.is_generator:
|
|
523
567
|
if context is None:
|
|
524
568
|
raise ValueError("The context is required for generator providers.")
|
|
525
|
-
cm = contextlib.contextmanager(provider.call)(
|
|
569
|
+
cm = contextlib.contextmanager(provider.call)(**provider_kwargs)
|
|
526
570
|
return context.enter(cm)
|
|
527
571
|
|
|
528
|
-
instance = provider.call(
|
|
572
|
+
instance = provider.call(**provider_kwargs)
|
|
529
573
|
if context is not None and is_context_manager(instance):
|
|
530
574
|
context.enter(instance)
|
|
531
575
|
return instance
|
|
532
576
|
|
|
533
577
|
async def _acreate_instance(
|
|
534
|
-
self,
|
|
535
|
-
provider: Provider,
|
|
536
|
-
context: InstanceContext | None = None,
|
|
578
|
+
self, provider: Provider, context: InstanceContext | None, /, **defaults: Any
|
|
537
579
|
) -> Any:
|
|
538
580
|
"""Create an instance asynchronously using the provider."""
|
|
539
|
-
|
|
581
|
+
provider_kwargs = await self._aget_provided_kwargs(
|
|
582
|
+
provider, context, **defaults
|
|
583
|
+
)
|
|
540
584
|
|
|
541
585
|
if provider.is_coroutine:
|
|
542
|
-
instance = await provider.call(
|
|
586
|
+
instance = await provider.call(**provider_kwargs)
|
|
543
587
|
if context is not None and is_async_context_manager(instance):
|
|
544
588
|
await context.aenter(instance)
|
|
545
589
|
return instance
|
|
@@ -549,7 +593,7 @@ class Container:
|
|
|
549
593
|
raise ValueError(
|
|
550
594
|
"The async stack is required for async generator providers."
|
|
551
595
|
)
|
|
552
|
-
cm = contextlib.asynccontextmanager(provider.call)(
|
|
596
|
+
cm = contextlib.asynccontextmanager(provider.call)(**provider_kwargs)
|
|
553
597
|
return await context.aenter(cm)
|
|
554
598
|
|
|
555
599
|
if provider.is_generator:
|
|
@@ -557,83 +601,102 @@ class Container:
|
|
|
557
601
|
def _create() -> Any:
|
|
558
602
|
if context is None:
|
|
559
603
|
raise ValueError("The stack is required for generator providers.")
|
|
560
|
-
cm = contextlib.contextmanager(provider.call)(
|
|
604
|
+
cm = contextlib.contextmanager(provider.call)(**provider_kwargs)
|
|
561
605
|
return context.enter(cm)
|
|
562
606
|
|
|
563
607
|
return await run_async(_create)
|
|
564
608
|
|
|
565
|
-
instance = await run_async(provider.call,
|
|
609
|
+
instance = await run_async(provider.call, **provider_kwargs)
|
|
566
610
|
if context is not None and is_async_context_manager(instance):
|
|
567
611
|
await context.aenter(instance)
|
|
568
612
|
return instance
|
|
569
613
|
|
|
570
|
-
def
|
|
614
|
+
def _get_provided_kwargs(
|
|
615
|
+
self, provider: Provider, context: InstanceContext | None, /, **defaults: Any
|
|
616
|
+
) -> dict[str, Any]:
|
|
617
|
+
"""Retrieve the arguments for a provider."""
|
|
618
|
+
provided_kwargs = {}
|
|
619
|
+
for parameter in provider.parameters:
|
|
620
|
+
instance = self._get_provider_instance(
|
|
621
|
+
provider, parameter, context, **defaults
|
|
622
|
+
)
|
|
623
|
+
provided_kwargs[parameter.name] = instance
|
|
624
|
+
return {**defaults, **provided_kwargs}
|
|
625
|
+
|
|
626
|
+
def _get_provider_instance(
|
|
571
627
|
self,
|
|
572
628
|
provider: Provider,
|
|
629
|
+
parameter: inspect.Parameter,
|
|
573
630
|
context: InstanceContext | None,
|
|
574
|
-
|
|
575
|
-
**
|
|
576
|
-
) ->
|
|
577
|
-
"""Retrieve
|
|
578
|
-
|
|
579
|
-
|
|
631
|
+
/,
|
|
632
|
+
**defaults: Any,
|
|
633
|
+
) -> Any:
|
|
634
|
+
"""Retrieve an instance of a dependency from the scoped context."""
|
|
635
|
+
if parameter.name in defaults:
|
|
636
|
+
return defaults[parameter.name]
|
|
580
637
|
|
|
638
|
+
# Get instance from overrides or context cache
|
|
639
|
+
if parameter.annotation in self._override_instances:
|
|
640
|
+
return self._override_instances[parameter.annotation]
|
|
641
|
+
elif context and parameter.annotation in context:
|
|
642
|
+
return context[parameter.annotation]
|
|
643
|
+
|
|
644
|
+
# Resolve the instance
|
|
645
|
+
try:
|
|
646
|
+
instance = self._resolve_parameter(provider, parameter)
|
|
647
|
+
except LookupError:
|
|
648
|
+
if parameter.default is inspect.Parameter.empty:
|
|
649
|
+
raise
|
|
650
|
+
instance = parameter.default
|
|
651
|
+
|
|
652
|
+
# Wrap the instance in a proxy for testing
|
|
653
|
+
if self.testing:
|
|
654
|
+
return InstanceProxy(interface=parameter.annotation, instance=instance)
|
|
655
|
+
|
|
656
|
+
return instance
|
|
657
|
+
|
|
658
|
+
async def _aget_provided_kwargs(
|
|
659
|
+
self, provider: Provider, context: InstanceContext | None, /, **defaults: Any
|
|
660
|
+
) -> dict[str, Any]:
|
|
661
|
+
"""Asynchronously retrieve the arguments for a provider."""
|
|
662
|
+
provided_kwargs = {}
|
|
581
663
|
for parameter in provider.parameters:
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
try:
|
|
588
|
-
instance = self._resolve_parameter(provider, parameter)
|
|
589
|
-
except LookupError:
|
|
590
|
-
if parameter.default is inspect.Parameter.empty:
|
|
591
|
-
raise
|
|
592
|
-
instance = parameter.default
|
|
593
|
-
else:
|
|
594
|
-
if self.testing:
|
|
595
|
-
instance = DependencyWrapper(
|
|
596
|
-
interface=parameter.annotation, instance=instance
|
|
597
|
-
)
|
|
598
|
-
if parameter.kind == parameter.POSITIONAL_ONLY:
|
|
599
|
-
provided_args.append(instance)
|
|
600
|
-
else:
|
|
601
|
-
provided_kwargs[parameter.name] = instance
|
|
602
|
-
return provided_args, provided_kwargs
|
|
664
|
+
instance = await self._aget_provider_instance(
|
|
665
|
+
provider, parameter, context, **defaults
|
|
666
|
+
)
|
|
667
|
+
provided_kwargs[parameter.name] = instance
|
|
668
|
+
return {**defaults, **provided_kwargs}
|
|
603
669
|
|
|
604
|
-
async def
|
|
670
|
+
async def _aget_provider_instance(
|
|
605
671
|
self,
|
|
606
672
|
provider: Provider,
|
|
673
|
+
parameter: inspect.Parameter,
|
|
607
674
|
context: InstanceContext | None,
|
|
608
|
-
|
|
609
|
-
**
|
|
610
|
-
) ->
|
|
611
|
-
"""Asynchronously retrieve
|
|
612
|
-
|
|
613
|
-
|
|
675
|
+
/,
|
|
676
|
+
**defaults: Any,
|
|
677
|
+
) -> Any:
|
|
678
|
+
"""Asynchronously retrieve an instance of a dependency from the context."""
|
|
679
|
+
if parameter.name in defaults:
|
|
680
|
+
return defaults[parameter.name]
|
|
614
681
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
provided_args.append(instance)
|
|
634
|
-
else:
|
|
635
|
-
provided_kwargs[parameter.name] = instance
|
|
636
|
-
return provided_args, provided_kwargs
|
|
682
|
+
# Get instance from overrides or context cache
|
|
683
|
+
if parameter.annotation in self._override_instances:
|
|
684
|
+
return self._override_instances[parameter.annotation]
|
|
685
|
+
elif context and parameter.annotation in context:
|
|
686
|
+
return context[parameter.annotation]
|
|
687
|
+
|
|
688
|
+
# Resolve the instance
|
|
689
|
+
try:
|
|
690
|
+
instance = await self._aresolve_parameter(provider, parameter)
|
|
691
|
+
except LookupError:
|
|
692
|
+
if parameter.default is inspect.Parameter.empty:
|
|
693
|
+
raise
|
|
694
|
+
instance = parameter.default
|
|
695
|
+
|
|
696
|
+
# Wrap the instance in a proxy for testing
|
|
697
|
+
if self.testing:
|
|
698
|
+
return InstanceProxy(interface=parameter.annotation, instance=instance)
|
|
699
|
+
return instance
|
|
637
700
|
|
|
638
701
|
def _resolve_parameter(
|
|
639
702
|
self, provider: Provider, parameter: inspect.Parameter
|
|
@@ -667,7 +730,7 @@ class Container:
|
|
|
667
730
|
wrapped = {
|
|
668
731
|
name: value.interface
|
|
669
732
|
for name, value in instance.__dict__.items()
|
|
670
|
-
if isinstance(value,
|
|
733
|
+
if isinstance(value, InstanceProxy)
|
|
671
734
|
}
|
|
672
735
|
|
|
673
736
|
# Custom resolver function
|
|
@@ -728,7 +791,7 @@ class Container:
|
|
|
728
791
|
|
|
729
792
|
def decorator(call: Callable[P, T]) -> Callable[P, T]:
|
|
730
793
|
provider = Provider(call=call, scope=scope)
|
|
731
|
-
self._register_provider(provider, override
|
|
794
|
+
self._register_provider(provider, override)
|
|
732
795
|
return call
|
|
733
796
|
|
|
734
797
|
return decorator
|
|
@@ -790,7 +853,7 @@ class Container:
|
|
|
790
853
|
self._validate_injected_parameter(call, parameter)
|
|
791
854
|
except LookupError as exc:
|
|
792
855
|
if not self.strict:
|
|
793
|
-
logger.debug(
|
|
856
|
+
self.logger.debug(
|
|
794
857
|
f"Cannot validate the `{get_full_qualname(call)}` parameter "
|
|
795
858
|
f"`{parameter.name}` with an annotation of "
|
|
796
859
|
f"`{get_full_qualname(parameter.annotation)} due to being "
|
anydi/_provider.py
CHANGED
|
@@ -209,13 +209,17 @@ class Provider:
|
|
|
209
209
|
|
|
210
210
|
def _detect_parameters(self, signature: inspect.Signature) -> None:
|
|
211
211
|
"""Detect the parameters of the callable provider."""
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
212
|
+
parameters = []
|
|
213
|
+
for parameter in signature.parameters.values():
|
|
214
|
+
if parameter.kind == inspect.Parameter.POSITIONAL_ONLY:
|
|
215
|
+
raise TypeError(
|
|
216
|
+
f"Positional-only parameter `{parameter.name}` is not allowed "
|
|
217
|
+
f"in the provider `{self}`."
|
|
218
218
|
)
|
|
219
|
+
annotation = get_typed_annotation(
|
|
220
|
+
parameter.annotation,
|
|
221
|
+
self._call_globals,
|
|
222
|
+
module=self._call_module,
|
|
219
223
|
)
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
parameters.append(parameter.replace(annotation=annotation))
|
|
225
|
+
self._parameters = parameters
|
anydi/_types.py
CHANGED
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
4
|
from collections.abc import Iterable
|
|
5
|
-
from dataclasses import dataclass
|
|
6
5
|
from types import ModuleType
|
|
7
6
|
from typing import Annotated, Any, NamedTuple, Union
|
|
8
7
|
|
|
@@ -38,24 +37,28 @@ def is_event_type(obj: Any) -> bool:
|
|
|
38
37
|
return inspect.isclass(obj) and issubclass(obj, Event)
|
|
39
38
|
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
instance: Any
|
|
40
|
+
class InstanceProxy:
|
|
41
|
+
__slots__ = ("interface", "instance")
|
|
42
|
+
|
|
43
|
+
def __init__(self, *, interface: type[Any], instance: Any):
|
|
44
|
+
self.interface = interface
|
|
45
|
+
self.instance = instance
|
|
45
46
|
|
|
46
47
|
def __getattribute__(self, name: str) -> Any:
|
|
47
|
-
if name in
|
|
48
|
+
if name in ("interface", "instance"):
|
|
48
49
|
return object.__getattribute__(self, name)
|
|
49
50
|
return getattr(self.instance, name)
|
|
50
51
|
|
|
52
|
+
def __repr__(self) -> str:
|
|
53
|
+
return f"InstanceProxy({self.interface!r})"
|
|
54
|
+
|
|
51
55
|
|
|
52
56
|
class ProviderDecoratorArgs(NamedTuple):
|
|
53
57
|
scope: Scope
|
|
54
58
|
override: bool
|
|
55
59
|
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
class Dependency:
|
|
61
|
+
class Dependency(NamedTuple):
|
|
59
62
|
member: Any
|
|
60
63
|
module: ModuleType
|
|
61
64
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
anydi/__init__.py,sha256=OfRg2EfXD65pHTGQKhfkABMwUhw5LvsuTQV_Tv4V4wk,501
|
|
2
|
-
anydi/_container.py,sha256=
|
|
2
|
+
anydi/_container.py,sha256=Z7Jc2lCAZDxVYmXZBP1zOI_3KuWCPeCqeAuZ5gtxva0,37922
|
|
3
3
|
anydi/_context.py,sha256=7LV_SL4QWkJeiG7_4D9PZ5lmU-MPzhofxC95zCgY9Gc,2651
|
|
4
|
-
anydi/
|
|
5
|
-
anydi/
|
|
6
|
-
anydi/_types.py,sha256=55Wvaxcs2DPpVXrMqhHebT_ZeGDnH-H_zhND306vaoU,1397
|
|
4
|
+
anydi/_provider.py,sha256=W42y8wbsnWbb9B9gI-pnEa-lsz68nK0VIm55CJW3pWg,7457
|
|
5
|
+
anydi/_types.py,sha256=Vttj9GTp9g0KKpK-uqolLfVZJPIM7f7_YL8bPlablcQ,1539
|
|
7
6
|
anydi/_utils.py,sha256=INI0jNIXrJ6LS4zqJymMO2yUEobpxmBGASf4G_vR6AU,4378
|
|
8
7
|
anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
8
|
anydi/ext/_utils.py,sha256=U6sRqWzccWUu7eMhbXX1NrwcaxitQF9cO1KxnKF37gw,2566
|
|
@@ -23,8 +22,8 @@ anydi/ext/pytest_plugin.py,sha256=3x_ZYFcLp4ZCRrs7neoohmWz56O9ydm92jxi_LnyD7w,42
|
|
|
23
22
|
anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
23
|
anydi/ext/starlette/middleware.py,sha256=9CQtGg5ZzUz2gFSzJr8U4BWzwNjK8XMctm3n52M77Z0,792
|
|
25
24
|
anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
anydi-0.
|
|
27
|
-
anydi-0.
|
|
28
|
-
anydi-0.
|
|
29
|
-
anydi-0.
|
|
30
|
-
anydi-0.
|
|
25
|
+
anydi-0.35.0.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
|
|
26
|
+
anydi-0.35.0.dist-info/METADATA,sha256=zFbrRuAZdaZ3Yt_sCKetsyAcRP9x834abiGENnn_8aA,5064
|
|
27
|
+
anydi-0.35.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
28
|
+
anydi-0.35.0.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
|
|
29
|
+
anydi-0.35.0.dist-info/RECORD,,
|
anydi/_logger.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|