python-dependency-injector/objects/providers.py

329 lines
9.2 KiB
Python
Raw Normal View History

"""Providers module."""
2015-01-04 17:26:33 +03:00
2015-03-23 17:27:48 +03:00
from six import class_types
2015-03-10 12:51:13 +03:00
from .utils import ensure_is_provider
from .utils import is_kwarg_injection
from .utils import is_attribute_injection
from .utils import is_method_injection
2015-01-10 12:24:25 +03:00
2015-03-13 18:31:07 +03:00
from .errors import Error
2015-01-04 17:26:33 +03:00
class Provider(object):
2015-03-09 01:01:39 +03:00
"""Base provider class."""
2015-01-04 17:26:33 +03:00
__IS_OBJECTS_PROVIDER__ = True
__slots__ = ('overridden',)
2015-01-11 19:10:11 +03:00
def __init__(self):
2015-03-09 01:01:39 +03:00
"""Initializer."""
self.overridden = None
2015-01-11 16:03:45 +03:00
2015-01-04 17:26:33 +03:00
def __call__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
2015-05-25 10:45:52 +03:00
if self.overridden:
return self.last_overriding(*args, **kwargs)
return self.__provide__(*args, **kwargs)
def __provide__(self, *args, **kwargs):
"""Providing strategy implementation.
Abstract protected method that implements providing strategy of
particular provider. Current method is called every time when not
overridden provider is called. Need to be overridden in subclasses.
"""
2015-01-04 17:26:33 +03:00
raise NotImplementedError()
2015-02-23 01:16:27 +03:00
def delegate(self):
"""Return provider's delegate."""
2015-03-14 01:02:01 +03:00
return Delegate(self)
2015-02-25 02:48:51 +03:00
def override(self, provider):
"""Override provider with another provider."""
if not self.overridden:
self.overridden = (ensure_is_provider(provider),)
else:
self.overridden = self.overridden + (ensure_is_provider(provider),)
2015-03-20 14:32:11 +03:00
def reset_override(self):
"""Reset all overriding providers."""
self.overridden = None
2015-03-20 14:32:11 +03:00
@property
def last_overriding(self):
"""Return last overriding provider."""
try:
return self.overridden[-1]
except (TypeError, IndexError):
raise Error('Provider {0} '.format(str(self)) +
2015-03-13 18:31:07 +03:00
'is not overridden')
2015-02-25 02:48:51 +03:00
2015-03-14 01:02:01 +03:00
class Delegate(Provider):
2015-03-09 01:01:39 +03:00
"""Provider's delegate."""
2015-02-25 02:48:51 +03:00
__slots__ = ('delegated',)
2015-02-25 02:48:51 +03:00
def __init__(self, delegated):
2015-03-09 01:01:39 +03:00
"""Initializer.
2015-02-25 02:48:51 +03:00
:type delegated: Provider
"""
self.delegated = ensure_is_provider(delegated)
2015-03-14 01:02:01 +03:00
super(Delegate, self).__init__()
2015-02-25 02:48:51 +03:00
2015-05-25 10:45:52 +03:00
def __provide__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
2015-03-09 01:24:46 +03:00
return self.delegated
2015-02-23 01:16:27 +03:00
2015-01-11 16:03:45 +03:00
class Factory(Provider):
2015-01-10 12:24:25 +03:00
"""Factory provider.
2015-01-04 17:26:33 +03:00
Factory provider creates new instance of specified class on every call.
2015-01-04 17:26:33 +03:00
"""
__slots__ = ('provides', 'kwargs', 'attributes', 'methods')
2015-01-10 12:24:25 +03:00
def __init__(self, provides, *injections):
2015-03-09 01:01:39 +03:00
"""Initializer."""
2015-03-23 17:27:48 +03:00
if not isinstance(provides, class_types):
raise Error('Factory provider expects to get class, ' +
'got {0} instead'.format(str(provides)))
2015-01-04 17:26:33 +03:00
self.provides = provides
self.kwargs = tuple((injection
for injection in injections
if is_kwarg_injection(injection)))
2015-03-11 16:27:38 +03:00
self.attributes = tuple((injection
for injection in injections
if is_attribute_injection(injection)))
self.methods = tuple((injection
for injection in injections
if is_method_injection(injection)))
super(Factory, self).__init__()
2015-01-04 17:26:33 +03:00
2015-05-25 10:45:52 +03:00
def __provide__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
init_kwargs = dict(((injection.name, injection.value)
for injection in self.kwargs))
init_kwargs.update(kwargs)
2015-01-04 17:26:33 +03:00
instance = self.provides(*args, **init_kwargs)
2015-01-10 12:24:25 +03:00
for attribute in self.attributes:
setattr(instance, attribute.name, attribute.value)
for method in self.methods:
getattr(instance, method.name)(method.value)
2015-01-04 17:26:33 +03:00
2015-03-09 01:01:39 +03:00
return instance
2015-01-04 17:26:33 +03:00
class NewInstance(Factory):
"""NewInstance provider.
It is synonym of Factory provider. NewInstance provider is considered to
be deprecated, but will be able to use for further backward
compatibility.
"""
class Singleton(Provider):
2015-03-09 01:01:39 +03:00
"""Singleton provider.
2015-01-04 17:26:33 +03:00
Singleton provider will create instance once and return it on every call.
"""
__slots__ = ('instance', 'factory')
2015-01-04 17:26:33 +03:00
def __init__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Initializer."""
2015-01-04 17:26:33 +03:00
self.instance = None
self.factory = Factory(*args, **kwargs)
super(Singleton, self).__init__()
2015-01-04 17:26:33 +03:00
2015-05-25 10:45:52 +03:00
def __provide__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
2015-01-04 17:26:33 +03:00
if not self.instance:
self.instance = self.factory(*args, **kwargs)
2015-01-04 17:26:33 +03:00
return self.instance
2015-03-15 01:50:24 +03:00
def reset(self):
2015-03-09 01:01:39 +03:00
"""Reset instance."""
2015-01-28 01:21:31 +03:00
self.instance = None
class ExternalDependency(Provider):
"""External dependency provider.
Those provider is used when dependency obviously have to be overridden by
the client's code, but it's interface is known.
"""
__slots__ = ('instance_of',)
2015-03-09 01:01:39 +03:00
def __init__(self, instance_of):
"""Initializer."""
2015-03-23 17:27:48 +03:00
if not isinstance(instance_of, class_types):
raise Error('ExternalDependency provider expects to get class, ' +
'got {0} instead'.format(str(instance_of)))
self.instance_of = instance_of
super(ExternalDependency, self).__init__()
def __call__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
if not self.overridden:
raise Error('Dependency is not defined')
instance = self.last_overriding(*args, **kwargs)
if not isinstance(instance, self.instance_of):
raise Error('{0} is not an '.format(instance) +
'instance of {0}'.format(self.instance_of))
return instance
def provided_by(self, provider):
"""Set external dependency provider."""
return self.override(provider)
2015-01-04 17:26:33 +03:00
class _StaticProvider(Provider):
2015-03-09 01:01:39 +03:00
"""Static provider.
2015-01-04 17:26:33 +03:00
Static provider is base implementation that provides exactly the same as
it got on input.
"""
__slots__ = ('provides',)
2015-01-04 17:26:33 +03:00
def __init__(self, provides):
2015-03-09 01:01:39 +03:00
"""Initializer."""
2015-01-04 17:26:33 +03:00
self.provides = provides
2015-01-11 19:10:11 +03:00
super(_StaticProvider, self).__init__()
2015-01-04 17:26:33 +03:00
2015-05-25 10:45:52 +03:00
def __provide__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
2015-01-04 17:26:33 +03:00
return self.provides
class Class(_StaticProvider):
2015-03-09 01:01:39 +03:00
"""Class provider provides class."""
2015-01-04 17:26:33 +03:00
class Object(_StaticProvider):
2015-03-09 01:01:39 +03:00
"""Object provider provides object."""
2015-01-04 17:26:33 +03:00
class Function(_StaticProvider):
2015-03-09 01:01:39 +03:00
"""Function provider provides function."""
2015-01-04 17:26:33 +03:00
class Value(_StaticProvider):
2015-03-09 01:01:39 +03:00
"""Value provider provides value."""
2015-01-28 01:48:33 +03:00
class Callable(Provider):
2015-03-09 01:01:39 +03:00
"""Callable provider.
Callable provider provides callable that is called on every provider call
with some predefined dependency injections.
2015-01-28 01:48:33 +03:00
"""
__slots__ = ('callback', 'injections')
def __init__(self, callback, *injections):
2015-03-09 01:01:39 +03:00
"""Initializer."""
if not callable(callback):
raise Error('Callable expected, got {0}'.format(str(callback)))
self.callback = callback
2015-03-11 16:27:38 +03:00
self.injections = tuple((injection
for injection in injections
if is_kwarg_injection(injection)))
2015-01-28 01:48:33 +03:00
super(Callable, self).__init__()
2015-05-25 10:45:52 +03:00
def __provide__(self, *args, **kwargs):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
injections = dict(((injection.name, injection.value)
for injection in self.injections))
2015-01-28 01:48:33 +03:00
injections.update(kwargs)
return self.callback(*args, **injections)
2015-01-28 14:08:54 +03:00
class Config(Provider):
2015-03-09 01:01:39 +03:00
"""Config provider.
2015-01-28 14:08:54 +03:00
Config provider provides dict values. Also config provider creates
child config objects for all undefined attribute calls. It makes possible
to create deferred config value provider.
2015-01-28 14:08:54 +03:00
"""
__slots__ = ('value',)
2015-01-28 14:08:54 +03:00
def __init__(self, value=None):
2015-03-09 01:01:39 +03:00
"""Initializer."""
2015-01-28 14:08:54 +03:00
if not value:
value = dict()
self.value = value
super(Config, self).__init__()
2015-05-25 10:45:52 +03:00
def __provide__(self, paths=None):
2015-03-09 01:01:39 +03:00
"""Return provided instance."""
2015-01-28 14:08:54 +03:00
value = self.value
if paths:
for path in paths:
try:
value = value[path]
except KeyError:
raise Error('Config key '
'"{0}" is undefined'.format('.'.join(paths)))
return value
2015-03-10 12:51:13 +03:00
2015-03-23 17:27:48 +03:00
def __getattr__(self, item):
"""Return instance of deferred config."""
return _ChildConfig(parents=(item,), root_config=self)
def update_from(self, value):
"""Update current value from another one."""
self.value.update(value)
2015-03-10 12:51:13 +03:00
class _ChildConfig(Provider):
2015-03-10 12:51:13 +03:00
"""Child config provider.
2015-03-10 12:51:13 +03:00
Child config provide an value from the root config object according to
the current path in the config tree.
2015-03-10 12:51:13 +03:00
"""
2015-03-16 12:41:42 +03:00
__slots__ = ('parents', 'root_config')
2015-03-16 12:41:42 +03:00
def __init__(self, parents, root_config):
2015-03-10 12:51:13 +03:00
"""Initializer."""
2015-03-16 12:41:42 +03:00
self.parents = parents
2015-03-10 12:51:13 +03:00
self.root_config = root_config
super(_ChildConfig, self).__init__()
2015-03-10 12:51:13 +03:00
2015-05-25 10:45:52 +03:00
def __provide__(self, *args, **kwargs):
2015-03-23 17:27:48 +03:00
"""Return provided instance."""
return self.root_config(self.parents)
2015-03-10 12:51:13 +03:00
def __getattr__(self, item):
"""Return instance of deferred config."""
return _ChildConfig(parents=self.parents + (item,),
root_config=self.root_config)