Annotations
Autowiring relies on annotations or hints to be able to inject dependencies. When it is not possible to automatically locate a given dependency, it must be annotated with additional metadata.
When do you need to provide annotations.
Injecting | Annotations required? | What is required |
---|---|---|
Services | No | |
Interface with only one implementation | No | |
Default implementation of an interface | No | |
Interface with multiple implementations | Yes | Qualifier |
Parameters | Yes | Parameter name |
Parameter expressions | Yes | Expression |
Annotation types
Wireup supports two types of annotations. Using Python's Annotated
and default values.
Annotated
This is the preferred method for Python 3.9+ and moving forward. It is also recommended to
backport this using typing_extensions
for Python 3.8.
@container.autowire
def target(
env: Annotated[str, Inject(param="env_name")],
logs_cache_dir: Annotated[str, Inject(expr="${cache_dir}/logs")],
):
...
Default values (deprecated)
This relies on the use of default values to inject parameters. Anything that can be passed to Annotated
may also
be used here.
@container.autowire
def target(
env: str = Inject(param="env_name"),
logs_cache_dir: str = Inject(expr="${cache_dir}/logs")
):
...
Explicit injection annotation
Even though annotating services is optional, you CAN still annotate them to be explicit about what will be injected. This also has the benefit of making the container throw when such as service does not exist instead of silently skipping this parameter.
This has limited application when using annotated types as the runtime will raise regardless, but when using default values as annotations it can be quite useful.
@container.autowire
def target(random_service: Annotated[RandomService, Inject()]):
...