A decorator for injection dependencies into functions/methods, based
    on their type annotations.

    .. code-block:: python

        class SomeClass:
            @inject
            def __init__(self, my_dep: DepType) -> None:
                self.my_dep = my_dep

    .. important::

        On the opposite to :class:`~haps.Inject`, dependency is injected
        at the moment of method invocation. In case of decorating `__init__`,
        dependency is injected when `SomeClass` instance is created.

    :param fun: callable with annotated parameters
    :return: decorated callable

def inject(fun: Callable) -> Callable:
    """
    A decorator for injection dependencies into functions/methods, based
    on their type annotations.

    .. code-block:: python

        class SomeClass:
            @inject
            def __init__(self, my_dep: DepType) -> None:
                self.my_dep = my_dep

    .. important::

        On the opposite to :class:`~haps.Inject`, dependency is injected
        at the moment of method invocation. In case of decorating `__init__`,
        dependency is injected when `SomeClass` instance is created.

    :param fun: callable with annotated parameters
    :return: decorated callable
    """
    sig = inspect.signature(fun)

    injectables: Dict[str, Any] = {}
    for name, param in sig.parameters.items():
        type_ = param.annotation
        if name == 'self':
            continue
        else:
            injectables[name] = type_

    @wraps(fun)
    def _inner(*args, **kwargs):
        container = Container()
        for n, t in injectables.items():
            if n not in kwargs:
                kwargs[n] = container.get_object(t)

        return fun(*args, **kwargs)

    return _inner