Skip to content

Commit 147c234

Browse files
committed
Allow annotated marker to be anywhere in the annotation list.
1 parent 5a1aef9 commit 147c234

File tree

3 files changed

+33
-18
lines changed

3 files changed

+33
-18
lines changed

src/dependency_injector/wiring.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -672,23 +672,18 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None:
672672

673673
def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]:
674674
if get_origin(parameter.annotation) is Annotated:
675-
args = get_args(parameter.annotation)
676-
if len(args) > 1:
677-
marker = args[1]
678-
else:
679-
marker = None
675+
candidates = get_args(parameter.annotation)[1:]
680676
else:
681-
marker = parameter.default
682-
683-
for marker_extractor in MARKER_EXTRACTORS:
684-
if _marker := marker_extractor(marker):
685-
marker = _marker
686-
break
687-
688-
if not isinstance(marker, _Marker):
689-
return None
677+
candidates = (parameter.default,)
690678

691-
return marker
679+
for marker in candidates:
680+
for marker_extractor in MARKER_EXTRACTORS:
681+
if _marker := marker_extractor(marker):
682+
marker = _marker
683+
break
684+
if _is_marker(marker):
685+
return marker
686+
return None
692687

693688

694689
@cache
@@ -1213,9 +1208,11 @@ def _get_members_and_annotated(obj: Any) -> Iterable[Tuple[str, Any]]:
12131208
for annotation_name, annotation in annotations.items():
12141209
if get_origin(annotation) is Annotated:
12151210
args = get_args(annotation)
1216-
if len(args) > 1:
1217-
member = args[1]
1218-
members.append((annotation_name, member))
1211+
# Search through all metadata items (args[1:]) for a DI marker
1212+
for arg in args[1:]:
1213+
if _is_marker(arg):
1214+
members.append((annotation_name, arg))
1215+
break
12191216
return members
12201217

12211218

tests/unit/samples/wiring/module_annotated.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,10 @@ def test_class_decorator(service: Annotated[Service, Provide[Container.service]]
124124

125125
def test_container(container: Annotated[Container, Provide[Container]]):
126126
return container.service()
127+
128+
129+
@inject
130+
def test_annotated_with_non_di_metadata_first(
131+
service: Annotated[Service, "some other annotated value", Provide[Container.service]],
132+
):
133+
return service

tests/unit/wiring/provider_ids/test_main_annotated_py36.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,14 @@ def test_class_decorator():
174174
def test_container():
175175
service = module.test_container()
176176
assert isinstance(service, Service)
177+
178+
179+
def test_annotated_with_non_di_metadata_first():
180+
"""Test that Annotated works when DI marker is not the first metadata item.
181+
182+
This tests the case where Annotated has other metadata (like docstrings or
183+
other annotations) before the Provide marker, e.g.:
184+
Annotated[Service, "some doc", Provide[Container.service]]
185+
"""
186+
service = module.test_annotated_with_non_di_metadata_first()
187+
assert isinstance(service, Service)

0 commit comments

Comments
 (0)