Working with Interfaces
When autowiring dependencies, you might want to inject an interface rather than the concrete implementation directly. Since Python doesn't have built-in interfaces, you can leverage any class that's marked as abstract within the container.
The following code registers Engine
as an interface. This implies that Engine
can't be directly injected.
Instead, a dependency that implements the interface must be present and also be registered in the container.
@container.abstract
class Engine:
def do_thing(self):
...
To autowire interfaces, you can simply register a dependency that implements the interface within the container. When injecting, ask for the interface itself, not its concrete implementation.
@container.register
class CombustionEngine(Engine):
def do_thing(self):
return "I'm a Combustion Engine"
@container.autowire
def do_engine_things(engine: Engine):
return engine.do_thing() # Returns "I'm a Combustion Engine"
In scenarios where there are multiple implementations of an interface, each implementation must be associated with a qualifier.
@container.register(qualifier="electric")
class ElectricEngine(Engine):
def do_thing(self):
return "I'm an Electric Engine"
@container.register(qualifier="combustion")
class CombustionEngine(Engine):
def do_thing(self):
return "I'm a Combustion Engine"
While injecting an interface with multiple implementing dependencies, you need to specify a qualifier to indicate which concrete class should be resolved.
container.autowire
def target(
engine: Annotated[Engine, Wire(qualifier="electric")],
combustion: Annotated[Engine, Wire(qualifier="combustion")],
):
...