From 1d58fd719b2a3b6475b9fd633ff097958e2039de Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 18 Jul 2025 10:01:38 -0400 Subject: [PATCH 1/2] injector_test: Add test demonstrating handling of optional parameters --- injector_test.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/injector_test.py b/injector_test.py index ade7ba9..1553a50 100644 --- a/injector_test.py +++ b/injector_test.py @@ -1761,6 +1761,15 @@ def function(a: Inject[Inject[int]]) -> None: assert get_bindings(function) == {'a': int} + # This will not inject `None` even if there is a provider configured to provide + # str | None elsewhere in the graph because `None` is stripped in + @inject + def function12(a: str | None): + pass + + assert get_bindings(function12) == {'a': str | None} + + # Tests https://github.com/alecthomas/injector/issues/202 @pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10+") def test_get_bindings_for_pep_604(): From 5866e12b4033245616e9692cf6ab4320f7085bca Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 18 Jul 2025 10:04:17 -0400 Subject: [PATCH 2/2] _infer_injected_bindings: Don't strip NoneType from function bindings --- injector/__init__.py | 3 +-- injector_test.py | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index e53b762..0d49dd7 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -1263,9 +1263,8 @@ def _recreate_annotated_origin(annotated_type: Any) -> Any: if only_explicit_bindings and _inject_marker not in metadata or _noinject_marker in metadata: del bindings[k] elif _is_specialization(v, Union) or _is_new_union_type(v): - # We don't treat Optional parameters in any special way at the moment. union_members = v.__args__ - new_members = tuple(set(union_members) - {type(None)}) + new_members = tuple(set(union_members)) # mypy stared complaining about this line for some reason: # error: Variable "new_members" is not valid as a type new_union = Union[new_members] # type: ignore diff --git a/injector_test.py b/injector_test.py index 1553a50..f4b50bf 100644 --- a/injector_test.py +++ b/injector_test.py @@ -1761,8 +1761,7 @@ def function(a: Inject[Inject[int]]) -> None: assert get_bindings(function) == {'a': int} - # This will not inject `None` even if there is a provider configured to provide - # str | None elsewhere in the graph because `None` is stripped in + # This should correctly resolve str | None @inject def function12(a: str | None): pass @@ -1777,7 +1776,7 @@ def test_get_bindings_for_pep_604(): def function1(a: int | None) -> None: pass - assert get_bindings(function1) == {'a': int} + assert get_bindings(function1) == {'a': Union[int, None]} @inject def function1(a: int | str) -> None: