Skip to content

Commit

Permalink
Rename parameters in method signatures.
Browse files Browse the repository at this point in the history
  • Loading branch information
runemalm committed Mar 23, 2024
1 parent e84eddd commit dafdace
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 154 deletions.
88 changes: 44 additions & 44 deletions src/dependency_injection/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

class DependencyContainer(metaclass=SingletonMeta):

def __init__(self, name=None):
def __init__(self, name: str=None):
self.name = name if name is not None else DEFAULT_CONTAINER_NAME
self._registrations = {}
self._singleton_instances = {}
self._scoped_instances = {}

@classmethod
def get_instance(cls, name=None):
def get_instance(cls, name: str=None):
if name is None:
name = DEFAULT_CONTAINER_NAME

Expand All @@ -26,88 +26,88 @@ def get_instance(cls, name=None):

return cls._instances[(cls, name)]

def register_transient(self, interface, class_, constructor_args=None):
if interface in self._registrations:
raise ValueError(f"Dependency {interface} is already registered.")
self._registrations[interface] = Registration(interface, class_, Scope.TRANSIENT, constructor_args)
def register_transient(self, dependency: Type, implementation: Type, constructor_args=None):
if dependency in self._registrations:
raise ValueError(f"Dependency {dependency} is already registered.")
self._registrations[dependency] = Registration(dependency, implementation, Scope.TRANSIENT, constructor_args)

def register_scoped(self, interface, class_, constructor_args=None):
if interface in self._registrations:
raise ValueError(f"Dependency {interface} is already registered.")
self._registrations[interface] = Registration(interface, class_, Scope.SCOPED, constructor_args)
def register_scoped(self, dependency: Type, implementation: Type, constructor_args=None):
if dependency in self._registrations:
raise ValueError(f"Dependency {dependency} is already registered.")
self._registrations[dependency] = Registration(dependency, implementation, Scope.SCOPED, constructor_args)

def register_singleton(self, interface, class_, constructor_args=None):
if interface in self._registrations:
raise ValueError(f"Dependency {interface} is already registered.")
self._registrations[interface] = Registration(interface, class_, Scope.SINGLETON, constructor_args)
def register_singleton(self, dependency: Type, implementation: Type, constructor_args=None):
if dependency in self._registrations:
raise ValueError(f"Dependency {dependency} is already registered.")
self._registrations[dependency] = Registration(dependency, implementation, Scope.SINGLETON, constructor_args)

def resolve(self, interface, scope_name=DEFAULT_SCOPE_NAME):
def resolve(self, dependency: Type, scope_name=DEFAULT_SCOPE_NAME):
if scope_name not in self._scoped_instances:
self._scoped_instances[scope_name] = {}

if interface not in self._registrations:
raise KeyError(f"Dependency {interface.__name__} is not registered.")
if dependency not in self._registrations:
raise KeyError(f"Dependency {dependency.__name__} is not registered.")

registration = self._registrations[interface]
dependency_scope = registration.scope
dependency_class = registration.class_
registration = self._registrations[dependency]
scope = registration.scope
implementation = registration.implementation
constructor_args = registration.constructor_args

self._validate_constructor_args(constructor_args=constructor_args, class_=dependency_class)
self._validate_constructor_args(constructor_args=constructor_args, implementation=implementation)

if dependency_scope == Scope.TRANSIENT:
if scope == Scope.TRANSIENT:
return self._inject_dependencies(
class_=dependency_class,
implementation=implementation,
constructor_args=constructor_args
)
elif dependency_scope == Scope.SCOPED:
if interface not in self._scoped_instances[scope_name]:
self._scoped_instances[scope_name][interface] = (
elif scope == Scope.SCOPED:
if dependency not in self._scoped_instances[scope_name]:
self._scoped_instances[scope_name][dependency] = (
self._inject_dependencies(
class_=dependency_class,
implementation=implementation,
scope_name=scope_name,
constructor_args=constructor_args,
))
return self._scoped_instances[scope_name][interface]
elif dependency_scope == Scope.SINGLETON:
if interface not in self._singleton_instances:
self._singleton_instances[interface] = (
return self._scoped_instances[scope_name][dependency]
elif scope == Scope.SINGLETON:
if dependency not in self._singleton_instances:
self._singleton_instances[dependency] = (
self._inject_dependencies(
class_=dependency_class,
implementation=implementation,
constructor_args=constructor_args
)
)
return self._singleton_instances[interface]
return self._singleton_instances[dependency]

raise ValueError(f"Invalid dependency scope: {dependency_scope}")
raise ValueError(f"Invalid dependency scope: {scope}")

def _validate_constructor_args(self, constructor_args: Dict[str, Any], class_: Type) -> None:
class_constructor = inspect.signature(class_.__init__).parameters
def _validate_constructor_args(self, constructor_args: Dict[str, Any], implementation: Type) -> None:
constructor = inspect.signature(implementation.__init__).parameters

# Check if any required parameter is missing
missing_params = [param for param in class_constructor.keys() if
missing_params = [param for param in constructor.keys() if
param not in ["self", "cls", "args", "kwargs"] and
param not in constructor_args]
if missing_params:
raise ValueError(
f"Missing required constructor arguments: "
f"{', '.join(missing_params)} for class '{class_.__name__}'.")
f"{', '.join(missing_params)} for class '{implementation.__name__}'.")

for arg_name, arg_value in constructor_args.items():
if arg_name not in class_constructor:
if arg_name not in constructor:
raise ValueError(
f"Invalid constructor argument '{arg_name}' for class '{class_.__name__}'. "
f"Invalid constructor argument '{arg_name}' for class '{implementation.__name__}'. "
f"The class does not have a constructor parameter with this name.")

expected_type = class_constructor[arg_name].annotation
expected_type = constructor[arg_name].annotation
if expected_type != inspect.Parameter.empty:
if not isinstance(arg_value, expected_type):
raise TypeError(
f"Constructor argument '{arg_name}' has an incompatible type. "
f"Expected type: {expected_type}, provided type: {type(arg_value)}.")

def _inject_dependencies(self, class_, scope_name=None, constructor_args=None):
constructor = inspect.signature(class_.__init__)
def _inject_dependencies(self, implementation, scope_name=None, constructor_args=None):
constructor = inspect.signature(implementation.__init__)
params = constructor.parameters

dependencies = {}
Expand All @@ -127,4 +127,4 @@ def _inject_dependencies(self, class_, scope_name=None, constructor_args=None):
else:
dependencies[param_name] = self.resolve(param_info.annotation, scope_name=scope_name)

return class_(**dependencies)
return implementation(**dependencies)
8 changes: 4 additions & 4 deletions src/dependency_injection/registration.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from typing import Any, Dict
from typing import Any, Dict, Type

from dependency_injection.scope import Scope


class Registration():

def __init__(self, interface, class_, scope: Scope, constructor_args: Dict[str, Any] = None):
self.interface = interface
self.class_ = class_
def __init__(self, dependency: Type, implementation: Type, scope: Scope, constructor_args: Dict[str, Any] = None):
self.dependency = dependency
self.implementation = implementation
self.scope = scope
self.constructor_args = constructor_args or {}
14 changes: 7 additions & 7 deletions tests/unit_test/container/register/test_register_scoped.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency = Vehicle
implementation = Car

# act
dependency_container.register_scoped(interface, dependency_class)
dependency_container.register_scoped(dependency, implementation)

# assert
# (no exception thrown)
Expand All @@ -37,10 +37,10 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_scoped(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_scoped(dependency, implementation)

# act + assert
with pytest.raises(ValueError, match="is already registered"):
dependency_container.register_scoped(interface, dependency_class)
dependency_container.register_scoped(dependency, implementation)
14 changes: 7 additions & 7 deletions tests/unit_test/container/register/test_register_singleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency = Vehicle
implementation = Car

# act
dependency_container.register_singleton(interface, dependency_class)
dependency_container.register_singleton(dependency, implementation)

# assert
# (no exception thrown)
Expand All @@ -37,10 +37,10 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_singleton(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_singleton(dependency, implementation)

# act + assert
with pytest.raises(ValueError, match="is already registered"):
dependency_container.register_singleton(interface, dependency_class)
dependency_container.register_singleton(dependency, implementation)
14 changes: 7 additions & 7 deletions tests/unit_test/container/register/test_register_transient.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency = Vehicle
implementation = Car

# act
dependency_container.register_transient(interface, dependency_class)
dependency_container.register_transient(dependency, implementation)

# assert (no exception thrown)

Expand All @@ -36,10 +36,10 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_transient(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_transient(dependency, implementation)

# act + assert
with pytest.raises(ValueError, match="is already registered"):
dependency_container.register_transient(interface, dependency_class)
dependency_container.register_transient(dependency, implementation)
6 changes: 3 additions & 3 deletions tests/unit_test/container/register/test_register_with_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency = Vehicle
implementation = Car

# act + assert (no exception)
dependency_container.register_transient(interface, dependency_class, constructor_args={"color": "red", "mileage": 3800})
dependency_container.register_transient(dependency, implementation, constructor_args={"color": "red", "mileage": 3800})
20 changes: 10 additions & 10 deletions tests/unit_test/container/resolve/test_resolve_scoped.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_scoped(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_scoped(dependency, implementation)

# act
resolved_dependency_in_scope_1 = dependency_container.resolve(interface, scope_name="test-scope")
resolved_dependency_in_scope_2 = dependency_container.resolve(interface, scope_name="test-scope")
resolved_dependency_in_scope_1 = dependency_container.resolve(dependency, scope_name="test-scope")
resolved_dependency_in_scope_2 = dependency_container.resolve(dependency, scope_name="test-scope")

# assert
self.assertEqual(resolved_dependency_in_scope_1, resolved_dependency_in_scope_2)
Expand All @@ -37,13 +37,13 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_scoped(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_scoped(dependency, implementation)

# act
resolved_dependency_in_scope_1 = dependency_container.resolve(interface, scope_name="scope_1")
resolved_dependency_in_scope_2 = dependency_container.resolve(interface, scope_name="scope_2")
resolved_dependency_in_scope_1 = dependency_container.resolve(dependency, scope_name="scope_1")
resolved_dependency_in_scope_2 = dependency_container.resolve(dependency, scope_name="scope_2")

# assert
self.assertNotEqual(resolved_dependency_in_scope_1, resolved_dependency_in_scope_2)
18 changes: 9 additions & 9 deletions tests/unit_test/container/resolve/test_resolve_singleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_singleton(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_singleton(dependency, implementation)

# act
resolved_dependency = dependency_container.resolve(interface)
resolved_dependency = dependency_container.resolve(dependency)

# assert
self.assertIsInstance(resolved_dependency, Car)
Expand All @@ -36,13 +36,13 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer()
interface = Vehicle
dependency_class = Car
dependency_container.register_singleton(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_singleton(dependency, implementation)

# act
resolved_dependency_1 = dependency_container.resolve(interface)
resolved_dependency_2 = dependency_container.resolve(interface)
resolved_dependency_1 = dependency_container.resolve(dependency)
resolved_dependency_2 = dependency_container.resolve(dependency)

# assert
self.assertEqual(resolved_dependency_1, resolved_dependency_2)
18 changes: 9 additions & 9 deletions tests/unit_test/container/resolve/test_resolve_transient.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer.get_instance()
interface = Vehicle
dependency_class = Car
dependency_container.register_transient(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_transient(dependency, implementation)

# act
resolved_dependency = dependency_container.resolve(interface)
resolved_dependency = dependency_container.resolve(dependency)

# assert
self.assertIsInstance(resolved_dependency, Car)
Expand All @@ -36,13 +36,13 @@ class Car(Vehicle):
pass

dependency_container = DependencyContainer()
interface = Vehicle
dependency_class = Car
dependency_container.register_transient(interface, dependency_class)
dependency = Vehicle
implementation = Car
dependency_container.register_transient(dependency, implementation)

# act
resolved_dependency_1 = dependency_container.resolve(interface)
resolved_dependency_2 = dependency_container.resolve(interface)
resolved_dependency_1 = dependency_container.resolve(dependency)
resolved_dependency_2 = dependency_container.resolve(dependency)

# assert
self.assertNotEqual(resolved_dependency_1, resolved_dependency_2)
Loading

0 comments on commit dafdace

Please sign in to comment.