From ce957ab42a79247fbfd255b109cbdbdd55738be8 Mon Sep 17 00:00:00 2001 From: Tobias Nilsson Date: Wed, 15 Jun 2022 01:01:32 +0200 Subject: [PATCH] fix: inspect union arguments for annotations (#195) NoInject[T] = None has the runtime typehint NoInject[T] | None, instead of the expected NoInject[T | None]. NoInject[str] = 'blarb' works as expected Resolves #192 --- injector/__init__.py | 15 ++++++++++++++- injector_test.py | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index 0e79b22..731c1c1 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -1190,7 +1190,20 @@ def _infer_injected_bindings(callable: Callable, only_explicit_bindings: bool) - # mypy complains about this construct: # error: The type alias is invalid in runtime context # See: https://github.com/python/mypy/issues/5354 - bindings[k] = new_union # type: ignore + union_metadata = { + metadata + for member in new_members + for metadata in getattr(member, '__metadata__', tuple()) + if _is_specialization(member, Annotated) + } + if ( + only_explicit_bindings + and _inject_marker not in union_metadata + or _noinject_marker in union_metadata + ): + del bindings[k] + else: + bindings[k] = new_union # type: ignore return bindings diff --git a/injector_test.py b/injector_test.py index 9e3a601..76e9bd2 100644 --- a/injector_test.py +++ b/injector_test.py @@ -11,7 +11,7 @@ """Functional tests for the "Injector" dependency injection framework.""" from contextlib import contextmanager -from typing import Any, NewType +from typing import Any, NewType, Optional import abc import sys import threading @@ -1481,3 +1481,16 @@ def test_get_bindings(): pass assert get_bindings(function8) == {} + + # Default arguments to NoInject annotations should behave the same as noninjectable decorator w.r.t 'None' + @inject + @noninjectable('b') + def function9(self, a: int, b: Optional[str] = None): + pass + + @inject + def function10(self, a: int, b: NoInject[Optional[str]] = None): + # b:s type is Union[NoInject[Union[str, None]], None] + pass + + assert get_bindings(function9) == {'a': int} == get_bindings(function10)