anydi 0.25.0a1__py3-none-any.whl → 0.25.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 CHANGED
@@ -15,21 +15,16 @@ from typing import (
15
15
  Awaitable,
16
16
  Callable,
17
17
  ContextManager,
18
- Dict,
19
18
  Iterable,
20
19
  Iterator,
21
- List,
22
20
  Mapping,
23
- Optional,
24
21
  Sequence,
25
- Type,
26
22
  TypeVar,
27
- Union,
28
23
  cast,
29
24
  overload,
30
25
  )
31
26
 
32
- from typing_extensions import Annotated, ParamSpec, final, get_args, get_origin
27
+ from typing_extensions import ParamSpec, final, get_args, get_origin
33
28
 
34
29
  try:
35
30
  from types import NoneType
@@ -48,12 +43,18 @@ from ._logger import logger
48
43
  from ._module import Module, ModuleRegistry
49
44
  from ._scanner import Scanner
50
45
  from ._types import AnyInterface, Interface, Provider, Scope, is_marker
51
- from ._utils import get_full_qualname, get_signature, is_builtin_type
46
+ from ._utils import (
47
+ get_full_qualname,
48
+ get_typed_parameters,
49
+ get_typed_return_annotation,
50
+ has_resource_origin,
51
+ is_builtin_type,
52
+ )
52
53
 
53
54
  T = TypeVar("T", bound=Any)
54
55
  P = ParamSpec("P")
55
56
 
56
- ALLOWED_SCOPES: Dict[Scope, List[Scope]] = {
57
+ ALLOWED_SCOPES: dict[Scope, list[Scope]] = {
57
58
  "singleton": ["singleton"],
58
59
  "request": ["request", "singleton"],
59
60
  "transient": ["transient", "singleton", "request"],
@@ -71,10 +72,9 @@ class Container:
71
72
  def __init__(
72
73
  self,
73
74
  *,
74
- providers: Optional[Mapping[Type[Any], Provider]] = None,
75
- modules: Optional[
76
- Sequence[Union[Module, Type[Module], Callable[[Container], None]]]
77
- ] = None,
75
+ providers: Mapping[type[Any], Provider] | None = None,
76
+ modules: Sequence[Module | type[Module] | Callable[[Container], None]]
77
+ | None = None,
78
78
  strict: bool = False,
79
79
  ) -> None:
80
80
  """Initialize the AnyDI instance.
@@ -84,13 +84,13 @@ class Container:
84
84
  modules: Optional sequence of modules to register during initialization.
85
85
  strict: Whether to enable strict mode. Defaults to False.
86
86
  """
87
- self._providers: Dict[Type[Any], Provider] = {}
87
+ self._providers: dict[type[Any], Provider] = {}
88
88
  self._singleton_context = SingletonContext(self)
89
89
  self._transient_context = TransientContext(self)
90
- self._request_context_var: ContextVar[Optional[RequestContext]] = ContextVar(
90
+ self._request_context_var: ContextVar[RequestContext | None] = ContextVar(
91
91
  "request_context", default=None
92
92
  )
93
- self._override_instances: Dict[Type[Any], Any] = {}
93
+ self._override_instances: dict[type[Any], Any] = {}
94
94
  self._strict = strict
95
95
 
96
96
  # Components
@@ -117,7 +117,7 @@ class Container:
117
117
  return self._strict
118
118
 
119
119
  @property
120
- def providers(self) -> Dict[Type[Any], Provider]:
120
+ def providers(self) -> dict[type[Any], Provider]:
121
121
  """Get the registered providers.
122
122
 
123
123
  Returns:
@@ -333,7 +333,7 @@ class Container:
333
333
  """
334
334
  related_providers = []
335
335
 
336
- for parameter in provider.parameters.values():
336
+ for parameter in provider.parameters:
337
337
  if parameter.annotation is inspect._empty: # noqa
338
338
  raise TypeError(
339
339
  f"Missing provider `{provider}` "
@@ -363,7 +363,7 @@ class Container:
363
363
  "registered with matching scopes."
364
364
  )
365
365
 
366
- def _detect_scope(self, obj: Callable[..., Any]) -> Optional[Scope]:
366
+ def _detect_scope(self, obj: Callable[..., Any]) -> Scope | None:
367
367
  """Detect the scope for a provider.
368
368
 
369
369
  Args:
@@ -372,7 +372,7 @@ class Container:
372
372
  The auto scope, or None if the auto scope cannot be detected.
373
373
  """
374
374
  has_transient, has_request, has_singleton = False, False, False
375
- for parameter in get_signature(obj).parameters.values():
375
+ for parameter in get_typed_parameters(obj):
376
376
  sub_provider = self._get_or_register_provider(parameter.annotation)
377
377
  if not has_transient and sub_provider.scope == "transient":
378
378
  has_transient = True
@@ -389,7 +389,7 @@ class Container:
389
389
  return None
390
390
 
391
391
  def register_module(
392
- self, module: Union[Module, Type[Module], Callable[[Container], None]]
392
+ self, module: Module | type[Module] | Callable[[Container], None]
393
393
  ) -> None:
394
394
  """Register a module as a callable, module type, or module instance.
395
395
 
@@ -633,14 +633,11 @@ class Container:
633
633
  def inject(self) -> Callable[[Callable[P, T]], Callable[P, T]]: ...
634
634
 
635
635
  def inject(
636
- self, obj: Union[Callable[P, Union[T, Awaitable[T]]], None] = None
637
- ) -> Union[
638
- Callable[
639
- [Callable[P, Union[T, Awaitable[T]]]],
640
- Callable[P, Union[T, Awaitable[T]]],
641
- ],
642
- Callable[P, Union[T, Awaitable[T]]],
643
- ]:
636
+ self, obj: Callable[P, T | Awaitable[T]] | None = None
637
+ ) -> (
638
+ Callable[[Callable[P, T | Awaitable[T]]], Callable[P, T | Awaitable[T]]]
639
+ | Callable[P, T | Awaitable[T]]
640
+ ):
644
641
  """Decorator to inject dependencies into a callable.
645
642
 
646
643
  Args:
@@ -652,8 +649,8 @@ class Container:
652
649
  """
653
650
 
654
651
  def decorator(
655
- obj: Callable[P, Union[T, Awaitable[T]]],
656
- ) -> Callable[P, Union[T, Awaitable[T]]]:
652
+ obj: Callable[P, T | Awaitable[T]],
653
+ ) -> Callable[P, T | Awaitable[T]]:
657
654
  injected_params = self._get_injected_params(obj)
658
655
 
659
656
  if inspect.iscoroutinefunction(obj):
@@ -694,12 +691,9 @@ class Container:
694
691
  def scan(
695
692
  self,
696
693
  /,
697
- packages: Union[
698
- Union[types.ModuleType, str],
699
- Iterable[Union[types.ModuleType, str]],
700
- ],
694
+ packages: types.ModuleType | str | Iterable[types.ModuleType | str],
701
695
  *,
702
- tags: Optional[Iterable[str]] = None,
696
+ tags: Iterable[str] | None = None,
703
697
  ) -> None:
704
698
  """Scan packages or modules for decorated members and inject dependencies.
705
699
 
@@ -723,32 +717,28 @@ class Container:
723
717
  Raises:
724
718
  TypeError: If the provider return annotation is missing or invalid.
725
719
  """
726
- annotation = get_signature(obj).return_annotation
720
+ annotation = get_typed_return_annotation(obj)
727
721
 
728
- if annotation is inspect._empty: # noqa
722
+ if annotation is None:
729
723
  raise TypeError(
730
724
  f"Missing `{get_full_qualname(obj)}` provider return annotation."
731
725
  )
732
726
 
733
- origin = get_origin(annotation) or annotation
734
- args = get_args(annotation)
727
+ origin = get_origin(annotation)
735
728
 
736
- # Supported generic types
737
- if origin in (list, dict, tuple, Annotated):
729
+ if has_resource_origin(origin):
730
+ args = get_args(annotation)
738
731
  if args:
739
- return annotation
732
+ return args[0]
740
733
  else:
741
734
  raise TypeError(
742
- f"Cannot use `{get_full_qualname(obj)}` generic type annotation "
735
+ f"Cannot use `{get_full_qualname(obj)}` resource type annotation "
743
736
  "without actual type."
744
737
  )
745
738
 
746
- try:
747
- return args[0]
748
- except IndexError:
749
- return annotation
739
+ return annotation
750
740
 
751
- def _get_injected_params(self, obj: Callable[..., Any]) -> Dict[str, Any]:
741
+ def _get_injected_params(self, obj: Callable[..., Any]) -> dict[str, Any]:
752
742
  """Get the injected parameters of a callable object.
753
743
 
754
744
  Args:
@@ -759,7 +749,7 @@ class Container:
759
749
  of the injected parameters.
760
750
  """
761
751
  injected_params = {}
762
- for parameter in get_signature(obj).parameters.values():
752
+ for parameter in get_typed_parameters(obj):
763
753
  if not is_marker(parameter.default):
764
754
  continue
765
755
  try:
anydi/_context.py CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import abc
4
4
  import contextlib
5
5
  from types import TracebackType
6
- from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Type, TypeVar, cast
6
+ from typing import TYPE_CHECKING, Any, TypeVar, cast
7
7
 
8
8
  from typing_extensions import Self, final
9
9
 
@@ -87,7 +87,7 @@ class ScopedContext(abc.ABC):
87
87
 
88
88
  def _get_provider_arguments(
89
89
  self, provider: Provider
90
- ) -> Tuple[List[Any], Dict[str, Any]]:
90
+ ) -> tuple[list[Any], dict[str, Any]]:
91
91
  """Retrieve the arguments for a provider.
92
92
 
93
93
  Args:
@@ -97,7 +97,7 @@ class ScopedContext(abc.ABC):
97
97
  The arguments for the provider.
98
98
  """
99
99
  args, kwargs = [], {}
100
- for parameter in provider.parameters.values():
100
+ for parameter in provider.parameters:
101
101
  instance = self.container.resolve(parameter.annotation)
102
102
  if parameter.kind == parameter.POSITIONAL_ONLY:
103
103
  args.append(instance)
@@ -107,7 +107,7 @@ class ScopedContext(abc.ABC):
107
107
 
108
108
  async def _aget_provider_arguments(
109
109
  self, provider: Provider
110
- ) -> Tuple[List[Any], Dict[str, Any]]:
110
+ ) -> tuple[list[Any], dict[str, Any]]:
111
111
  """Asynchronously retrieve the arguments for a provider.
112
112
 
113
113
  Args:
@@ -117,7 +117,7 @@ class ScopedContext(abc.ABC):
117
117
  The arguments for the provider.
118
118
  """
119
119
  args, kwargs = [], {}
120
- for parameter in provider.parameters.values():
120
+ for parameter in provider.parameters:
121
121
  instance = await self.container.aresolve(parameter.annotation)
122
122
  if parameter.kind == parameter.POSITIONAL_ONLY:
123
123
  args.append(instance)
@@ -132,7 +132,7 @@ class ResourceScopedContext(ScopedContext):
132
132
  def __init__(self, container: Container) -> None:
133
133
  """Initialize the ScopedContext."""
134
134
  super().__init__(container)
135
- self._instances: Dict[Type[Any], Any] = {}
135
+ self._instances: dict[type[Any], Any] = {}
136
136
  self._stack = contextlib.ExitStack()
137
137
  self._async_stack = contextlib.AsyncExitStack()
138
138
 
@@ -237,7 +237,7 @@ class ResourceScopedContext(ScopedContext):
237
237
 
238
238
  def __exit__(
239
239
  self,
240
- exc_type: Type[BaseException] | None,
240
+ exc_type: type[BaseException] | None,
241
241
  exc_val: BaseException | None,
242
242
  exc_tb: TracebackType | None,
243
243
  ) -> None:
@@ -265,7 +265,7 @@ class ResourceScopedContext(ScopedContext):
265
265
 
266
266
  async def __aexit__(
267
267
  self,
268
- exc_type: Type[BaseException] | None,
268
+ exc_type: type[BaseException] | None,
269
269
  exc_val: BaseException | None,
270
270
  exc_tb: TracebackType | None,
271
271
  ) -> None:
anydi/_module.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import inspect
6
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Tuple, Type, TypeVar, Union
6
+ from typing import TYPE_CHECKING, Any, Callable, TypeVar
7
7
 
8
8
  from typing_extensions import Concatenate, NamedTuple, ParamSpec
9
9
 
@@ -24,7 +24,7 @@ class ModuleMeta(type):
24
24
  and stores it in the `providers` attribute.
25
25
  """
26
26
 
27
- def __new__(cls, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any]) -> Any:
27
+ def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> Any:
28
28
  """Create a new instance of the ModuleMeta class.
29
29
 
30
30
  This method extracts provider information from the class attributes and
@@ -49,7 +49,7 @@ class ModuleMeta(type):
49
49
  class Module(metaclass=ModuleMeta):
50
50
  """A base class for defining AnyDI modules."""
51
51
 
52
- providers: List[Tuple[str, ProviderDecoratorArgs]]
52
+ providers: list[tuple[str, ProviderDecoratorArgs]]
53
53
 
54
54
  def configure(self, container: Container) -> None:
55
55
  """Configure the AnyDI container with providers and their dependencies.
@@ -67,7 +67,7 @@ class ModuleRegistry:
67
67
  self.container = container
68
68
 
69
69
  def register(
70
- self, module: Union[Module, Type[Module], Callable[[Container], None]]
70
+ self, module: Module | type[Module] | Callable[[Container], None]
71
71
  ) -> None:
72
72
  """Register a module as a callable, module type, or module instance.
73
73
 
anydi/_scanner.py CHANGED
@@ -10,8 +10,6 @@ from typing import (
10
10
  Any,
11
11
  Callable,
12
12
  Iterable,
13
- List,
14
- Optional,
15
13
  TypeVar,
16
14
  Union,
17
15
  cast,
@@ -22,7 +20,7 @@ from typing import (
22
20
  from typing_extensions import NamedTuple, ParamSpec
23
21
 
24
22
  from ._types import is_marker
25
- from ._utils import get_signature
23
+ from ._utils import get_typed_parameters
26
24
 
27
25
  if TYPE_CHECKING:
28
26
  from ._container import Container
@@ -56,9 +54,9 @@ class Scanner:
56
54
  def scan(
57
55
  self,
58
56
  /,
59
- packages: Union[Union[ModuleType, str], Iterable[Union[ModuleType, str]]],
57
+ packages: ModuleType | str | Iterable[ModuleType | str],
60
58
  *,
61
- tags: Optional[Iterable[str]] = None,
59
+ tags: Iterable[str] | None = None,
62
60
  ) -> None:
63
61
  """Scan packages or modules for decorated members and inject dependencies.
64
62
 
@@ -68,10 +66,10 @@ class Scanner:
68
66
  tags: Optional list of tags to filter the scanned members. Only members
69
67
  with at least one matching tag will be scanned. Defaults to None.
70
68
  """
71
- dependencies: List[Dependency] = []
69
+ dependencies: list[Dependency] = []
72
70
 
73
71
  if isinstance(packages, Iterable) and not isinstance(packages, str):
74
- scan_packages: Iterable[Union[ModuleType, str]] = packages
72
+ scan_packages: Iterable[ModuleType | str] = packages
75
73
  else:
76
74
  scan_packages = cast(Iterable[Union[ModuleType, str]], [packages])
77
75
 
@@ -84,10 +82,10 @@ class Scanner:
84
82
 
85
83
  def _scan_package(
86
84
  self,
87
- package: Union[ModuleType, str],
85
+ package: ModuleType | str,
88
86
  *,
89
- tags: Optional[Iterable[str]] = None,
90
- ) -> List[Dependency]:
87
+ tags: Iterable[str] | None = None,
88
+ ) -> list[Dependency]:
91
89
  """Scan a package or module for decorated members.
92
90
 
93
91
  Args:
@@ -107,7 +105,7 @@ class Scanner:
107
105
  if not package_path:
108
106
  return self._scan_module(package, tags=tags)
109
107
 
110
- dependencies: List[Dependency] = []
108
+ dependencies: list[Dependency] = []
111
109
 
112
110
  for module_info in pkgutil.walk_packages(
113
111
  path=package_path, prefix=package.__name__ + "."
@@ -119,7 +117,7 @@ class Scanner:
119
117
 
120
118
  def _scan_module(
121
119
  self, module: ModuleType, *, tags: Iterable[str]
122
- ) -> List[Dependency]:
120
+ ) -> list[Dependency]:
123
121
  """Scan a module for decorated members.
124
122
 
125
123
  Args:
@@ -130,7 +128,7 @@ class Scanner:
130
128
  Returns:
131
129
  A list of scanned dependencies.
132
130
  """
133
- dependencies: List[Dependency] = []
131
+ dependencies: list[Dependency] = []
134
132
 
135
133
  for _, member in inspect.getmembers(module):
136
134
  if getattr(member, "__module__", None) != module.__name__ or not callable(
@@ -159,10 +157,10 @@ class Scanner:
159
157
 
160
158
  # Get by Marker
161
159
  if inspect.isclass(member):
162
- signature = get_signature(member.__init__)
160
+ parameters = get_typed_parameters(member.__init__)
163
161
  else:
164
- signature = get_signature(member)
165
- for parameter in signature.parameters.values():
162
+ parameters = get_typed_parameters(member)
163
+ for parameter in parameters:
166
164
  if is_marker(parameter.default):
167
165
  dependencies.append(
168
166
  self._create_dependency(member=member, module=module)
@@ -188,7 +186,7 @@ class Scanner:
188
186
 
189
187
  class InjectDecoratorArgs(NamedTuple):
190
188
  wrapped: bool
191
- tags: Optional[Iterable[str]]
189
+ tags: Iterable[str] | None
192
190
 
193
191
 
194
192
  @overload
@@ -197,20 +195,14 @@ def injectable(obj: Callable[P, T]) -> Callable[P, T]: ...
197
195
 
198
196
  @overload
199
197
  def injectable(
200
- *, tags: Optional[Iterable[str]] = None
198
+ *, tags: Iterable[str] | None = None
201
199
  ) -> Callable[[Callable[P, T]], Callable[P, T]]: ...
202
200
 
203
201
 
204
202
  def injectable(
205
- obj: Optional[Callable[P, T]] = None,
206
- tags: Optional[Iterable[str]] = None,
207
- ) -> Union[
208
- Callable[
209
- [Callable[P, T]],
210
- Callable[P, T],
211
- ],
212
- Callable[P, T],
213
- ]:
203
+ obj: Callable[P, T] | None = None,
204
+ tags: Iterable[str] | None = None,
205
+ ) -> Callable[[Callable[P, T]], Callable[P, T]] | Callable[P, T]:
214
206
  """Decorator for marking a function or method as requiring dependency injection.
215
207
 
216
208
  Args:
anydi/_types.py CHANGED
@@ -1,11 +1,13 @@
1
+ from __future__ import annotations
2
+
1
3
  import inspect
2
4
  from dataclasses import dataclass
3
5
  from functools import cached_property
4
6
  from typing import Any, Callable, Type, TypeVar, Union
5
7
 
6
- from typing_extensions import Annotated, Literal, Mapping, Self, TypeAlias
8
+ from typing_extensions import Annotated, Literal, Self, TypeAlias
7
9
 
8
- from ._utils import get_full_qualname, get_signature
10
+ from ._utils import get_full_qualname, get_typed_parameters
9
11
 
10
12
  Scope = Literal["transient", "singleton", "request"]
11
13
 
@@ -58,13 +60,13 @@ class Provider:
58
60
  return get_full_qualname(self.obj)
59
61
 
60
62
  @cached_property
61
- def parameters(self) -> Mapping[str, inspect.Parameter]:
63
+ def parameters(self) -> list[inspect.Parameter]:
62
64
  """Returns the parameters of the provider as a mapping.
63
65
 
64
66
  Returns:
65
67
  The parameters of the provider.
66
68
  """
67
- return get_signature(self.obj).parameters
69
+ return get_typed_parameters(self.obj)
68
70
 
69
71
  @cached_property
70
72
  def is_class(self) -> bool:
anydi/_utils.py CHANGED
@@ -1,10 +1,12 @@
1
1
  """Shared AnyDI utils module."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import builtins
4
6
  import functools
5
7
  import inspect
6
8
  import sys
7
- from typing import Any, Callable, Dict, Type, TypeVar
9
+ from typing import Any, AsyncIterator, Callable, ForwardRef, Iterator, TypeVar, cast
8
10
 
9
11
  from typing_extensions import Annotated, ParamSpec, get_origin
10
12
 
@@ -14,22 +16,23 @@ except ImportError:
14
16
  anyio = None # type: ignore[assignment]
15
17
 
16
18
 
17
- T = TypeVar("T")
18
- P = ParamSpec("P")
19
+ if sys.version_info < (3, 9): # pragma: nocover
19
20
 
21
+ def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
22
+ return type_._evaluate(globalns, localns) # noqa
20
23
 
21
- def get_full_qualname(obj: Any) -> str:
22
- """Get the fully qualified name of an object.
24
+ else:
25
+
26
+ def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
27
+ return cast(Any, type_)._evaluate(globalns, localns, set()) # noqa
23
28
 
24
- This function returns the fully qualified name of the given object,
25
- which includes both the module name and the object's qualname.
26
29
 
27
- Args:
28
- obj: The object for which to retrieve the fully qualified name.
30
+ T = TypeVar("T")
31
+ P = ParamSpec("P")
32
+
29
33
 
30
- Returns:
31
- The fully qualified name of the object.
32
- """
34
+ def get_full_qualname(obj: Any) -> str:
35
+ """Get the fully qualified name of an object."""
33
36
  origin = get_origin(obj)
34
37
  if origin is Annotated:
35
38
  metadata = ", ".join(
@@ -53,35 +56,55 @@ def get_full_qualname(obj: Any) -> str:
53
56
  return f"{module_name}.{qualname}"
54
57
 
55
58
 
56
- def is_builtin_type(tp: Type[Any]) -> bool:
57
- """
58
- Check if the given type is a built-in type.
59
- Args:
60
- tp (type): The type to check.
61
- Returns:
62
- bool: True if the type is a built-in type, False otherwise.
63
- """
59
+ def is_builtin_type(tp: type[Any]) -> bool:
60
+ """Check if the given type is a built-in type."""
64
61
  return tp.__module__ == builtins.__name__
65
62
 
66
63
 
67
- @functools.lru_cache(maxsize=None)
68
- def get_signature(obj: Callable[..., Any]) -> inspect.Signature:
69
- """Get the signature of a callable object.
64
+ def make_forwardref(annotation: str, globalns: dict[str, Any]) -> Any:
65
+ """Create a forward reference from a string annotation."""
66
+ forward_ref = ForwardRef(annotation)
67
+ return evaluate_forwardref(forward_ref, globalns, globalns)
68
+
70
69
 
71
- This function uses the `inspect.signature` function to retrieve the signature
72
- of the given callable object. It applies an LRU cache decorator to improve
73
- performance by caching the signatures of previously inspected objects.
70
+ def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:
71
+ """Get the typed annotation of a parameter."""
72
+ if isinstance(annotation, str):
73
+ annotation = ForwardRef(annotation)
74
+ annotation = evaluate_forwardref(annotation, globalns, globalns)
75
+ return annotation
74
76
 
75
- Args:
76
- obj: The callable object to inspect.
77
77
 
78
- Returns:
79
- The signature of the callable object.
80
- """
81
- signature_kwargs: Dict[str, Any] = {}
82
- if sys.version_info >= (3, 10):
83
- signature_kwargs["eval_str"] = True
84
- return inspect.signature(obj, **signature_kwargs)
78
+ def get_typed_return_annotation(obj: Callable[..., Any]) -> Any:
79
+ """Get the typed return annotation of a callable object."""
80
+ signature = inspect.signature(obj)
81
+ annotation = signature.return_annotation
82
+ if annotation is inspect.Signature.empty:
83
+ return None
84
+ globalns = getattr(obj, "__globals__", {})
85
+ return get_typed_annotation(annotation, globalns)
86
+
87
+
88
+ def get_typed_parameters(obj: Callable[..., Any]) -> list[inspect.Parameter]:
89
+ """Get the typed parameters of a callable object."""
90
+ globalns = getattr(obj, "__globals__", {})
91
+ return [
92
+ parameter.replace(
93
+ annotation=get_typed_annotation(parameter.annotation, globalns)
94
+ )
95
+ for name, parameter in inspect.signature(obj).parameters.items()
96
+ ]
97
+
98
+
99
+ _resource_origins = (
100
+ get_origin(Iterator),
101
+ get_origin(AsyncIterator),
102
+ )
103
+
104
+
105
+ def has_resource_origin(origin: Any) -> bool:
106
+ """Check if the given origin is a resource origin."""
107
+ return origin in _resource_origins
85
108
 
86
109
 
87
110
  async def run_async(
@@ -90,19 +113,7 @@ async def run_async(
90
113
  *args: P.args,
91
114
  **kwargs: P.kwargs,
92
115
  ) -> T:
93
- """Runs the given function asynchronously using the `anyio` library.
94
-
95
- Args:
96
- func: The function to run asynchronously.
97
- args: The positional arguments to pass to the function.
98
- kwargs: The keyword arguments to pass to the function.
99
-
100
- Returns:
101
- The result of the function.
102
-
103
- Raises:
104
- ImportError: If the `anyio` library is not installed.
105
- """
116
+ """Runs the given function asynchronously using the `anyio` library."""
106
117
  if not anyio:
107
118
  raise ImportError(
108
119
  "`anyio` library is not currently installed. Please make sure to install "
@@ -1,3 +1,9 @@
1
1
  from ._container import container
2
+ from ._utils import inject_urlpatterns, register_components, register_settings
2
3
 
3
- __all__ = ["container"]
4
+ __all__ = [
5
+ "container",
6
+ "register_components",
7
+ "register_settings",
8
+ "inject_urlpatterns",
9
+ ]
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Sequence
4
+
5
+ from django.conf import settings
6
+ from typing_extensions import TypedDict
7
+
8
+
9
+ class Settings(TypedDict):
10
+ CONTAINER_FACTORY: str | None
11
+ STRICT_MODE: bool
12
+ REGISTER_SETTINGS: bool
13
+ REGISTER_COMPONENTS: bool
14
+ INJECT_URLCONF: str | Sequence[str] | None
15
+ MODULES: Sequence[str]
16
+ SCAN_PACKAGES: Sequence[str]
17
+ PATCH_NINJA: bool
18
+
19
+
20
+ DEFAULTS = Settings(
21
+ CONTAINER_FACTORY=None,
22
+ STRICT_MODE=False,
23
+ REGISTER_SETTINGS=False,
24
+ REGISTER_COMPONENTS=False,
25
+ MODULES=[],
26
+ PATCH_NINJA=False,
27
+ INJECT_URLCONF=None,
28
+ SCAN_PACKAGES=[],
29
+ )
30
+
31
+
32
+ def get_settings() -> Settings:
33
+ """Get the AnyDI settings from the Django settings."""
34
+ return Settings(
35
+ **{
36
+ **DEFAULTS,
37
+ **getattr(settings, "ANYDI", {}),
38
+ }
39
+ )
@@ -1,6 +1,107 @@
1
+ from __future__ import annotations
2
+
1
3
  from collections.abc import Iterator
4
+ from functools import wraps
5
+ from typing import Any
6
+
7
+ from django.conf import settings
8
+ from django.core.cache import BaseCache, caches
9
+ from django.db import connections
10
+ from django.db.backends.base.base import BaseDatabaseWrapper
11
+ from django.urls import URLPattern, URLResolver, get_resolver
12
+ from typing_extensions import Annotated, get_origin
13
+
14
+ import anydi
15
+
16
+
17
+ def register_settings(
18
+ container: anydi.Container, prefix: str = "django.conf.setting."
19
+ ) -> None:
20
+ """Register Django settings into the container."""
21
+
22
+ def _get_setting_value(value: Any) -> Any:
23
+ return lambda: value
24
+
25
+ for setting_name in dir(settings):
26
+ setting_value = getattr(settings, setting_name)
27
+ if not setting_name.isupper():
28
+ continue
29
+
30
+ container.register(
31
+ Annotated[Any, f"{prefix}{setting_name}"],
32
+ _get_setting_value(setting_value),
33
+ scope="singleton",
34
+ )
35
+
36
+ def _resolve(resolve: Any) -> Any:
37
+ @wraps(resolve)
38
+ def wrapper(interface: Any) -> Any:
39
+ return resolve(_aware_settings(interface, prefix))
40
+
41
+ return wrapper
42
+
43
+ def _aresolve(resolve: Any) -> Any:
44
+ @wraps(resolve)
45
+ async def wrapper(interface: Any) -> Any:
46
+ return await resolve(_aware_settings(interface, prefix))
47
+
48
+ return wrapper
49
+
50
+ # Patch resolvers
51
+ container.resolve = _resolve(container.resolve) # type: ignore[method-assign] # noqa
52
+ container.aresolve = _aresolve(container.aresolve) # type: ignore[method-assign] # noqa
53
+
54
+
55
+ def _aware_settings(interface: Any, prefix: str) -> Any:
56
+ origin = get_origin(interface)
57
+ if origin is not Annotated:
58
+ return interface # pragma: no cover
59
+ named = interface.__metadata__[-1]
60
+
61
+ if isinstance(named, str) and named.startswith(prefix):
62
+ _, setting_name = named.rsplit(prefix, maxsplit=1)
63
+ return Annotated[Any, f"{prefix}{setting_name}"]
64
+ return interface
65
+
66
+
67
+ def register_components(container: anydi.Container) -> None:
68
+ """Register Django components into the container."""
69
+
70
+ # Register caches
71
+ def _get_cache(cache_name: str) -> Any:
72
+ return lambda: caches[cache_name]
73
+
74
+ for cache_name in caches:
75
+ container.register(
76
+ Annotated[BaseCache, cache_name],
77
+ _get_cache(cache_name),
78
+ scope="singleton",
79
+ )
80
+
81
+ # Register database connections
82
+ def _get_connection(alias: str) -> Any:
83
+ return lambda: connections[alias]
84
+
85
+ for alias in connections:
86
+ container.register(
87
+ Annotated[BaseDatabaseWrapper, alias],
88
+ _get_connection(alias),
89
+ scope="singleton",
90
+ )
91
+
2
92
 
3
- from django.urls import URLPattern, URLResolver
93
+ def inject_urlpatterns(container: anydi.Container, *, urlconf: str) -> None:
94
+ """Auto-inject the container into views."""
95
+ resolver = get_resolver(urlconf)
96
+ for pattern in iter_urlpatterns(resolver.url_patterns):
97
+ # Skip already injected views
98
+ if hasattr(pattern.callback, "_injected"):
99
+ continue
100
+ # Skip django-ninja views
101
+ if pattern.lookup_str.startswith("ninja."):
102
+ continue # pragma: no cover
103
+ pattern.callback = container.inject(pattern.callback)
104
+ pattern.callback._injected = True # type: ignore[attr-defined]
4
105
 
5
106
 
6
107
  def iter_urlpatterns(
anydi/ext/django/apps.py CHANGED
@@ -1,22 +1,18 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import types
3
- from asyncio import get_running_loop
4
- from functools import wraps
5
- from typing import Any, Callable, cast
5
+ from typing import Callable, cast
6
6
 
7
7
  from django.apps import AppConfig
8
8
  from django.conf import settings
9
- from django.core.cache import BaseCache, caches
10
9
  from django.core.exceptions import ImproperlyConfigured
11
- from django.db import connections
12
- from django.db.backends.base.base import BaseDatabaseWrapper
13
- from django.urls import get_resolver
14
10
  from django.utils.module_loading import import_string
15
- from typing_extensions import Annotated, get_origin
16
11
 
17
12
  import anydi
18
13
 
19
- from ._utils import iter_urlpatterns
14
+ from ._settings import get_settings
15
+ from ._utils import inject_urlpatterns, register_components, register_settings
20
16
 
21
17
  logger = logging.getLogger(__name__)
22
18
 
@@ -25,39 +21,44 @@ class ContainerConfig(AppConfig): # type: ignore[misc]
25
21
  name = "anydi.ext.django"
26
22
  label = "anydi_django"
27
23
 
28
- # Prefix for Django settings
29
- settings_prefix = "django.conf.settings."
30
-
31
24
  def __init__(self, app_name: str, app_module: types.ModuleType | None) -> None:
32
25
  super().__init__(app_name, app_module)
26
+ self.settings = get_settings()
33
27
  # Create a container
34
- container_getter_path = getattr(settings, "ANYDI_CONTAINER_GETTER", None)
35
- if container_getter_path:
28
+ container_factory_path = self.settings["CONTAINER_FACTORY"]
29
+ if container_factory_path:
36
30
  try:
37
- container_getter = cast(
38
- Callable[[], anydi.Container], import_string(container_getter_path)
31
+ container_factory = cast(
32
+ Callable[[], anydi.Container], import_string(container_factory_path)
39
33
  )
40
34
  except ImportError as exc:
41
35
  raise ImproperlyConfigured(
42
- f"Cannot import container getter '{container_getter_path}'."
36
+ f"Cannot import container factory '{container_factory_path}'."
43
37
  ) from exc
44
- self.container = container_getter()
38
+ self.container = container_factory()
45
39
  else:
46
40
  self.container = anydi.Container(
47
- strict=getattr(settings, "ANYDI_STRICT_MODE", False),
41
+ strict=self.settings["STRICT_MODE"],
48
42
  )
49
43
 
50
44
  def ready(self) -> None: # noqa: C901
51
45
  # Register Django settings
52
- if getattr(settings, "ANYDI_REGISTER_SETTINGS", False):
53
- self.register_settings()
46
+ if self.settings["REGISTER_SETTINGS"]:
47
+ register_settings(
48
+ self.container,
49
+ prefix=getattr(
50
+ settings,
51
+ "ANYDI_SETTINGS_PREFIX",
52
+ "django.conf.settings.",
53
+ ),
54
+ )
54
55
 
55
56
  # Register Django components
56
- if getattr(settings, "ANYDI_REGISTER_COMPONENTS", False):
57
- self.register_components()
57
+ if self.settings["REGISTER_COMPONENTS"]:
58
+ register_components(self.container)
58
59
 
59
60
  # Register modules
60
- for module_path in getattr(settings, "ANYDI_MODULES", []):
61
+ for module_path in self.settings["MODULES"]:
61
62
  try:
62
63
  module_cls = import_string(module_path)
63
64
  except ImportError as exc:
@@ -67,111 +68,18 @@ class ContainerConfig(AppConfig): # type: ignore[misc]
67
68
  self.container.register_module(module_cls)
68
69
 
69
70
  # Patching the django-ninja framework if it installed
70
- if getattr(settings, "ANYDI_PATCH_NINJA", False):
71
- self.patch_ninja()
71
+ if self.settings["PATCH_NINJA"]:
72
+ from .ninja import patch_ninja
73
+
74
+ patch_ninja()
72
75
 
73
76
  # Auto-injecting the container into views
74
- if urlconf := getattr(settings, "ANYDI_AUTO_INJECT_URLCONF", None):
75
- self.auto_inject_urlconf(urlconf)
77
+ if urlconf := self.settings["INJECT_URLCONF"]:
78
+ if isinstance(urlconf, str):
79
+ urlconf = [urlconf]
80
+ for u in urlconf:
81
+ inject_urlpatterns(self.container, urlconf=u)
76
82
 
77
83
  # Scan packages
78
- for scan_package in getattr(settings, "ANYDI_SCAN_PACKAGES", []):
84
+ for scan_package in self.settings["SCAN_PACKAGES"]:
79
85
  self.container.scan(scan_package)
80
-
81
- # Start the container
82
- if getattr(settings, "ANYDI_START_CONTAINER", False):
83
- try:
84
- get_running_loop()
85
- except RuntimeError:
86
- logger.warning(
87
- "Starting the container is only supported in an async context."
88
- )
89
- else:
90
- self.container.start()
91
-
92
- def register_settings(self) -> None: # noqa: C901
93
- """Register Django settings into the container."""
94
-
95
- def _get_setting_value(value: Any) -> Any:
96
- return lambda: value
97
-
98
- for setting_name in dir(settings):
99
- setting_value = getattr(settings, setting_name)
100
- if not setting_name.isupper():
101
- continue
102
-
103
- self.container.register(
104
- Annotated[Any, f"{self.settings_prefix}{setting_name}"],
105
- _get_setting_value(setting_value),
106
- scope="singleton",
107
- )
108
-
109
- def _aware_settings(interface: Any) -> Any:
110
- origin = get_origin(interface)
111
- if origin is not Annotated:
112
- return interface # pragma: no cover
113
- named = interface.__metadata__[-1]
114
-
115
- if isinstance(named, str) and named.startswith(self.settings_prefix):
116
- _, setting_name = named.rsplit(self.settings_prefix, maxsplit=1)
117
- return Annotated[Any, f"{self.settings_prefix}{setting_name}"]
118
- return interface
119
-
120
- def _resolve(resolve: Any) -> Any:
121
- @wraps(resolve)
122
- def wrapper(interface: Any) -> Any:
123
- return resolve(_aware_settings(interface))
124
-
125
- return wrapper
126
-
127
- def _aresolve(resolve: Any) -> Any:
128
- @wraps(resolve)
129
- async def wrapper(interface: Any) -> Any:
130
- return await resolve(_aware_settings(interface))
131
-
132
- return wrapper
133
-
134
- # Patch resolvers
135
- self.container.resolve = _resolve(self.container.resolve) # type: ignore[method-assign] # noqa
136
- self.container.aresolve = _aresolve(self.container.aresolve) # type: ignore[method-assign] # noqa
137
-
138
- def register_components(self) -> None:
139
- """Register Django components into the container."""
140
-
141
- # Register caches
142
- def _get_cache(cache_name: str) -> Any:
143
- return lambda: caches[cache_name]
144
-
145
- for cache_name in caches:
146
- self.container.register(
147
- Annotated[BaseCache, cache_name],
148
- _get_cache(cache_name),
149
- scope="singleton",
150
- )
151
-
152
- # Register database connections
153
- def _get_connection(alias: str) -> Any:
154
- return lambda: connections[alias]
155
-
156
- for alias in connections:
157
- self.container.register(
158
- Annotated[BaseDatabaseWrapper, alias],
159
- _get_connection(alias),
160
- scope="singleton",
161
- )
162
-
163
- def auto_inject_urlconf(self, urlconf: str) -> None:
164
- """Auto-inject the container into views."""
165
- resolver = get_resolver(urlconf)
166
- for pattern in iter_urlpatterns(resolver.url_patterns):
167
- # Skip django-ninja views
168
- if pattern.lookup_str.startswith("ninja."):
169
- continue # pragma: no cover
170
- pattern.callback = self.container.inject(pattern.callback)
171
-
172
- @staticmethod
173
- def patch_ninja() -> None:
174
- """Patch the django-ninja framework."""
175
- from .ninja import patch
176
-
177
- patch()
@@ -0,0 +1,26 @@
1
+ from typing import Callable
2
+
3
+ from asgiref.sync import iscoroutinefunction
4
+ from django.http import HttpRequest, HttpResponse
5
+ from django.utils.decorators import sync_and_async_middleware
6
+
7
+ from ._container import container
8
+
9
+
10
+ @sync_and_async_middleware # type: ignore[misc]
11
+ def request_scoped_middleware(
12
+ get_response: Callable[[HttpRequest], HttpResponse],
13
+ ) -> Callable[[HttpRequest], HttpResponse]:
14
+ if iscoroutinefunction(get_response):
15
+
16
+ async def async_middleware(request: HttpRequest) -> HttpResponse:
17
+ async with container.arequest_context():
18
+ return await get_response(request)
19
+
20
+ return async_middleware
21
+
22
+ def middleware(request: HttpRequest) -> HttpResponse:
23
+ with container.request_context():
24
+ return get_response(request)
25
+
26
+ return middleware
@@ -10,7 +10,7 @@ from ._operation import AsyncOperation, Operation
10
10
  from ._signature import ViewSignature
11
11
 
12
12
 
13
- def patch() -> None:
13
+ def patch_ninja() -> None:
14
14
  operation.ViewSignature = ViewSignature # type: ignore[attr-defined]
15
15
  operation.Operation = Operation # type: ignore[misc]
16
16
  operation.AsyncOperation = AsyncOperation # type: ignore[misc]
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from typing import Any
2
4
 
3
5
  from django.http import HttpRequest, HttpResponseBase
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import inspect
2
4
  from collections.abc import Callable
3
5
  from typing import Any
@@ -9,7 +11,7 @@ from ninja.signature.details import (
9
11
  )
10
12
  from ninja.signature.utils import get_path_param_names, get_typed_signature
11
13
 
12
- from anydi._types import Marker # noqa
14
+ from anydi._types import is_marker # noqa
13
15
 
14
16
 
15
17
  class ViewSignature(BaseViewSignature):
@@ -44,7 +46,7 @@ class ViewSignature(BaseViewSignature):
44
46
  continue
45
47
 
46
48
  # Skip default values that are anydi dependency markers
47
- if isinstance(arg.default, Marker):
49
+ if is_marker(arg.default):
48
50
  self.dependencies.append((name, arg.annotation))
49
51
  continue
50
52
 
anydi/ext/fastapi.py CHANGED
@@ -13,7 +13,7 @@ from starlette.requests import Request
13
13
  from typing_extensions import Annotated, get_args, get_origin
14
14
 
15
15
  from anydi import Container
16
- from anydi._utils import get_full_qualname, get_signature
16
+ from anydi._utils import get_full_qualname, get_typed_parameters
17
17
 
18
18
  from .starlette.middleware import RequestScopedMiddleware
19
19
 
@@ -47,7 +47,7 @@ def install(app: FastAPI, container: Container) -> None:
47
47
  call, *params = dependant.cache_key
48
48
  if not call:
49
49
  continue # pragma: no cover
50
- for parameter in get_signature(call).parameters.values():
50
+ for parameter in get_typed_parameters(call):
51
51
  _patch_route_parameter(call, parameter, container)
52
52
 
53
53
 
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import inspect
2
- from typing import Any, Callable, Iterator, List, Tuple, cast
4
+ from typing import Any, Callable, Iterator, cast
3
5
 
4
6
  import pytest
5
7
 
@@ -49,8 +51,8 @@ def _anydi_should_inject(request: pytest.FixtureRequest) -> bool:
49
51
 
50
52
 
51
53
  @pytest.fixture(scope="session")
52
- def _anydi_unresolved() -> Iterator[List[Any]]:
53
- unresolved: List[Any] = []
54
+ def _anydi_unresolved() -> Iterator[list[Any]]:
55
+ unresolved: list[Any] = []
54
56
  yield unresolved
55
57
  unresolved.clear()
56
58
 
@@ -58,9 +60,9 @@ def _anydi_unresolved() -> Iterator[List[Any]]:
58
60
  @pytest.fixture
59
61
  def _anydi_injected_parameter_iterator(
60
62
  request: pytest.FixtureRequest,
61
- _anydi_unresolved: List[str],
62
- ) -> Callable[[], Iterator[Tuple[str, Any]]]:
63
- def _iterator() -> Iterator[Tuple[str, inspect.Parameter]]:
63
+ _anydi_unresolved: list[str],
64
+ ) -> Callable[[], Iterator[tuple[str, Any]]]:
65
+ def _iterator() -> Iterator[tuple[str, inspect.Parameter]]:
64
66
  for name, parameter in inspect.signature(request.function).parameters.items():
65
67
  if (
66
68
  ((interface := parameter.annotation) is parameter.empty)
@@ -77,8 +79,8 @@ def _anydi_injected_parameter_iterator(
77
79
  def _anydi_inject(
78
80
  request: pytest.FixtureRequest,
79
81
  _anydi_should_inject: bool,
80
- _anydi_injected_parameter_iterator: Callable[[], Iterator[Tuple[str, Any]]],
81
- _anydi_unresolved: List[str],
82
+ _anydi_injected_parameter_iterator: Callable[[], Iterator[tuple[str, Any]]],
83
+ _anydi_unresolved: list[str],
82
84
  ) -> None:
83
85
  """Inject dependencies into the test function."""
84
86
 
@@ -107,8 +109,8 @@ def _anydi_inject(
107
109
  async def _anydi_ainject(
108
110
  request: pytest.FixtureRequest,
109
111
  _anydi_should_inject: bool,
110
- _anydi_injected_parameter_iterator: Callable[[], Iterator[Tuple[str, Any]]],
111
- _anydi_unresolved: List[str],
112
+ _anydi_injected_parameter_iterator: Callable[[], Iterator[tuple[str, Any]]],
113
+ _anydi_unresolved: list[str],
112
114
  ) -> None:
113
115
  """Inject dependencies into the test function."""
114
116
  if not inspect.iscoroutinefunction(request.function) or not _anydi_should_inject:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: anydi
3
- Version: 0.25.0a1
3
+ Version: 0.25.1
4
4
  Summary: Dependency Injection library
5
5
  Home-page: https://github.com/antonrh/anydi
6
6
  License: MIT
@@ -139,3 +139,59 @@ def say_hello(message: str = Inject()) -> dict[str, str]:
139
139
  anydi.ext.fastapi.install(app, container)
140
140
  ```
141
141
 
142
+
143
+
144
+ ## Django Ninja Example
145
+
146
+ *container.py*
147
+
148
+ ```python
149
+ from anydi import Container
150
+
151
+
152
+ def get_container() -> Container:
153
+ container = Container()
154
+
155
+ @container.provider(scope="singleton")
156
+ def message() -> str:
157
+ return "Hello, World!"
158
+
159
+ return container
160
+ ```
161
+
162
+ *settings.py*
163
+
164
+ ```python
165
+ INSTALLED_APPS = [
166
+ ...
167
+ "anydi.ext.django",
168
+ ]
169
+
170
+ ANYDI = {
171
+ "CONTAINER_FACTORY": "myapp.container.get_container",
172
+ "PATCH_NINJA": True,
173
+ }
174
+ ```
175
+
176
+ *urls.py*
177
+
178
+ ```python
179
+ from django.http import HttpRequest
180
+ from django.urls import path
181
+ from ninja import NinjaAPI
182
+
183
+ from anydi import auto
184
+
185
+ api = NinjaAPI()
186
+
187
+
188
+ @api.get("/hello")
189
+ def say_hello(request: HttpRequest, message: str = auto) -> dict[str, str]:
190
+ return {"message": message}
191
+
192
+
193
+ urlpatterns = [
194
+ path("api/", api.urls),
195
+ ]
196
+ ```
197
+
@@ -0,0 +1,28 @@
1
+ anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
2
+ anydi/_container.py,sha256=rZ0HgWFC7jJuZo7iLjMYnTm4utWBMOeiaPThz8a5sbY,27996
3
+ anydi/_context.py,sha256=k956mFE_pfPdU0fxOJ8YRHBZx7sU_ln8fheYNofbmSs,10215
4
+ anydi/_logger.py,sha256=UpubJUnW83kffFxkhUlObm2DmZX1Pjqoz9YFKS-JOPg,52
5
+ anydi/_module.py,sha256=E1TfLud_Af-MPB83PxIzHVA1jlDW2FGaRP_il1a6y3Y,3675
6
+ anydi/_scanner.py,sha256=cyEk-K2Q8ssZStq8GrxMeEcCuAZMw-RXrjlgWEevKCs,6667
7
+ anydi/_types.py,sha256=vQTrFjsYhlMxfo1nOFem05x2QUJMQkVh4ZaC7W0XZJY,3434
8
+ anydi/_utils.py,sha256=XHVNkd-__SKlWlyeGE2e1Yi-DBr4DPWzZOIVbTrQyMI,3692
9
+ anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ anydi/ext/django/__init__.py,sha256=QI1IABCVgSDTUoh7M9WMECKXwB3xvh04HfQ9TOWw1Mk,223
11
+ anydi/ext/django/_container.py,sha256=cxVoYQG16WP0S_Yv4TnLwuaaT7NVEOhLWO-YdALJUb4,418
12
+ anydi/ext/django/_settings.py,sha256=cKzFBGtPCsexZ2ZcInubBukIebhxzNfa3F0KuwoZYaA,844
13
+ anydi/ext/django/_utils.py,sha256=76_T-gxP67qddlRyevAF2oe-FTv9NBJSBgOWxxs0qZQ,3673
14
+ anydi/ext/django/apps.py,sha256=-gj_tqb6goeYMNItr6nwWHYXZwDOdiH8anby0YwnUmw,2866
15
+ anydi/ext/django/middleware.py,sha256=iVHWtE829khMY-BXbNNt0g2FrIApKprna7dCG9ObEis,823
16
+ anydi/ext/django/ninja/__init__.py,sha256=kW3grUgWp_nkWSG_-39ADHMrZLGNcj9TsJ9OW8iWWrk,546
17
+ anydi/ext/django/ninja/_operation.py,sha256=wSWa7D73XTVlOibmOciv2l6JHPe1ERZcXrqI8W-oO2w,2696
18
+ anydi/ext/django/ninja/_signature.py,sha256=2cSzKxBIxXLqtwNuH6GSlmjVJFftoGmleWfyk_NVEWw,2207
19
+ anydi/ext/fastapi.py,sha256=kVUKVKtqCx1Nfnm1oh2BMyB0G7qQKPw6OGfxFlqUqtc,5305
20
+ anydi/ext/pytest_plugin.py,sha256=vtjQCwQ0_saG8qhYAYn2wQzXVrXfwXOEhJlTjGqtXA8,3999
21
+ anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
23
+ anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ anydi-0.25.1.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
25
+ anydi-0.25.1.dist-info/METADATA,sha256=fB_AJZKJ6uqYM9Sd4O5ULmFJWuyJq1i1Vi1zV5AyBJE,5160
26
+ anydi-0.25.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
27
+ anydi-0.25.1.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
28
+ anydi-0.25.1.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
2
- anydi/_container.py,sha256=LeGrujx8zMzBuR8PD7qNqVJmmLB-frAG74gihX0lxNc,28341
3
- anydi/_context.py,sha256=btGJzvTMkj5v95rAw6kjOclISKcSugC4wzrHlWlCk_I,10258
4
- anydi/_logger.py,sha256=UpubJUnW83kffFxkhUlObm2DmZX1Pjqoz9YFKS-JOPg,52
5
- anydi/_module.py,sha256=1fBo9-RWxo7TeyP0Y2uJokT-NXP2pjik6CXNoeo3l-8,3712
6
- anydi/_scanner.py,sha256=9S3XbNVFAnHClT3FBo2CWeDBzCLG58i93a1ZJgaMNIo,6775
7
- anydi/_types.py,sha256=TfqJ7TfudOzGMG4_OliAMMJplu42mXZcZmgmtK2oz14,3412
8
- anydi/_utils.py,sha256=haRwC6YTTFf6CNTfwsRQ4NZsNByoUkEmE4-rh1-VYLs,3152
9
- anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- anydi/ext/django/__init__.py,sha256=wsFBQP2j76Ui_0SJlN_8LKhZvEEdxA-w_yoyRAcaM58,59
11
- anydi/ext/django/_container.py,sha256=cxVoYQG16WP0S_Yv4TnLwuaaT7NVEOhLWO-YdALJUb4,418
12
- anydi/ext/django/_utils.py,sha256=C-1UabpwgCHUryAT-Pv8vU5QFfBahQlqhjecvihjtgY,430
13
- anydi/ext/django/apps.py,sha256=qjzKqYIB00qjsSv2RQNVnFMi0lCljmaGtMIy3JMAE0U,6326
14
- anydi/ext/django/ninja/__init__.py,sha256=FckjVqzXTzlBllFg2PZ62wi432-ydZFyWq6ZkF2LJ9I,540
15
- anydi/ext/django/ninja/_operation.py,sha256=A_RbMbJyVaafoeBhZpmPQ96l1RQFLA1FchkJC_uRKnM,2660
16
- anydi/ext/django/ninja/_signature.py,sha256=kdPU0QL3_oloWi43ehi2QJVn_WaRm1klZ6D7sA-SQYo,2177
17
- anydi/ext/fastapi.py,sha256=zKuo7nNpcMXppUsime5LLKTkAiNrlEtcLRFK4FRur0c,5311
18
- anydi/ext/pytest_plugin.py,sha256=tmncz2IbIR7FGlgmAtcf00yDKg9SQP9lCFnJBmtHx3A,3976
19
- anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
21
- anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- anydi-0.25.0a1.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
23
- anydi-0.25.0a1.dist-info/METADATA,sha256=WvjurCb1o4pBgxTvNh-7KY3-6qocjK0euML7cVagy2E,4373
24
- anydi-0.25.0a1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
25
- anydi-0.25.0a1.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
26
- anydi-0.25.0a1.dist-info/RECORD,,