python-dependency-injector/dependency_injector/injections.py

117 lines
3.1 KiB
Python
Raw Normal View History

2015-03-09 01:01:39 +03:00
"""Injections module."""
2015-01-10 12:24:25 +03:00
import sys
import six
from .utils import is_provider
from .utils import ensure_is_injection
from .utils import get_injectable_kwargs
from .errors import Error
2015-01-10 12:24:25 +03:00
IS_PYPY = '__pypy__' in sys.builtin_module_names
if IS_PYPY or six.PY3: # pragma: no cover
OBJECT_INIT = six.get_unbound_function(object.__init__)
else: # pragma: no cover
OBJECT_INIT = None
2015-01-10 12:24:25 +03:00
class Injection(object):
2015-03-09 01:01:39 +03:00
"""Base injection class."""
2015-01-10 12:24:25 +03:00
2015-07-22 10:53:16 +03:00
__IS_INJECTION__ = True
__slots__ = ('injectable', 'is_provider')
def __init__(self, injectable):
2015-03-09 01:01:39 +03:00
"""Initializer."""
2015-01-10 12:24:25 +03:00
self.injectable = injectable
self.is_provider = is_provider(injectable)
2015-01-10 12:24:25 +03:00
2015-01-11 16:03:45 +03:00
@property
def value(self):
2015-03-09 01:01:39 +03:00
"""Return injectable value."""
if self.is_provider:
2015-01-11 16:03:45 +03:00
return self.injectable()
return self.injectable
2015-01-10 12:24:25 +03:00
class NamedInjection(Injection):
"""Base class of named injections."""
__slots__ = ('name',)
def __init__(self, name, injectable):
"""Initializer."""
self.name = name
super(NamedInjection, self).__init__(injectable)
class Arg(Injection):
"""Positional argument injection."""
__IS_ARG_INJECTION__ = True
class KwArg(NamedInjection):
"""Keyword argument injection."""
2015-01-10 12:24:25 +03:00
2015-07-22 10:53:16 +03:00
__IS_KWARG_INJECTION__ = True
2015-01-10 12:24:25 +03:00
class Attribute(NamedInjection):
2015-03-09 01:01:39 +03:00
"""Attribute injection."""
2015-01-10 12:24:25 +03:00
2015-07-22 10:53:16 +03:00
__IS_ATTRIBUTE_INJECTION__ = True
2015-01-10 12:24:25 +03:00
class Method(NamedInjection):
2015-03-09 01:01:39 +03:00
"""Method injection."""
2015-07-22 10:53:16 +03:00
__IS_METHOD_INJECTION__ = True
def inject(*args, **kwargs):
"""Dependency injection decorator.
:type injection: Injection
:return: (callable) -> (callable)
"""
2015-09-03 16:00:23 +03:00
injections = tuple(KwArg(name, value)
for name, value in six.iteritems(kwargs))
if args:
2015-09-03 16:00:23 +03:00
injections += tuple(ensure_is_injection(injection)
for injection in args)
def decorator(callback_or_cls):
"""Dependency injection decorator."""
if isinstance(callback_or_cls, six.class_types):
cls = callback_or_cls
try:
cls_init = six.get_unbound_function(cls.__init__)
assert cls_init is not OBJECT_INIT
except (AttributeError, AssertionError):
raise 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
2015-09-14 10:53:24 +03:00
if hasattr(callback, 'injections'):
callback.injections += injections
return callback
@six.wraps(callback)
def decorated(*args, **kwargs):
"""Decorated with dependency injection callback."""
return callback(*args,
**get_injectable_kwargs(kwargs,
2015-09-14 10:53:24 +03:00
decorated.injections))
2015-09-14 10:53:24 +03:00
decorated.injections = injections
return decorated
return decorator