Skip to content

Commit

Permalink
Merge branch 'di-container-handle-defaults' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
mssalvatore committed Mar 7, 2023
2 parents fc8d9ba + cb20874 commit 90fd53d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 9 deletions.
35 changes: 26 additions & 9 deletions monkey/common/di_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ def __init__(self, hostname: str):
def resolve(self, type_: Type[T]) -> T:
"""
Resolves all dependencies and returns a new instance of `type_` using constructor dependency
injection. Note that only positional arguments are resolved. Varargs, keyword-only args, and
default values are ignored.
injection. Note that only positional arguments or arguments with defaults are resolved.
Varargs and keyword-only args are ignored.
Dependencies are resolved with the following precedence
Expand Down Expand Up @@ -143,13 +143,23 @@ def resolve_dependencies(self, type_: Type[T]) -> Sequence[Any]:
"""
args = []

for arg_name, arg_type in inspect.getfullargspec(type_).annotations.items():
try:
instance = self._resolve_convention(arg_type, arg_name)
except UnregisteredConventionError:
instance = self._resolve_type(arg_type)
for parameter in inspect.signature(type_).parameters.values():
with suppress(UnregisteredConventionError):
args.append(self._resolve_convention(parameter.annotation, parameter.name))
continue

args.append(instance)
with suppress(UnresolvableDependencyError):
args.append(self._resolve_type(parameter.annotation))
continue

with suppress(UnresolvableDependencyError):
args.append(self._resolve_default(parameter.name, parameter.default))
continue

raise UnresolvableDependencyError(
f"Failed to resolve dependency {parameter.name} of type "
f"{DIContainer._format_type_name(parameter.annotation)}"
)

return tuple(args)

Expand All @@ -165,7 +175,8 @@ def _resolve_convention(self, type_: Type[T], name: str) -> T:
def _resolve_type(self, type_: Type[T]) -> T:
if type_ in self._type_registry:
return self._construct_new_instance(type_)
elif type_ in self._instance_registry:

if type_ in self._instance_registry:
return self._retrieve_registered_instance(type_)

raise UnresolvableDependencyError(
Expand All @@ -183,6 +194,12 @@ def _construct_new_instance(self, arg_type: Type[T]) -> T:
def _retrieve_registered_instance(self, arg_type: Type[T]) -> T:
return self._instance_registry[arg_type]

def _resolve_default(self, name: str, default: T) -> T:
if default is not inspect.Parameter.empty:
return default

raise UnresolvableDependencyError(f'No default found for "{name}"')

def release(self, interface: Type[T]):
"""
Deregister an interface
Expand Down
36 changes: 36 additions & 0 deletions monkey/tests/unit_tests/common/test_di_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,39 @@ def test_release_convention(container):
with pytest.raises(ValueError):
container.release_convention(str, "my_str")
container.resolve(TestClass6)


class Dependency:
def __init__(self, my_int=42):
self.my_int = my_int


class HasDefault:
def __init__(self, dependency: Dependency = Dependency(99)):
self.dependency = dependency


def test_handle_default_parameter__no_dependency_registered(container):
has_default = container.resolve(HasDefault)
assert has_default.dependency.my_int == 99


def test_handle_default_parameter__dependency_registered(container):
container.register(Dependency, Dependency)

has_default = container.resolve(HasDefault)
assert has_default.dependency.my_int == 42


def test_handle_default_parameter__skip_default(container):
class HasDefault_2_Parameters:
def __init__(self, dependency: Dependency = Dependency(99), my_str: str = "hello"):
self.dependency = dependency
self.my_str = my_str

container.register_instance(str, "goodbye")

has_default = container.resolve(HasDefault_2_Parameters)

assert has_default.dependency.my_int == 99
assert has_default.my_str == "goodbye"

0 comments on commit 90fd53d

Please sign in to comment.