mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 17:47:02 +03:00
114 lines
3.5 KiB
Python
114 lines
3.5 KiB
Python
"""Dependency injector injections module."""
|
|
|
|
import warnings
|
|
|
|
import six
|
|
|
|
from dependency_injector.providers.base import (
|
|
_parse_positional_injections,
|
|
_parse_keyword_injections,
|
|
)
|
|
from dependency_injector import utils
|
|
from dependency_injector import errors
|
|
|
|
|
|
def inject(*args, **kwargs):
|
|
"""Dependency injection decorator.
|
|
|
|
.. warning::
|
|
|
|
:py:func:`inject` decorator has been deprecated since version 2.2.0.
|
|
|
|
Usage of :py:func:`inject` decorator can lead to bad design and could
|
|
be considered as anti-pattern.
|
|
|
|
:py:func:`inject` decorator can be used for making inline dependency
|
|
injections. It patches decorated callable in such way that dependency
|
|
injection will be done during every call of decorated callable.
|
|
|
|
:py:func:`inject` decorator supports different syntaxes of passing
|
|
injections:
|
|
|
|
.. code-block:: python
|
|
|
|
# Positional arguments injections:
|
|
@inject(1, 2)
|
|
def some_function(arg1, arg2):
|
|
pass
|
|
|
|
# Keyword arguments injections:
|
|
@inject(arg1=1)
|
|
@inject(arg2=2)
|
|
def some_function(arg1, arg2):
|
|
pass
|
|
|
|
# Keyword arguments injections into class init:
|
|
@inject(arg1=1)
|
|
@inject(arg2=2)
|
|
class SomeClass(object):
|
|
|
|
def __init__(self, arg1, arg2):
|
|
pass
|
|
|
|
.. deprecated:: 2.2.0
|
|
Usage of :py:func:`inject` decorator can lead to bad design and could
|
|
be considered as anti-pattern.
|
|
|
|
:param args: Tuple of context positional arguments.
|
|
:type args: tuple[object]
|
|
|
|
:param kwargs: Dictionary of context keyword arguments.
|
|
:type kwargs: dict[str, object]
|
|
|
|
:return: Class / callable decorator
|
|
:rtype: (callable) -> (type | callable)
|
|
"""
|
|
warnings.warn(message='Call to a deprecated decorator - @{0}.{1}'
|
|
.format(inject.__module__, inject.__name__),
|
|
category=DeprecationWarning,
|
|
stacklevel=2)
|
|
|
|
arg_injections = _parse_positional_injections(args)
|
|
kwarg_injections = _parse_keyword_injections(kwargs)
|
|
|
|
def decorator(callback_or_cls):
|
|
"""Dependency injection decorator."""
|
|
if isinstance(callback_or_cls, six.class_types):
|
|
cls = callback_or_cls
|
|
cls_init = utils.fetch_cls_init(cls)
|
|
if not cls_init:
|
|
raise errors.Error(
|
|
'Class {0}.{1} has no __init__() '.format(cls.__module__,
|
|
cls.__name__) +
|
|
'method and could not be decorated with @inject decorator')
|
|
cls.__init__ = decorator(cls_init)
|
|
return cls
|
|
|
|
callback = callback_or_cls
|
|
|
|
if hasattr(callback, '__INJECT_DECORATED__'):
|
|
callback.args += arg_injections
|
|
callback.kwargs.update(kwarg_injections)
|
|
return callback
|
|
|
|
@six.wraps(callback)
|
|
def decorated(*args, **kwargs):
|
|
"""Decorated with dependency injection callback."""
|
|
if decorated.args:
|
|
args = tuple(arg.provide_injection()
|
|
for arg in decorated.args) + args
|
|
|
|
for name, arg in six.iteritems(decorated.kwargs):
|
|
if name not in kwargs:
|
|
kwargs[name] = arg.provide_injection()
|
|
|
|
return callback(*args, **kwargs)
|
|
|
|
decorated.__INJECT_DECORATED__ = True
|
|
decorated.origin = callback
|
|
decorated.args = arg_injections
|
|
decorated.kwargs = kwarg_injections
|
|
|
|
return decorated
|
|
return decorator
|