python-dependency-injector/dependency_injector/injections.py

114 lines
3.5 KiB
Python
Raw Normal View History

2016-06-03 12:03:27 +03:00
"""Dependency injector injections module."""
2015-01-10 12:24:25 +03:00
import warnings
import six
2016-05-29 16:39:39 +03:00
from dependency_injector.providers.base import (
_parse_positional_injections,
_parse_keyword_injections,
)
2016-05-29 16:39:39 +03:00
from dependency_injector import utils
from dependency_injector import errors
2015-01-10 12:24:25 +03:00
def inject(*args, **kwargs):
"""Dependency injection decorator.
2016-09-23 00:24:45 +03:00
.. 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.
2015-11-24 11:33:10 +03:00
: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
2016-05-29 16:39:39 +03:00
# Positional arguments injections:
2015-11-24 11:33:10 +03:00
@inject(1, 2)
def some_function(arg1, arg2):
pass
2016-05-29 16:39:39 +03:00
# Keyword arguments injections:
2015-11-24 11:33:10 +03:00
@inject(arg1=1)
@inject(arg2=2)
def some_function(arg1, arg2):
pass
2016-05-29 16:39:39 +03:00
# Keyword arguments injections into class init:
2015-11-24 11:33:10 +03:00
@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.
2015-11-25 16:02:20 +03:00
:param args: Tuple of context positional arguments.
:type args: tuple[object]
:param kwargs: Dictionary of context keyword arguments.
:type kwargs: dict[str, object]
2015-11-24 11:33:10 +03:00
: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)
2016-05-29 16:39:39 +03:00
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
2016-05-29 16:39:39 +03:00
cls_init = utils.fetch_cls_init(cls)
2016-03-01 16:42:06 +03:00
if not cls_init:
2016-05-29 16:39:39 +03:00
raise errors.Error(
2016-03-01 16:42:06 +03:00
'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
2016-03-01 13:25:54 +03:00
if hasattr(callback, '__INJECT_DECORATED__'):
callback.args += arg_injections
2016-05-29 16:39:39 +03:00
callback.kwargs.update(kwarg_injections)
return callback
@six.wraps(callback)
def decorated(*args, **kwargs):
"""Decorated with dependency injection callback."""
2016-02-08 01:29:41 +03:00
if decorated.args:
args = tuple(arg.provide_injection()
for arg in decorated.args) + args
2016-02-08 01:29:41 +03:00
2016-05-29 16:39:39 +03:00
for name, arg in six.iteritems(decorated.kwargs):
if name not in kwargs:
kwargs[name] = arg.provide_injection()
2016-02-08 01:29:41 +03:00
return callback(*args, **kwargs)
decorated.__INJECT_DECORATED__ = True
decorated.origin = callback
decorated.args = arg_injections
decorated.kwargs = kwarg_injections
return decorated
return decorator