From 3e4c18412eea13b2ad64f57eb3c879b0bdffc8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20P=C3=A4rsson?= Date: Fri, 15 Aug 2025 10:44:56 +0200 Subject: [PATCH 1/2] test: Split and extend `get_bindings()` tests --- injector_test.py | 50 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/injector_test.py b/injector_test.py index 67f3b6e..5d04209 100644 --- a/injector_test.py +++ b/injector_test.py @@ -1589,59 +1589,82 @@ def test_binder_has_implicit_binding_for_implicitly_bound_type(): assert not injector.binder.has_explicit_binding_for(int) -def test_get_bindings(): +def test_gets_no_bindings_without_injection() -> None: def function1(a: int) -> None: pass assert get_bindings(function1) == {} + +def test_gets_bindings_with_inject_decorator() -> None: @inject def function2(a: int) -> None: pass assert get_bindings(function2) == {'a': int} + +def test_gets_multiple_bindings_with_inject_decorator() -> None: + @inject + def function2(a: int, b: str) -> None: + pass + + assert get_bindings(function2) == {'a': int, 'b': str} + + +def test_only_gets_injectable_bindings_without_noninjectable_decorator() -> None: @inject @noninjectable('b') def function3(a: int, b: str) -> None: pass - assert get_bindings(function3) == {'a': int} - # Let's verify that the inject/noninjectable ordering doesn't matter @noninjectable('b') @inject def function3b(a: int, b: str) -> None: pass - assert get_bindings(function3b) == {'a': int} + assert get_bindings(function3) == {'a': int} == get_bindings(function3b) - # The simple case of no @inject but injection requested with Inject[...] + +def test_gets_bindings_with_inject_annotation() -> None: def function4(a: Inject[int], b: str) -> None: pass assert get_bindings(function4) == {'a': int} - # Using @inject with Inject is redundant but it should not break anything + +def test_gets_multiple_bindings_with_inject_annotation() -> None: + def function4(a: Inject[int], b: Inject[str]) -> None: + pass + + assert get_bindings(function4) == {'a': int, 'b': str} + + +def test_gets_bindings_inject_with_redundant_inject_annotation() -> None: @inject def function5(a: Inject[int], b: str) -> None: pass assert get_bindings(function5) == {'a': int, 'b': str} - # We need to be able to exclude a parameter from injection with NoInject + +def test_only_gets_bindings_without_noinject_annotation() -> None: @inject def function6(a: int, b: NoInject[str]) -> None: pass assert get_bindings(function6) == {'a': int} - # The presence of NoInject should not trigger anything on its own + +def test_gets_no_bindings_for_noinject_annotation_only() -> None: def function7(a: int, b: NoInject[str]) -> None: pass assert get_bindings(function7) == {} + +def test_gets_no_bindings_for_multiple_noinject_annotations() -> None: # There was a bug where in case of multiple NoInject-decorated parameters only the first one was # actually made noninjectable and we tried to inject something we couldn't possibly provide # into the second one. @@ -1651,19 +1674,22 @@ def function8(a: NoInject[int], b: NoInject[int]) -> None: assert get_bindings(function8) == {} - # Default arguments to NoInject annotations should behave the same as noninjectable decorator w.r.t 'None' + +def test_get_bindings_noinject_with_default_should_behave_identically() -> None: @inject @noninjectable('b') - def function9(self, a: int, b: Optional[str] = None): + def function9(self, a: int, b: Optional[str] = None) -> None: pass @inject - def function10(self, a: int, b: NoInject[Optional[str]] = None): - # b:s type is Union[NoInject[Union[str, None]], None] + def function10(self, a: int, b: NoInject[Optional[str]] = None) -> None: + # b's type is Union[NoInject[Union[str, None]], None] pass assert get_bindings(function9) == {'a': int} == get_bindings(function10) + +def test_get_bindings_with_an_invalid_forward_reference_return_type() -> None: # If there's a return type annottion that contains an a forward reference that can't be # resolved (for whatever reason) we don't want that to break things for us – return types # don't matter for the purpose of dependency injection. From f2e321c8652d161010851efebae7954e361f6392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20P=C3=A4rsson?= Date: Fri, 15 Aug 2025 10:49:54 +0200 Subject: [PATCH 2/2] refactor: Rename functions --- injector_test.py | 52 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/injector_test.py b/injector_test.py index 5d04209..c5c0ec4 100644 --- a/injector_test.py +++ b/injector_test.py @@ -1590,78 +1590,78 @@ def test_binder_has_implicit_binding_for_implicitly_bound_type(): def test_gets_no_bindings_without_injection() -> None: - def function1(a: int) -> None: + def function(a: int) -> None: pass - assert get_bindings(function1) == {} + assert get_bindings(function) == {} def test_gets_bindings_with_inject_decorator() -> None: @inject - def function2(a: int) -> None: + def function(a: int) -> None: pass - assert get_bindings(function2) == {'a': int} + assert get_bindings(function) == {'a': int} def test_gets_multiple_bindings_with_inject_decorator() -> None: @inject - def function2(a: int, b: str) -> None: + def function(a: int, b: str) -> None: pass - assert get_bindings(function2) == {'a': int, 'b': str} + assert get_bindings(function) == {'a': int, 'b': str} def test_only_gets_injectable_bindings_without_noninjectable_decorator() -> None: @inject @noninjectable('b') - def function3(a: int, b: str) -> None: + def function1(a: int, b: str) -> None: pass # Let's verify that the inject/noninjectable ordering doesn't matter @noninjectable('b') @inject - def function3b(a: int, b: str) -> None: + def function2(a: int, b: str) -> None: pass - assert get_bindings(function3) == {'a': int} == get_bindings(function3b) + assert get_bindings(function1) == {'a': int} == get_bindings(function2) def test_gets_bindings_with_inject_annotation() -> None: - def function4(a: Inject[int], b: str) -> None: + def function(a: Inject[int], b: str) -> None: pass - assert get_bindings(function4) == {'a': int} + assert get_bindings(function) == {'a': int} def test_gets_multiple_bindings_with_inject_annotation() -> None: - def function4(a: Inject[int], b: Inject[str]) -> None: + def function(a: Inject[int], b: Inject[str]) -> None: pass - assert get_bindings(function4) == {'a': int, 'b': str} + assert get_bindings(function) == {'a': int, 'b': str} def test_gets_bindings_inject_with_redundant_inject_annotation() -> None: @inject - def function5(a: Inject[int], b: str) -> None: + def function(a: Inject[int], b: str) -> None: pass - assert get_bindings(function5) == {'a': int, 'b': str} + assert get_bindings(function) == {'a': int, 'b': str} def test_only_gets_bindings_without_noinject_annotation() -> None: @inject - def function6(a: int, b: NoInject[str]) -> None: + def function(a: int, b: NoInject[str]) -> None: pass - assert get_bindings(function6) == {'a': int} + assert get_bindings(function) == {'a': int} def test_gets_no_bindings_for_noinject_annotation_only() -> None: - def function7(a: int, b: NoInject[str]) -> None: + def function(a: int, b: NoInject[str]) -> None: pass - assert get_bindings(function7) == {} + assert get_bindings(function) == {} def test_gets_no_bindings_for_multiple_noinject_annotations() -> None: @@ -1669,24 +1669,24 @@ def test_gets_no_bindings_for_multiple_noinject_annotations() -> None: # actually made noninjectable and we tried to inject something we couldn't possibly provide # into the second one. @inject - def function8(a: NoInject[int], b: NoInject[int]) -> None: + def function(a: NoInject[int], b: NoInject[int]) -> None: pass - assert get_bindings(function8) == {} + assert get_bindings(function) == {} def test_get_bindings_noinject_with_default_should_behave_identically() -> None: @inject @noninjectable('b') - def function9(self, a: int, b: Optional[str] = None) -> None: + def function1(self, a: int, b: Optional[str] = None) -> None: pass @inject - def function10(self, a: int, b: NoInject[Optional[str]] = None) -> None: + def function2(self, a: int, b: NoInject[Optional[str]] = None) -> None: # b's type is Union[NoInject[Union[str, None]], None] pass - assert get_bindings(function9) == {'a': int} == get_bindings(function10) + assert get_bindings(function1) == {'a': int} == get_bindings(function2) def test_get_bindings_with_an_invalid_forward_reference_return_type() -> None: @@ -1694,10 +1694,10 @@ def test_get_bindings_with_an_invalid_forward_reference_return_type() -> None: # resolved (for whatever reason) we don't want that to break things for us – return types # don't matter for the purpose of dependency injection. @inject - def function11(a: int) -> 'InvalidForwardReference': + def function(a: int) -> 'InvalidForwardReference': pass - assert get_bindings(function11) == {'a': int} + assert get_bindings(function) == {'a': int} # Tests https://github.com/alecthomas/injector/issues/202