2016-04-03 17:27:53 +03:00
|
|
|
"""Dependency injector creational providers."""
|
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
import six
|
|
|
|
|
2016-04-03 17:27:53 +03:00
|
|
|
from dependency_injector.providers.callable import Callable
|
2016-05-18 01:17:15 +03:00
|
|
|
from dependency_injector.injections import Attribute
|
2016-05-18 00:05:10 +03:00
|
|
|
from dependency_injector.utils import GLOBAL_LOCK
|
2016-04-03 17:27:53 +03:00
|
|
|
from dependency_injector.errors import Error
|
|
|
|
|
|
|
|
|
|
|
|
class Factory(Callable):
|
2016-05-18 01:17:15 +03:00
|
|
|
r""":py:class:`Factory` provider creates new instance on every call.
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
:py:class:`Factory` supports positional & keyword argument injections,
|
2016-05-22 14:57:25 +03:00
|
|
|
as well as attribute injections.
|
|
|
|
|
|
|
|
Positional and keyword argument injections could be defined like this:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
factory = Factory(SomeClass,
|
|
|
|
'positional_arg1', 'positional_arg2',
|
|
|
|
keyword_argument1=3, keyword_argument=4)
|
|
|
|
|
|
|
|
# or
|
|
|
|
|
|
|
|
factory = Factory(SomeClass) \
|
|
|
|
.args('positional_arg1', 'positional_arg2') \
|
|
|
|
.kwargs(keyword_argument1=3, keyword_argument=4)
|
|
|
|
|
|
|
|
# or
|
|
|
|
|
|
|
|
factory = Factory(SomeClass)
|
|
|
|
factory.args('positional_arg1', 'positional_arg2')
|
|
|
|
factory.kwargs(keyword_argument1=3, keyword_argument=4)
|
|
|
|
|
|
|
|
|
|
|
|
Attribute injections are defined by using :py:meth:`Factory.attributes`:
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
factory = Factory(SomeClass) \
|
2016-05-22 14:57:25 +03:00
|
|
|
.attributes(attribute1=1, attribute2=2)
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
Retrieving of provided instance can be performed via calling
|
|
|
|
:py:class:`Factory` object:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
factory = Factory(SomeClass)
|
2016-04-03 17:27:53 +03:00
|
|
|
some_object = factory()
|
|
|
|
|
|
|
|
.. py:attribute:: provided_type
|
|
|
|
|
|
|
|
If provided type is defined, :py:class:`Factory` checks that
|
|
|
|
:py:attr:`Factory.provides` is subclass of
|
|
|
|
:py:attr:`Factory.provided_type`.
|
|
|
|
|
|
|
|
:type: type | None
|
|
|
|
|
|
|
|
.. py:attribute:: cls
|
|
|
|
|
|
|
|
Class that provides object.
|
|
|
|
Alias for :py:attr:`provides`.
|
|
|
|
|
|
|
|
:type: type
|
|
|
|
"""
|
|
|
|
|
|
|
|
provided_type = None
|
|
|
|
|
2016-05-18 00:05:10 +03:00
|
|
|
__slots__ = ('cls', '_attributes')
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 15:07:48 +03:00
|
|
|
def __init__(self, provides, *args, **kwargs):
|
2016-04-03 17:27:53 +03:00
|
|
|
"""Initializer.
|
|
|
|
|
|
|
|
:param provides: Class or other callable that provides object
|
|
|
|
for creation.
|
|
|
|
:type provides: type | callable
|
|
|
|
"""
|
|
|
|
if (self.__class__.provided_type and
|
|
|
|
not issubclass(provides, self.__class__.provided_type)):
|
|
|
|
raise Error('{0} can provide only {1} instances'.format(
|
|
|
|
self.__class__, self.__class__.provided_type))
|
|
|
|
|
2016-05-18 00:05:10 +03:00
|
|
|
self._attributes = tuple()
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 15:07:48 +03:00
|
|
|
super(Factory, self).__init__(provides, *args, **kwargs)
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
self.cls = self._provides
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def injections(self):
|
|
|
|
"""Read-only tuple of all injections.
|
|
|
|
|
|
|
|
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
|
|
|
|
"""
|
2016-05-18 01:17:15 +03:00
|
|
|
return super(Factory, self).injections + self._attributes
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 00:05:10 +03:00
|
|
|
def attributes(self, **kwargs):
|
|
|
|
"""Add attribute injections.
|
2016-05-16 11:16:14 +03:00
|
|
|
|
|
|
|
:param kwargs: Dictionary of injections.
|
|
|
|
:type kwargs: dict
|
|
|
|
|
2016-05-18 00:05:10 +03:00
|
|
|
:return: Reference ``self``
|
|
|
|
"""
|
2016-05-18 01:17:15 +03:00
|
|
|
self._attributes += tuple(Attribute(name, value)
|
|
|
|
for name, value in six.iteritems(kwargs))
|
2016-05-17 22:37:50 +03:00
|
|
|
return self
|
2016-05-16 11:16:14 +03:00
|
|
|
|
2016-04-03 17:27:53 +03:00
|
|
|
def _provide(self, *args, **kwargs):
|
|
|
|
"""Return provided instance.
|
|
|
|
|
|
|
|
:param args: Tuple of context positional arguments.
|
|
|
|
:type args: tuple[object]
|
|
|
|
|
|
|
|
:param kwargs: Dictionary of context keyword arguments.
|
|
|
|
:type kwargs: dict[str, object]
|
|
|
|
|
|
|
|
:rtype: object
|
|
|
|
"""
|
2016-05-18 00:05:10 +03:00
|
|
|
if self._args:
|
2016-05-22 15:37:39 +03:00
|
|
|
args = tuple(arg.get_value() for arg in self._args) + args
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 00:05:10 +03:00
|
|
|
for kwarg in self._kwargs:
|
2016-04-03 17:27:53 +03:00
|
|
|
if kwarg.name not in kwargs:
|
2016-05-22 15:37:39 +03:00
|
|
|
kwargs[kwarg.name] = kwarg.get_value()
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
instance = self._provides(*args, **kwargs)
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 00:05:10 +03:00
|
|
|
for attribute in self._attributes:
|
2016-05-22 15:37:39 +03:00
|
|
|
setattr(instance, attribute.name, attribute.get_value())
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
return instance
|
|
|
|
|
|
|
|
|
|
|
|
class DelegatedFactory(Factory):
|
|
|
|
""":py:class:`DelegatedFactory` is a delegated :py:class:`Factory`.
|
|
|
|
|
|
|
|
:py:class:`DelegatedFactory` is a :py:class:`Factory`, that is injected
|
|
|
|
"as is".
|
|
|
|
|
|
|
|
.. py:attribute:: provided_type
|
|
|
|
|
|
|
|
If provided type is defined, :py:class:`Factory` checks that
|
|
|
|
:py:attr:`Factory.provides` is subclass of
|
|
|
|
:py:attr:`Factory.provided_type`.
|
|
|
|
|
|
|
|
:type: type | None
|
|
|
|
|
|
|
|
.. py:attribute:: cls
|
|
|
|
|
|
|
|
Class that provides object.
|
|
|
|
Alias for :py:attr:`provides`.
|
|
|
|
|
|
|
|
:type: type
|
|
|
|
"""
|
|
|
|
|
|
|
|
__IS_DELEGATED__ = True
|
|
|
|
|
|
|
|
|
|
|
|
class Singleton(Factory):
|
|
|
|
""":py:class:`Singleton` provider returns same instance on every call.
|
|
|
|
|
|
|
|
:py:class:`Singleton` provider creates instance once and return it on every
|
|
|
|
call. :py:class:`Singleton` extends :py:class:`Factory`, so, please follow
|
|
|
|
:py:class:`Factory` documentation to go inside with injections syntax.
|
|
|
|
|
|
|
|
:py:class:`Singleton` is thread-safe and could be used in multithreading
|
|
|
|
environment without any negative impact.
|
|
|
|
|
|
|
|
Retrieving of provided instance can be performed via calling
|
|
|
|
:py:class:`Singleton` object:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
singleton = Singleton(SomeClass)
|
2016-04-03 17:27:53 +03:00
|
|
|
some_object = singleton()
|
|
|
|
|
|
|
|
.. py:attribute:: provided_type
|
|
|
|
|
|
|
|
If provided type is defined, :py:class:`Factory` checks that
|
|
|
|
:py:attr:`Factory.provides` is subclass of
|
|
|
|
:py:attr:`Factory.provided_type`.
|
|
|
|
|
|
|
|
:type: type | None
|
|
|
|
|
|
|
|
.. py:attribute:: cls
|
|
|
|
|
|
|
|
Class that provides object.
|
|
|
|
Alias for :py:attr:`provides`.
|
|
|
|
|
|
|
|
:type: type
|
|
|
|
"""
|
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
__slots__ = ('_instance',)
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 15:07:48 +03:00
|
|
|
def __init__(self, provides, *args, **kwargs):
|
2016-04-03 17:27:53 +03:00
|
|
|
"""Initializer.
|
|
|
|
|
|
|
|
:param provides: Class or other callable that provides object
|
|
|
|
for creation.
|
|
|
|
:type provides: type | callable
|
|
|
|
"""
|
2016-05-18 01:17:15 +03:00
|
|
|
self._instance = None
|
2016-05-18 15:07:48 +03:00
|
|
|
super(Singleton, self).__init__(provides, *args, **kwargs)
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
"""Reset cached instance, if any.
|
|
|
|
|
|
|
|
:rtype: None
|
|
|
|
"""
|
2016-05-18 01:17:15 +03:00
|
|
|
self._instance = None
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
def _provide(self, *args, **kwargs):
|
|
|
|
"""Return provided instance.
|
|
|
|
|
|
|
|
:param args: Tuple of context positional arguments.
|
|
|
|
:type args: tuple[object]
|
|
|
|
|
|
|
|
:param kwargs: Dictionary of context keyword arguments.
|
|
|
|
:type kwargs: dict[str, object]
|
|
|
|
|
|
|
|
:rtype: object
|
|
|
|
"""
|
2016-05-18 01:17:15 +03:00
|
|
|
if self._instance:
|
|
|
|
return self._instance
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
with GLOBAL_LOCK:
|
2016-05-18 01:17:15 +03:00
|
|
|
self._instance = super(Singleton, self)._provide(*args, **kwargs)
|
2016-04-03 17:27:53 +03:00
|
|
|
|
2016-05-18 01:17:15 +03:00
|
|
|
return self._instance
|
2016-04-03 17:27:53 +03:00
|
|
|
|
|
|
|
|
|
|
|
class DelegatedSingleton(Singleton):
|
|
|
|
""":py:class:`DelegatedSingleton` is a delegated :py:class:`Singleton`.
|
|
|
|
|
|
|
|
:py:class:`DelegatedSingleton` is a :py:class:`Singleton`, that is injected
|
|
|
|
"as is".
|
|
|
|
|
|
|
|
.. py:attribute:: provided_type
|
|
|
|
|
|
|
|
If provided type is defined, :py:class:`Factory` checks that
|
|
|
|
:py:attr:`Factory.provides` is subclass of
|
|
|
|
:py:attr:`Factory.provided_type`.
|
|
|
|
|
|
|
|
:type: type | None
|
|
|
|
|
|
|
|
.. py:attribute:: cls
|
|
|
|
|
|
|
|
Class that provides object.
|
|
|
|
Alias for :py:attr:`provides`.
|
|
|
|
|
|
|
|
:type: type
|
|
|
|
"""
|
|
|
|
|
|
|
|
__IS_DELEGATED__ = True
|