Source code for injectable.autowiring.autowired_type

from typing import Union, TypeVar, Sequence

import typing_inspect

from injectable.autowiring.autowiring_utils import (
    sanitize_if_forward_ref,
    is_sequence,
    is_raw_sequence,
)
from injectable.injection.inject import inject, inject_multiple

T = TypeVar("T")


class _Autowired:
    def __init__(
        self,
        dependency: Union[T, str],
        *,
        namespace: str = None,
        group: str = None,
        exclude_groups: Sequence[str] = None,
        lazy: bool = False,
    ):
        optional = False
        multiple = False

        if typing_inspect.is_optional_type(dependency):
            dependency = typing_inspect.get_args(dependency, evaluate=True)[0]
            optional = True
        elif typing_inspect.is_union_type(dependency):
            raise TypeError(
                "Autowired Union can only be used to indicate"
                " optional autowiring in the forms 'Union[T, None]' or"
                " 'Optional[T]'"
            )

        if is_sequence(typing_inspect.get_origin(dependency) or dependency):
            subscripted_types = typing_inspect.get_args(dependency, evaluate=True)
            if subscripted_types == typing_inspect.get_args(Sequence):
                raise TypeError("Type not defined for Autowired list")
            subscripted_type = subscripted_types[0]
            if typing_inspect.is_optional_type(subscripted_type):
                raise TypeError(
                    "List of Optional is invalid for autowiring. Use"
                    " 'Autowired(Optional[List[...]])' instead."
                )
            elif typing_inspect.is_union_type(subscripted_type):
                raise TypeError("Only one type should be defined for Autowired list")
            dependency = subscripted_type
            multiple = True
        elif is_raw_sequence(dependency):
            if len(dependency) != 1:
                raise TypeError(
                    "Only one type should be defined for Autowired"
                    f" {dependency.__class__.__qualname__}"
                )
            dependency = dependency[0]
            multiple = True

        self.optional = optional
        self.multiple = multiple
        self.dependency = sanitize_if_forward_ref(dependency)
        self.namespace = namespace
        self.group = group
        self.exclude_groups = exclude_groups
        self.lazy = lazy

    def inject(self) -> T:
        if self.multiple:
            return inject_multiple(
                self.dependency,
                namespace=self.namespace,
                group=self.group,
                exclude_groups=self.exclude_groups,
                lazy=self.lazy,
                optional=self.optional,
            )
        return inject(
            self.dependency,
            namespace=self.namespace,
            group=self.group,
            exclude_groups=self.exclude_groups,
            lazy=self.lazy,
            optional=self.optional,
        )


[docs]class Autowired: """ Autowired type annotation marks a parameter to be autowired for injection. Autowired parameters must be last in declaration if there are others which aren't autowired. Also, autowired parameters must not be given default values. This type annotation does not performs the function autowiring by itself. The function must be decorated with :meth:`@autowired <injectable.autowired>` for autowiring. :param dependency: class, base class or qualifier of the dependency to be used for lookup among the registered injectables. Can be wrapped in a typing sequence, e.g. ``List[...]``, to inject a list containing all matching injectables. Can be wrapped in a optional, e.g. ``Optional[...]``, to inject None if no matches are found to inject. ``Optional[List[...]]`` is valid and will inject an empty list if no matches are found to inject. :param namespace: (optional) namespace in which to look for the dependency. Defaults to :const:`injectable.constants.DEFAULT_NAMESPACE`. :param group: (optional) group to filter out other injectables outside of this group. Defaults to None. :param exclude_groups: (optional) list of groups to be excluded. Defaults to None. :param lazy: (optional) when True will return an instance which will automatically initialize itself when first used but not before that. Defaults to False. Usage:: >>> from injectable import Autowired, autowired >>> >>> @autowired ... def foo(arg: Autowired("qualifier")): ... ... """ # fake signature to conform return type to be the same as the dependency arg def __new__( cls, dependency: Union[T, str], *, namespace: str = None, group: str = None, exclude_groups: Sequence[str] = None, lazy: bool = False, ) -> T: return _Autowired( dependency, namespace=namespace, group=group, exclude_groups=exclude_groups, lazy=lazy, )