anydi 0.45.0__tar.gz → 0.46.0rc1__tar.gz

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.
Files changed (96) hide show
  1. {anydi-0.45.0 → anydi-0.46.0rc1}/PKG-INFO +1 -1
  2. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/__init__.py +2 -2
  3. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_container.py +20 -15
  4. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_scan.py +2 -2
  5. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_typing.py +6 -7
  6. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/_utils.py +13 -9
  7. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/ninja/_signature.py +6 -3
  8. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/fastapi.py +2 -1
  9. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/faststream.py +2 -1
  10. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/testing.py +2 -0
  11. {anydi-0.45.0 → anydi-0.46.0rc1}/pyproject.toml +2 -2
  12. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/fastapi/test_ext.py +0 -1
  13. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/faststream/test_ext.py +0 -1
  14. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/test_container.py +1 -2
  15. {anydi-0.45.0 → anydi-0.46.0rc1}/uv.lock +1 -1
  16. {anydi-0.45.0 → anydi-0.46.0rc1}/.editorconfig +0 -0
  17. {anydi-0.45.0 → anydi-0.46.0rc1}/.github/workflows/ci.yml +0 -0
  18. {anydi-0.45.0 → anydi-0.46.0rc1}/.gitignore +0 -0
  19. {anydi-0.45.0 → anydi-0.46.0rc1}/.readthedocs.yaml +0 -0
  20. {anydi-0.45.0 → anydi-0.46.0rc1}/LICENSE +0 -0
  21. {anydi-0.45.0 → anydi-0.46.0rc1}/Makefile +0 -0
  22. {anydi-0.45.0 → anydi-0.46.0rc1}/README.md +0 -0
  23. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_async.py +0 -0
  24. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_context.py +0 -0
  25. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_decorators.py +0 -0
  26. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_module.py +0 -0
  27. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_provider.py +0 -0
  28. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/_scope.py +0 -0
  29. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/__init__.py +0 -0
  30. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/__init__.py +0 -0
  31. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/_container.py +0 -0
  32. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/_settings.py +0 -0
  33. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/_utils.py +0 -0
  34. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/apps.py +0 -0
  35. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/middleware.py +0 -0
  36. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/ninja/__init__.py +0 -0
  37. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/django/ninja/_operation.py +0 -0
  38. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/pydantic_settings.py +0 -0
  39. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/pytest_plugin.py +0 -0
  40. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/starlette/__init__.py +0 -0
  41. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/ext/starlette/middleware.py +0 -0
  42. {anydi-0.45.0 → anydi-0.46.0rc1}/anydi/py.typed +0 -0
  43. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/examples/basic.md +0 -0
  44. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/extensions/django.md +0 -0
  45. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/extensions/fastapi.md +0 -0
  46. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/extensions/faststream.md +0 -0
  47. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/extensions/pydantic_settings.md +0 -0
  48. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/index.md +0 -0
  49. {anydi-0.45.0 → anydi-0.46.0rc1}/docs/usage.md +0 -0
  50. {anydi-0.45.0 → anydi-0.46.0rc1}/mkdocs.yml +0 -0
  51. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/__init__.py +0 -0
  52. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/conftest.py +0 -0
  53. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/__init__.py +0 -0
  54. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/__init__.py +0 -0
  55. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/api/__init__.py +0 -0
  56. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/api/router.py +0 -0
  57. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/api/test_router.py +0 -0
  58. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/api/urls.py +0 -0
  59. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/conftest.py +0 -0
  60. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/container.py +0 -0
  61. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/scan/__init__.py +0 -0
  62. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/services.py +0 -0
  63. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/settings.py +0 -0
  64. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/test_views.py +0 -0
  65. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/urls.py +0 -0
  66. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/django/views.py +0 -0
  67. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/fastapi/__init__.py +0 -0
  68. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/fastapi/app.py +0 -0
  69. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/fastapi/conftest.py +0 -0
  70. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/fastapi/test_routes.py +0 -0
  71. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/faststream/__init__.py +0 -0
  72. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/faststream/test_subscribers.py +0 -0
  73. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/fixtures.py +0 -0
  74. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/starlette/__init__.py +0 -0
  75. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/starlette/app.py +0 -0
  76. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/starlette/conftest.py +0 -0
  77. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/starlette/test_routes.py +0 -0
  78. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/test_pydantic.py +0 -0
  79. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/ext/test_pytest_plugin.py +0 -0
  80. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/fixtures.py +0 -0
  81. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/__init__.py +0 -0
  82. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/__init__.py +0 -0
  83. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a1/__init__.py +0 -0
  84. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a1/handlers.py +0 -0
  85. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a2/__init__.py +0 -0
  86. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a2/a21/__init__.py +0 -0
  87. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a2/a21/handlers.py +0 -0
  88. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a3/__init__.py +0 -0
  89. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/a/a3/handlers.py +0 -0
  90. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/b/__init__.py +0 -0
  91. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/scan_app/b/handlers.py +0 -0
  92. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/test_decorators.py +0 -0
  93. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/test_module.py +0 -0
  94. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/test_scan.py +0 -0
  95. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/test_testing.py +0 -0
  96. {anydi-0.45.0 → anydi-0.46.0rc1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anydi
3
- Version: 0.45.0
3
+ Version: 0.46.0rc1
4
4
  Summary: Dependency Injection library
5
5
  Project-URL: Repository, https://github.com/antonrh/anydi
6
6
  Author-email: Anton Ruhlov <antonruhlov@gmail.com>
@@ -5,10 +5,10 @@ from ._decorators import injectable, provided, provider, request, singleton, tra
5
5
  from ._module import Module
6
6
  from ._provider import ProviderDef as Provider
7
7
  from ._scope import Scope
8
- from ._typing import Marker
8
+ from ._typing import InjectMarker
9
9
 
10
10
  # Alias for dependency auto marker
11
- auto = Marker()
11
+ auto = InjectMarker()
12
12
 
13
13
 
14
14
  __all__ = [
@@ -31,8 +31,8 @@ from ._typing import (
31
31
  is_builtin_type,
32
32
  is_context_manager,
33
33
  is_event_type,
34
+ is_inject_marker,
34
35
  is_iterator_type,
35
- is_marker,
36
36
  is_none_type,
37
37
  type_repr,
38
38
  )
@@ -806,29 +806,34 @@ class Container:
806
806
  """Get the injected parameters of a callable object."""
807
807
  injected_params: dict[str, Any] = {}
808
808
  for parameter in get_typed_parameters(call):
809
- if not is_marker(parameter.default):
810
- continue
811
- self._validate_injected_parameter(call, parameter)
812
- injected_params[parameter.name] = parameter.annotation
809
+ interface, should_inject = self._validate_injected_parameter(
810
+ parameter, call=call
811
+ )
812
+ if should_inject:
813
+ injected_params[parameter.name] = interface
813
814
  return injected_params
814
815
 
815
816
  def _validate_injected_parameter(
816
- self, call: Callable[..., Any], parameter: inspect.Parameter
817
- ) -> None:
817
+ self, parameter: inspect.Parameter, *, call: Callable[..., Any]
818
+ ) -> tuple[Any, bool]:
818
819
  """Validate an injected parameter."""
819
- # TODO: temporary disable until strict is enforced
820
- return None
820
+ interface, should_inject = parameter.annotation, False
821
+ if is_inject_marker(parameter.default):
822
+ if parameter.annotation is inspect.Parameter.empty:
823
+ raise TypeError(
824
+ f"Missing `{type_repr(call)}` "
825
+ f"parameter `{parameter.name}` annotation."
826
+ )
827
+ should_inject = True
821
828
 
822
- if parameter.annotation is inspect.Parameter.empty:
823
- raise TypeError(
824
- f"Missing `{type_repr(call)}` parameter `{parameter.name}` annotation."
825
- )
829
+ return interface, should_inject
826
830
 
827
- if not self.has_provider_for(parameter.annotation):
831
+ # TODO: temporary disable until strict is enforced
832
+ if not self.has_provider_for(interface):
828
833
  raise LookupError(
829
834
  f"`{type_repr(call)}` has an unknown dependency parameter "
830
835
  f"`{parameter.name}` with an annotation of "
831
- f"`{type_repr(parameter.annotation)}`."
836
+ f"`{type_repr(interface)}`."
832
837
  )
833
838
 
834
839
  ############################
@@ -9,7 +9,7 @@ from types import ModuleType
9
9
  from typing import TYPE_CHECKING, Any, Callable, Union
10
10
 
11
11
  from ._decorators import is_injectable
12
- from ._typing import get_typed_parameters, is_marker
12
+ from ._typing import get_typed_parameters, is_inject_marker
13
13
 
14
14
  if TYPE_CHECKING:
15
15
  from ._container import Container
@@ -104,7 +104,7 @@ class Scanner:
104
104
  # check for parameter markers
105
105
  if not tags:
106
106
  for param in get_typed_parameters(member):
107
- if is_marker(param.default):
107
+ if is_inject_marker(param.default):
108
108
  return True
109
109
 
110
110
  return False
@@ -93,8 +93,8 @@ def get_typed_parameters(obj: Callable[..., Any]) -> list[inspect.Parameter]:
93
93
  ]
94
94
 
95
95
 
96
- class _Marker:
97
- """A marker class for marking dependencies."""
96
+ class _InjectMarker:
97
+ """A marker object for declaring injectable dependencies."""
98
98
 
99
99
  __slots__ = ()
100
100
 
@@ -102,13 +102,12 @@ class _Marker:
102
102
  return self
103
103
 
104
104
 
105
- def Marker() -> Any:
106
- return _Marker()
105
+ def InjectMarker() -> Any:
106
+ return _InjectMarker()
107
107
 
108
108
 
109
- def is_marker(obj: Any) -> bool:
110
- """Checks if an object is a marker."""
111
- return isinstance(obj, _Marker)
109
+ def is_inject_marker(obj: Any) -> bool:
110
+ return isinstance(obj, _InjectMarker)
112
111
 
113
112
 
114
113
  class Event:
@@ -8,13 +8,17 @@ from typing import Annotated, Any, Callable
8
8
 
9
9
  from typing_extensions import get_args, get_origin
10
10
 
11
- from anydi._container import Container
11
+ from anydi import Container
12
+ from anydi._typing import _InjectMarker
12
13
 
13
14
  logger = logging.getLogger(__name__)
14
15
 
15
16
 
16
- class HasInterface:
17
- _interface: Any = None
17
+ class HasInterface(_InjectMarker):
18
+ __slots__ = ("_interface",)
19
+
20
+ def __init__(self, interface: Any = None) -> None:
21
+ self._interface = interface
18
22
 
19
23
  @property
20
24
  def interface(self) -> Any:
@@ -65,9 +69,9 @@ def patch_call_parameter(
65
69
  """Patch a parameter to inject dependencies using AnyDI."""
66
70
  parameter = patch_annotated_parameter(parameter)
67
71
 
68
- if not isinstance(parameter.default, HasInterface):
69
- return None
70
-
71
- container._validate_injected_parameter(call, parameter) # noqa
72
-
73
- parameter.default.interface = parameter.annotation
72
+ interface, should_inject = container._validate_injected_parameter(
73
+ parameter, call=call
74
+ ) # noqa
75
+ if should_inject:
76
+ parameter.default.interface = interface
77
+ return None
@@ -11,7 +11,8 @@ from ninja.signature.details import (
11
11
  )
12
12
  from ninja.signature.utils import get_path_param_names, get_typed_signature
13
13
 
14
- from anydi._typing import is_marker # noqa
14
+ from anydi._typing import is_inject_marker # noqa
15
+ from anydi.ext.django import container
15
16
 
16
17
 
17
18
  class ViewSignature(BaseViewSignature):
@@ -45,8 +46,10 @@ class ViewSignature(BaseViewSignature):
45
46
  self.response_arg = name
46
47
  continue
47
48
 
48
- # Skip default values that are anydi dependency markers
49
- if is_marker(arg.default):
49
+ interface, should_inject = container._validate_injected_parameter(
50
+ arg, call=self.view_func
51
+ )
52
+ if should_inject:
50
53
  self.dependencies.append((name, arg.annotation))
51
54
  continue
52
55
 
@@ -49,11 +49,12 @@ def get_container(request: Request) -> Container:
49
49
  return cast(Container, request.app.state.container)
50
50
 
51
51
 
52
- class Resolver(HasInterface, params.Depends):
52
+ class Resolver(params.Depends, HasInterface):
53
53
  """Parameter dependency class for injecting dependencies using AnyDI."""
54
54
 
55
55
  def __init__(self) -> None:
56
56
  super().__init__(dependency=self._dependency, use_cache=True)
57
+ HasInterface.__init__(self)
57
58
 
58
59
  async def _dependency(self, container: Container = Depends(get_container)) -> Any:
59
60
  return await container.aresolve(self.interface)
@@ -43,11 +43,12 @@ def get_container(broker: BrokerUsecase[Any, Any]) -> Container:
43
43
  return cast(Container, getattr(broker, "_container")) # noqa
44
44
 
45
45
 
46
- class Resolver(HasInterface, Depends):
46
+ class Resolver(Depends, HasInterface):
47
47
  """Parameter dependency class for injecting dependencies using AnyDI."""
48
48
 
49
49
  def __init__(self) -> None:
50
50
  super().__init__(dependency=self._dependency, use_cache=True, cast=True)
51
+ HasInterface.__init__(self)
51
52
 
52
53
  async def _dependency(self, context: ContextRepo) -> Any:
53
54
  container = get_container(context.get("broker"))
@@ -18,6 +18,8 @@ T = TypeVar("T")
18
18
 
19
19
 
20
20
  class TestContainer(Container):
21
+ __test__ = False
22
+
21
23
  def __init__(
22
24
  self,
23
25
  *,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "anydi"
3
- version = "0.45.0"
3
+ version = "0.46.0rc1"
4
4
  description = "Dependency Injection library"
5
5
  authors = [{ name = "Anton Ruhlov", email = "antonruhlov@gmail.com" }]
6
6
  requires-python = "~=3.9"
@@ -137,7 +137,7 @@ omit = [
137
137
  ]
138
138
 
139
139
  [tool.bumpversion]
140
- current_version = "0.45.0"
140
+ current_version = "0.46.0rc1"
141
141
  parse = """(?x)
142
142
  (?P<major>0|[1-9]\\d*)\\.
143
143
  (?P<minor>0|[1-9]\\d*)\\.
@@ -14,7 +14,6 @@ def test_inject_param_missing_interface() -> None:
14
14
  _ = param.interface
15
15
 
16
16
 
17
- @pytest.mark.skip(reason="disable until strict is enforced")
18
17
  def test_install_without_annotation() -> None:
19
18
  container = Container()
20
19
 
@@ -14,7 +14,6 @@ def test_inject_param_missing_interface() -> None:
14
14
  _ = param.interface
15
15
 
16
16
 
17
- @pytest.mark.skip(reason="disable until strict is enforced")
18
17
  def test_install_without_annotation() -> None:
19
18
  container = Container()
20
19
 
@@ -1420,7 +1420,6 @@ class TestContainerInjector:
1420
1420
 
1421
1421
  assert result == "service ident = 1000"
1422
1422
 
1423
- @pytest.mark.skip(reason="disable until strict is enforced")
1424
1423
  def test_inject_missing_annotation(self, container: Container) -> None:
1425
1424
  def handler(name=auto) -> str: # type: ignore
1426
1425
  return name # type: ignore
@@ -1431,7 +1430,7 @@ class TestContainerInjector:
1431
1430
  container.inject(handler)
1432
1431
 
1433
1432
  @pytest.mark.skip(reason="disable until strict is enforced")
1434
- def test_inject_unknown_dependency_using_strict_mode(self) -> None:
1433
+ def test_inject_unknown_dependency(self) -> None:
1435
1434
  container = Container()
1436
1435
 
1437
1436
  def handler(message: str = auto) -> None:
@@ -13,7 +13,7 @@ wheels = [
13
13
 
14
14
  [[package]]
15
15
  name = "anydi"
16
- version = "0.45.0"
16
+ version = "0.46.0rc1"
17
17
  source = { editable = "." }
18
18
  dependencies = [
19
19
  { name = "anyio" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes