diff --git a/src/dependency_injector/wiring.py b/src/dependency_injector/wiring.py index ceeee74e..6b13e05c 100644 --- a/src/dependency_injector/wiring.py +++ b/src/dependency_injector/wiring.py @@ -682,23 +682,18 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None: def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: if get_origin(parameter.annotation) is Annotated: - args = get_args(parameter.annotation) - if len(args) > 1: - marker = args[1] - else: - marker = None + candidates = get_args(parameter.annotation)[1:] else: - marker = parameter.default - - for marker_extractor in MARKER_EXTRACTORS: - if _marker := marker_extractor(marker): - marker = _marker - break - - if not isinstance(marker, _Marker): - return None + candidates = (parameter.default,) - return marker + for marker in candidates: + for marker_extractor in MARKER_EXTRACTORS: + if _marker := marker_extractor(marker): + marker = _marker + break + if _is_marker(marker): + return marker + return None @cache @@ -1223,9 +1218,11 @@ def _get_members_and_annotated(obj: Any) -> Iterable[Tuple[str, Any]]: for annotation_name, annotation in annotations.items(): if get_origin(annotation) is Annotated: args = get_args(annotation) - if len(args) > 1: - member = args[1] - members.append((annotation_name, member)) + # Search through all metadata items (args[1:]) for a DI marker + for arg in args[1:]: + if _is_marker(arg): + members.append((annotation_name, arg)) + break return members diff --git a/tests/unit/samples/wiring/module_annotated.py b/tests/unit/samples/wiring/module_annotated.py index f954d0cb..3af049f2 100644 --- a/tests/unit/samples/wiring/module_annotated.py +++ b/tests/unit/samples/wiring/module_annotated.py @@ -124,3 +124,10 @@ def test_class_decorator(service: Annotated[Service, Provide[Container.service]] def test_container(container: Annotated[Container, Provide[Container]]): return container.service() + + +@inject +def test_annotated_with_non_di_metadata_first( + service: Annotated[Service, "some other annotated value", Provide[Container.service]], +): + return service diff --git a/tests/unit/wiring/provider_ids/test_main_annotated_py36.py b/tests/unit/wiring/provider_ids/test_main_annotated_py36.py index 34d1d747..5e289cd0 100644 --- a/tests/unit/wiring/provider_ids/test_main_annotated_py36.py +++ b/tests/unit/wiring/provider_ids/test_main_annotated_py36.py @@ -174,3 +174,14 @@ def test_class_decorator(): def test_container(): service = module.test_container() assert isinstance(service, Service) + + +def test_annotated_with_non_di_metadata_first(): + """Test that Annotated works when DI marker is not the first metadata item. + + This tests the case where Annotated has other metadata (like docstrings or + other annotations) before the Provide marker, e.g.: + Annotated[Service, "some doc", Provide[Container.service]] + """ + service = module.test_annotated_with_non_di_metadata_first() + assert isinstance(service, Service)