anydi 0.24.2__py3-none-any.whl → 0.24.3__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
@@ -43,7 +43,12 @@ from ._logger import logger
43
43
  from ._module import Module, ModuleRegistry
44
44
  from ._scanner import Scanner
45
45
  from ._types import AnyInterface, Interface, Provider, Scope, is_marker
46
- 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
+ is_builtin_type,
51
+ )
47
52
 
48
53
  T = TypeVar("T", bound=Any)
49
54
  P = ParamSpec("P")
@@ -327,7 +332,7 @@ class Container:
327
332
  """
328
333
  related_providers = []
329
334
 
330
- for parameter in provider.parameters.values():
335
+ for parameter in provider.parameters:
331
336
  if parameter.annotation is inspect._empty: # noqa
332
337
  raise TypeError(
333
338
  f"Missing provider `{provider}` "
@@ -366,7 +371,7 @@ class Container:
366
371
  The auto scope, or None if the auto scope cannot be detected.
367
372
  """
368
373
  has_transient, has_request, has_singleton = False, False, False
369
- for parameter in get_signature(obj).parameters.values():
374
+ for parameter in get_typed_parameters(obj):
370
375
  sub_provider = self._get_or_register_provider(parameter.annotation)
371
376
  if not has_transient and sub_provider.scope == "transient":
372
377
  has_transient = True
@@ -711,9 +716,9 @@ class Container:
711
716
  Raises:
712
717
  TypeError: If the provider return annotation is missing or invalid.
713
718
  """
714
- annotation = get_signature(obj).return_annotation
719
+ annotation = get_typed_return_annotation(obj)
715
720
 
716
- if annotation is inspect._empty: # noqa
721
+ if annotation is None:
717
722
  raise TypeError(
718
723
  f"Missing `{get_full_qualname(obj)}` provider return annotation."
719
724
  )
@@ -741,7 +746,7 @@ class Container:
741
746
  of the injected parameters.
742
747
  """
743
748
  injected_params = {}
744
- for parameter in get_signature(obj).parameters.values():
749
+ for parameter in get_typed_parameters(obj):
745
750
  if not is_marker(parameter.default):
746
751
  continue
747
752
  try:
anydi/_context.py CHANGED
@@ -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)
@@ -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)
anydi/_scanner.py CHANGED
@@ -20,7 +20,7 @@ from typing import (
20
20
  from typing_extensions import NamedTuple, ParamSpec
21
21
 
22
22
  from ._types import is_marker
23
- from ._utils import get_signature
23
+ from ._utils import get_typed_parameters
24
24
 
25
25
  if TYPE_CHECKING:
26
26
  from ._container import Container
@@ -157,10 +157,10 @@ class Scanner:
157
157
 
158
158
  # Get by Marker
159
159
  if inspect.isclass(member):
160
- signature = get_signature(member.__init__)
160
+ parameters = get_typed_parameters(member.__init__)
161
161
  else:
162
- signature = get_signature(member)
163
- for parameter in signature.parameters.values():
162
+ parameters = get_typed_parameters(member)
163
+ for parameter in parameters:
164
164
  if is_marker(parameter.default):
165
165
  dependencies.append(
166
166
  self._create_dependency(member=member, module=module)
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
- from typing import Any, Callable, Mapping, Type, TypeVar, Union
6
+ from typing import Any, Callable, Type, TypeVar, Union
5
7
 
6
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
@@ -6,7 +6,7 @@ import builtins
6
6
  import functools
7
7
  import inspect
8
8
  import sys
9
- from typing import Any, Callable, TypeVar
9
+ from typing import Any, Callable, ForwardRef, TypeVar, cast
10
10
 
11
11
  from typing_extensions import Annotated, ParamSpec, get_origin
12
12
 
@@ -16,22 +16,23 @@ except ImportError:
16
16
  anyio = None # type: ignore[assignment]
17
17
 
18
18
 
19
- T = TypeVar("T")
20
- P = ParamSpec("P")
19
+ if sys.version_info < (3, 9): # pragma: nocover
21
20
 
21
+ def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
22
+ return type_._evaluate(globalns, localns) # noqa
22
23
 
23
- def get_full_qualname(obj: Any) -> str:
24
- """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
25
28
 
26
- This function returns the fully qualified name of the given object,
27
- which includes both the module name and the object's qualname.
28
29
 
29
- Args:
30
- obj: The object for which to retrieve the fully qualified name.
30
+ T = TypeVar("T")
31
+ P = ParamSpec("P")
31
32
 
32
- Returns:
33
- The fully qualified name of the object.
34
- """
33
+
34
+ def get_full_qualname(obj: Any) -> str:
35
+ """Get the fully qualified name of an object."""
35
36
  origin = get_origin(obj)
36
37
  if origin is Annotated:
37
38
  metadata = ", ".join(
@@ -56,34 +57,43 @@ def get_full_qualname(obj: Any) -> str:
56
57
 
57
58
 
58
59
  def is_builtin_type(tp: type[Any]) -> bool:
59
- """
60
- Check if the given type is a built-in type.
61
- Args:
62
- tp (type): The type to check.
63
- Returns:
64
- bool: True if the type is a built-in type, False otherwise.
65
- """
60
+ """Check if the given type is a built-in type."""
66
61
  return tp.__module__ == builtins.__name__
67
62
 
68
63
 
69
- @functools.lru_cache(maxsize=None)
70
- def get_signature(obj: Callable[..., Any]) -> inspect.Signature:
71
- """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)
72
68
 
73
- This function uses the `inspect.signature` function to retrieve the signature
74
- of the given callable object. It applies an LRU cache decorator to improve
75
- performance by caching the signatures of previously inspected objects.
76
69
 
77
- Args:
78
- obj: The callable object to inspect.
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
79
76
 
80
- Returns:
81
- The signature of the callable object.
82
- """
83
- signature_kwargs: dict[str, Any] = {}
84
- if sys.version_info >= (3, 10):
85
- signature_kwargs["eval_str"] = True
86
- return inspect.signature(obj, **signature_kwargs)
77
+
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
+ ]
87
97
 
88
98
 
89
99
  async def run_async(
@@ -92,19 +102,7 @@ async def run_async(
92
102
  *args: P.args,
93
103
  **kwargs: P.kwargs,
94
104
  ) -> T:
95
- """Runs the given function asynchronously using the `anyio` library.
96
-
97
- Args:
98
- func: The function to run asynchronously.
99
- args: The positional arguments to pass to the function.
100
- kwargs: The keyword arguments to pass to the function.
101
-
102
- Returns:
103
- The result of the function.
104
-
105
- Raises:
106
- ImportError: If the `anyio` library is not installed.
107
- """
105
+ """Runs the given function asynchronously using the `anyio` library."""
108
106
  if not anyio:
109
107
  raise ImportError(
110
108
  "`anyio` library is not currently installed. Please make sure to install "
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: anydi
3
- Version: 0.24.2
3
+ Version: 0.24.3
4
4
  Summary: Dependency Injection library
5
5
  Home-page: https://github.com/antonrh/anydi
6
6
  License: MIT
@@ -0,0 +1,19 @@
1
+ anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
2
+ anydi/_container.py,sha256=geBYRsvWECDuKJSAal84RjF88ZYf9_w4wxBUgOI3XWs,27978
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=xM5Lw4SNcUKL-9nA8arlhUeUveXFpvvY8cB9ZGV2h6g,3439
9
+ anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ anydi/ext/fastapi.py,sha256=kVUKVKtqCx1Nfnm1oh2BMyB0G7qQKPw6OGfxFlqUqtc,5305
11
+ anydi/ext/pytest_plugin.py,sha256=vtjQCwQ0_saG8qhYAYn2wQzXVrXfwXOEhJlTjGqtXA8,3999
12
+ anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
14
+ anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ anydi-0.24.3.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
16
+ anydi-0.24.3.dist-info/METADATA,sha256=NcsRJMFeKJAEWl6FERdpxutYYFfYYQhh5tGi39CvVKo,4371
17
+ anydi-0.24.3.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
18
+ anydi-0.24.3.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
19
+ anydi-0.24.3.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- anydi/__init__.py,sha256=aeaBp5vq09sG-e9sqqs9qpUtUIDNfOdFPrlAfE5Ku9E,584
2
- anydi/_container.py,sha256=1egUGFF_YFqPDhDwCsprAdT-WvQNfQWMxBS4v5itzM4,27978
3
- anydi/_context.py,sha256=b7mNuCKB-EtYMhV4L_gqWuOzc296CaQqdoCHysvGdno,10233
4
- anydi/_logger.py,sha256=UpubJUnW83kffFxkhUlObm2DmZX1Pjqoz9YFKS-JOPg,52
5
- anydi/_module.py,sha256=E1TfLud_Af-MPB83PxIzHVA1jlDW2FGaRP_il1a6y3Y,3675
6
- anydi/_scanner.py,sha256=ts0k1BdklrqybnNG7FkHnQVJrDuI-Qy6Cw9wvuDnSJU,6663
7
- anydi/_types.py,sha256=cC5CJS-seuiEeZoLMfE5w-t6S7eLeJtjwpPaY65ovaw,3412
8
- anydi/_utils.py,sha256=h-hXqTrVs5pBG3fupenipnLs3MgB0WknqeYOhTKBjXc,3176
9
- anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- anydi/ext/fastapi.py,sha256=zKuo7nNpcMXppUsime5LLKTkAiNrlEtcLRFK4FRur0c,5311
11
- anydi/ext/pytest_plugin.py,sha256=vtjQCwQ0_saG8qhYAYn2wQzXVrXfwXOEhJlTjGqtXA8,3999
12
- anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- anydi/ext/starlette/middleware.py,sha256=Ni0BQaPjs_Ha6zcLZYYJ3-XkslTCnL9aCSa06rnRDMI,1139
14
- anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- anydi-0.24.2.dist-info/LICENSE,sha256=V6rU8a8fv6o2jQ-7ODHs0XfDFimot8Q6Km6CylRIDTo,1069
16
- anydi-0.24.2.dist-info/METADATA,sha256=Eu-ywIzWHmxQ3MsXYRt_1J0nb1rjEWNr6MdEdrumfk4,4371
17
- anydi-0.24.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
18
- anydi-0.24.2.dist-info/entry_points.txt,sha256=GmQblwzxFg42zva1HyBYJJ7TvrTIcSAGBHmyi3bvsi4,42
19
- anydi-0.24.2.dist-info/RECORD,,
File without changes