Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions injector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
log = logging.getLogger('injector')
log.addHandler(logging.NullHandler())

if log.level == logging.NOTSET:
if log.level == logging.NOTSET: # pragma: no cover
log.setLevel(logging.WARN)

T = TypeVar('T')
Expand Down Expand Up @@ -782,9 +782,9 @@ def _punch_through_alias(type_: Any) -> type:
def _get_origin(type_: type) -> Optional[type]:
origin = getattr(type_, '__origin__', None)
# Older typing behaves differently there and stores Dict and List as origin, we need to be flexible.
if origin is List:
if origin is List: # pragma: no cover
return list
elif origin is Dict:
elif origin is Dict: # pragma: no cover
return dict
return origin

Expand Down
69 changes: 69 additions & 0 deletions injector_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
ScopeDecorator,
SingletonScope,
UnknownArgument,
UnknownProvider,
UnsatisfiedRequirement,
get_bindings,
inject,
Expand Down Expand Up @@ -1049,6 +1050,15 @@ def test_custom_scope():
injector.get(Handler)


def test_get_accepts_a_scope_decorator_and_applies_that_scope():
class A:
pass

injector = Injector()
assert injector.get(A) is not injector.get(A)
assert injector.get(A, scope=singleton) is injector.get(A, scope=singleton)


def test_binder_install():
class ModuleA(Module):
def configure(self, binder):
Expand Down Expand Up @@ -1112,6 +1122,12 @@ def test_binder_provider_for_type_with_metaclass():
assert isinstance(binder.provider_for(A, None).get(injector), A)


def test_binder_provider_for_raises_unknown_provider_for_undeterminable_binding():
binder = Injector().binder
with pytest.raises(UnknownProvider):
binder.provider_for('not-a-type', to='a string value')


class ClassA:
def __init__(self, parameter):
pass
Expand Down Expand Up @@ -1618,6 +1634,16 @@ def __init__(self, message: str) -> None:
del X


def test_provider_with_unresolvable_forward_reference_return_type_raises_name_error():
class CustomModule(Module):
@provider
def provide_x(self) -> 'ReferenceThatCannotBeResolved':
return object()

with pytest.raises(NameError):
Injector(CustomModule)


def test_more_useful_exception_is_raised_when_parameters_type_is_any():
@inject
def fun(a: Any) -> None:
Expand All @@ -1640,6 +1666,41 @@ def fun(a: Any) -> None:
injector.call_with_injection(fun)


def test_create_object_wraps_new_typeerror_in_call_error():
class ClassWhoseNewRequiresAnArgument:
def __new__(cls, required_argument):
return super().__new__(cls)

with pytest.raises(CallError):
Injector().create_object(ClassWhoseNewRequiresAnArgument)


def test_unsatisfied_requirement_message_names_owning_module_for_a_function():
class Unbound:
pass

@inject
def function(dependency: Unbound) -> None:
pass

injector = Injector(auto_bind=False)
with pytest.raises(UnsatisfiedRequirement) as exc_info:
injector.call_with_injection(function)

assert str(exc_info.value) == '%s has an unsatisfied requirement on Unbound' % __name__


def test_unsatisfied_requirement_message_describes_a_tuple_interface():
class A:
pass

injector = Injector(auto_bind=False)
with pytest.raises(UnsatisfiedRequirement) as exc_info:
injector.get((A,))

assert str(exc_info.value) == 'unsatisfied requirement on [A]'


def test_optionals_are_ignored_for_now():
@inject
def fun(s: str = None):
Expand Down Expand Up @@ -2026,6 +2087,14 @@ def function(a: Inject[Inject[int]]) -> None:
assert get_bindings(function) == {'a': int}


def test_get_bindings_excludes_union_with_a_noinject_member() -> None:
@inject
def function_with_noinject_nested_in_union(a: Union[NoInject[int], str]) -> None:
pass

assert get_bindings(function_with_noinject_nested_in_union) == {}


# Tests https://github.com/alecthomas/injector/issues/202
def test_get_bindings_for_pep_604():
@inject
Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[pytest]
addopts = -v --tb=native --doctest-glob=*.md --doctest-modules --cov-report term --cov-report html --cov-report xml --cov=injector --cov-branch --cov-fail-under=90
addopts = -v --tb=native --doctest-glob=*.md --doctest-modules --cov-report term --cov-report html --cov-report xml --cov=injector --cov-branch --cov-fail-under=100
norecursedirs = __pycache__ *venv* .git build
Loading