Basic usage¶
You start by defining the container of your dependencies. Whenever you want the container to resolve a dependency, it uses the container to search for existing objects and a resolver automatically creates desired dependencies:
from inseminator import Container
class DomainModel:
def __init__(self):
self.__logic_constant = 1
def domain_logic(self, input_value: int) -> int:
return input_value + self.__logic_constant
class Controller:
def __init__(self, domain_model: DomainModel):
self.__domain_model = domain_model
def handler(self, input_value: int) -> int:
return self.__domain_model.domain_logic(input_value)
# entry-point of your application
container = Container()
# view layer handling
controller = container.resolve(Controller)
result = controller.handler(1)
print(result)
The strategy for resolving Controller is its constructor signature. The resolver works as follows.
We ask the
containerto resolve a dependencyController->container.resolve(Controller).Resolver inside the
containerchecks theController’s constructor signature, i.e. type hints of__init__method and seesdomain_models: DomainModel.If an instance of
DomainModelclass is already known by thecontainerit uses that instance. In the opposite case, the container starts the same resolving machinery forDomainModel- which is the exact case we are facing now.Because
DomainModeldoesn’t have any dependencies it can construct it directly.Now the resolver has all the dependencies for
Controllerconstructor and can instantiate it.
If we programmed against an interface instead of implementation the example is modified like this:
from inseminator import Container
from typing import Protocol
class DomainModel(Protocol):
def domain_logic(self, input_value: int) -> int:
...
class Controller:
def __init__(self, domain_model: DomainModel):
self.__domain_model = domain_model
def handler(self, input_value: int) -> int:
return self.__domain_model.domain_logic(input_value)
# domain model implementation
class ConcreteDomainModel:
def __init__(self):
self.__logic_constant = 1
def domain_logic(self, input_value: int) -> int:
return input_value + self.__logic_constant
# entry point of your application
container = Container()
container.register(DomainModel, value=ConcreateDomainModel())
# view layer handling
controller = container.resolve(Controller)
result = controller.handler(1)
print(result)
In this situation, protocol DomainModel doesn’t hold implementation details, only interface.
Using:
container.register(DomainModel, value=ConcreateDomainModel())
we’re guiding the resolver to use instance of ConcreateDomainModel in case someone asks
for DomainModel.