0.9.5 release

This commit is contained in:
Roman Mogilatov 2015-09-14 10:53:24 +03:00
parent 1bfa0be26b
commit 6cbd0ce7fc
7 changed files with 107 additions and 90 deletions

View File

@ -1 +1 @@
0.9.4 0.9.5

View File

@ -8,6 +8,7 @@ from .providers import Delegate
from .providers import Factory from .providers import Factory
from .providers import Singleton from .providers import Singleton
from .providers import ExternalDependency from .providers import ExternalDependency
from .providers import StaticProvider
from .providers import Class from .providers import Class
from .providers import Object from .providers import Object
from .providers import Function from .providers import Function
@ -43,6 +44,7 @@ __all__ = (
'Factory', 'Factory',
'Singleton', 'Singleton',
'ExternalDependency', 'ExternalDependency',
'StaticProvider',
'Class', 'Class',
'Object', 'Object',
'Function', 'Function',

View File

@ -32,19 +32,19 @@ class AbstractCatalog(object):
providers = dict() providers = dict()
__slots__ = ('_used_providers',) __slots__ = ('used_providers',)
def __init__(self, *used_providers): def __init__(self, *used_providers):
"""Initializer.""" """Initializer."""
self._used_providers = set(used_providers) self.used_providers = set(used_providers)
def __getattribute__(self, item): def __getattribute__(self, item):
"""Return providers.""" """Return providers."""
attribute = super(AbstractCatalog, self).__getattribute__(item) attribute = super(AbstractCatalog, self).__getattribute__(item)
if item in ('providers', '_used_providers',): if item in ('providers', 'used_providers',):
return attribute return attribute
if attribute not in self._used_providers: if attribute not in self.used_providers:
raise Error('Provider \'{0}\' '.format(item) + raise Error('Provider \'{0}\' '.format(item) +
'is not listed in dependencies') 'is not listed in dependencies')
return attribute return attribute

View File

@ -62,8 +62,8 @@ def inject(*args, **kwargs):
def decorator(callback): def decorator(callback):
"""Dependency injection decorator.""" """Dependency injection decorator."""
if hasattr(callback, '_injections'): if hasattr(callback, 'injections'):
callback._injections += injections callback.injections += injections
return callback return callback
@six.wraps(callback) @six.wraps(callback)
@ -71,9 +71,9 @@ def inject(*args, **kwargs):
"""Decorated with dependency injection callback.""" """Decorated with dependency injection callback."""
return callback(*args, return callback(*args,
**get_injectable_kwargs(kwargs, **get_injectable_kwargs(kwargs,
decorated._injections)) decorated.injections))
decorated._injections = injections decorated.injections = injections
return decorated return decorated
return decorator return decorator

View File

@ -19,15 +19,15 @@ class Provider(object):
"""Base provider class.""" """Base provider class."""
__IS_PROVIDER__ = True __IS_PROVIDER__ = True
__slots__ = ('_overridden',) __slots__ = ('overridden_by',)
def __init__(self): def __init__(self):
"""Initializer.""" """Initializer."""
self._overridden = None self.overridden_by = None
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
if self._overridden: if self.overridden_by:
return self.last_overriding(*args, **kwargs) return self.last_overriding(*args, **kwargs)
return self._provide(*args, **kwargs) return self._provide(*args, **kwargs)
@ -46,52 +46,52 @@ class Provider(object):
def override(self, provider): def override(self, provider):
"""Override provider with another provider.""" """Override provider with another provider."""
if not self._overridden: if not self.is_overridden:
self._overridden = (ensure_is_provider(provider),) self.overridden_by = (ensure_is_provider(provider),)
else: else:
self._overridden += (ensure_is_provider(provider),) self.overridden_by += (ensure_is_provider(provider),)
@property @property
def is_overridden(self): def is_overridden(self):
"""Check if provider is overridden by another provider.""" """Check if provider is overridden by another provider."""
return bool(self._overridden) return bool(self.overridden_by)
@property @property
def last_overriding(self): def last_overriding(self):
"""Return last overriding provider.""" """Return last overriding provider."""
try: try:
return self._overridden[-1] return self.overridden_by[-1]
except (TypeError, IndexError): except (TypeError, IndexError):
raise Error('Provider {0} is not overridden'.format(str(self))) raise Error('Provider {0} is not overridden'.format(str(self)))
def reset_last_overriding(self): def reset_last_overriding(self):
"""Reset last overriding provider.""" """Reset last overriding provider."""
if not self._overridden: if not self.is_overridden:
raise Error('Provider {0} is not overridden'.format(str(self))) raise Error('Provider {0} is not overridden'.format(str(self)))
self._overridden = self._overridden[:-1] self.overridden_by = self.overridden_by[:-1]
def reset_override(self): def reset_override(self):
"""Reset all overriding providers.""" """Reset all overriding providers."""
self._overridden = None self.overridden_by = None
class Delegate(Provider): class Delegate(Provider):
"""Provider's delegate.""" """Provider's delegate."""
__slots__ = ('_delegated',) __slots__ = ('delegated',)
def __init__(self, delegated): def __init__(self, delegated):
"""Initializer. """Initializer.
:type delegated: Provider :type delegated: Provider
""" """
self._delegated = ensure_is_provider(delegated) self.delegated = ensure_is_provider(delegated)
super(Delegate, self).__init__() super(Delegate, self).__init__()
def _provide(self, *args, **kwargs): def _provide(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
return self._delegated return self.delegated
class Factory(Provider): class Factory(Provider):
@ -101,49 +101,44 @@ class Factory(Provider):
Factory provider creates new instance of specified class on every call. Factory provider creates new instance of specified class on every call.
""" """
__slots__ = ('_provides', '_kwargs', '_attributes', '_methods') __slots__ = ('provides', 'kwargs', 'attributes', 'methods')
def __init__(self, provides, *injections, **kwargs): def __init__(self, provides, *injections, **kwargs):
"""Initializer.""" """Initializer."""
if not callable(provides): if not callable(provides):
raise Error('Factory provider expects to get callable, ' + raise Error('Factory provider expects to get callable, ' +
'got {0} instead'.format(str(provides))) 'got {0} instead'.format(str(provides)))
self._provides = provides self.provides = provides
self._kwargs = tuple(injection self.kwargs = tuple(injection
for injection in injections for injection in injections
if is_kwarg_injection(injection)) if is_kwarg_injection(injection))
if kwargs: if kwargs:
self._kwargs += tuple(KwArg(name, value) self.kwargs += tuple(KwArg(name, value)
for name, value in six.iteritems(kwargs)) for name, value in six.iteritems(kwargs))
self._attributes = tuple(injection self.attributes = tuple(injection
for injection in injections for injection in injections
if is_attribute_injection(injection)) if is_attribute_injection(injection))
self._methods = tuple(injection self.methods = tuple(injection
for injection in injections for injection in injections
if is_method_injection(injection)) if is_method_injection(injection))
super(Factory, self).__init__() super(Factory, self).__init__()
def _provide(self, *args, **kwargs): def _provide(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
instance = self._provides(*args, instance = self.provides(*args,
**get_injectable_kwargs(kwargs, **get_injectable_kwargs(kwargs,
self._kwargs)) self.kwargs))
for attribute in self._attributes: for attribute in self.attributes:
setattr(instance, attribute.name, attribute.value) setattr(instance, attribute.name, attribute.value)
for method in self._methods: for method in self.methods:
getattr(instance, method.name)(method.value) getattr(instance, method.name)(method.value)
return instance return instance
@property
class NewInstance(Factory): def injections(self):
"""Return tuple of all injections."""
"""NewInstance provider. return self.kwargs + self.attributes + self.methods
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): class Singleton(Provider):
@ -153,24 +148,24 @@ class Singleton(Provider):
Singleton provider will create instance once and return it on every call. Singleton provider will create instance once and return it on every call.
""" """
__slots__ = ('_instance', '_factory') __slots__ = ('instance', 'factory')
def __init__(self, provides, *injections, **kwargs): def __init__(self, provides, *injections, **kwargs):
"""Initializer.""" """Initializer."""
self._instance = None self.instance = None
self._factory = Factory(provides, *injections, **kwargs) self.factory = Factory(provides, *injections, **kwargs)
super(Singleton, self).__init__() super(Singleton, self).__init__()
def _provide(self, *args, **kwargs): def _provide(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
with GLOBAL_LOCK: with GLOBAL_LOCK:
if not self._instance: if not self.instance:
self._instance = self._factory(*args, **kwargs) self.instance = self.factory(*args, **kwargs)
return self._instance return self.instance
def reset(self): def reset(self):
"""Reset instance.""" """Reset instance."""
self._instance = None self.instance = None
class ExternalDependency(Provider): class ExternalDependency(Provider):
@ -181,26 +176,26 @@ class ExternalDependency(Provider):
the client's code, but it's interface is known. the client's code, but it's interface is known.
""" """
__slots__ = ('_instance_of',) __slots__ = ('instance_of',)
def __init__(self, instance_of): def __init__(self, instance_of):
"""Initializer.""" """Initializer."""
if not isinstance(instance_of, six.class_types): if not isinstance(instance_of, six.class_types):
raise Error('ExternalDependency provider expects to get class, ' + raise Error('ExternalDependency provider expects to get class, ' +
'got {0} instead'.format(str(instance_of))) 'got {0} instead'.format(str(instance_of)))
self._instance_of = instance_of self.instance_of = instance_of
super(ExternalDependency, self).__init__() super(ExternalDependency, self).__init__()
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
if not self._overridden: if not self.is_overridden:
raise Error('Dependency is not defined') raise Error('Dependency is not defined')
instance = self.last_overriding(*args, **kwargs) instance = self.last_overriding(*args, **kwargs)
if not isinstance(instance, self._instance_of): if not isinstance(instance, self.instance_of):
raise Error('{0} is not an '.format(instance) + raise Error('{0} is not an '.format(instance) +
'instance of {0}'.format(self._instance_of)) 'instance of {0}'.format(self.instance_of))
return instance return instance
@ -209,7 +204,7 @@ class ExternalDependency(Provider):
return self.override(provider) return self.override(provider)
class _StaticProvider(Provider): class StaticProvider(Provider):
"""Static provider. """Static provider.
@ -217,34 +212,34 @@ class _StaticProvider(Provider):
it got on input. it got on input.
""" """
__slots__ = ('_provides',) __slots__ = ('provides',)
def __init__(self, provides): def __init__(self, provides):
"""Initializer.""" """Initializer."""
self._provides = provides self.provides = provides
super(_StaticProvider, self).__init__() super(StaticProvider, self).__init__()
def _provide(self, *args, **kwargs): def _provide(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
return self._provides return self.provides
class Class(_StaticProvider): class Class(StaticProvider):
"""Class provider provides class.""" """Class provider provides class."""
class Object(_StaticProvider): class Object(StaticProvider):
"""Object provider provides object.""" """Object provider provides object."""
class Function(_StaticProvider): class Function(StaticProvider):
"""Function provider provides function.""" """Function provider provides function."""
class Value(_StaticProvider): class Value(StaticProvider):
"""Value provider provides value.""" """Value provider provides value."""
@ -257,21 +252,21 @@ class Callable(Provider):
with some predefined dependency injections. with some predefined dependency injections.
""" """
__slots__ = ('_callback', '_kwargs') __slots__ = ('callback', 'kwargs')
def __init__(self, callback, **kwargs): def __init__(self, callback, **kwargs):
"""Initializer.""" """Initializer."""
if not callable(callback): if not callable(callback):
raise Error('Callable expected, got {0}'.format(str(callback))) raise Error('Callable expected, got {0}'.format(str(callback)))
self._callback = callback self.callback = callback
self._kwargs = tuple(KwArg(name, value) self.kwargs = tuple(KwArg(name, value)
for name, value in six.iteritems(kwargs)) for name, value in six.iteritems(kwargs))
super(Callable, self).__init__() super(Callable, self).__init__()
def _provide(self, *args, **kwargs): def _provide(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
return self._callback(*args, **get_injectable_kwargs(kwargs, return self.callback(*args, **get_injectable_kwargs(kwargs,
self._kwargs)) self.kwargs))
class Config(Provider): class Config(Provider):
@ -283,22 +278,22 @@ class Config(Provider):
to create deferred config value provider. to create deferred config value provider.
""" """
__slots__ = ('_value',) __slots__ = ('value',)
def __init__(self, value=None): def __init__(self, value=None):
"""Initializer.""" """Initializer."""
if not value: if not value:
value = dict() value = dict()
self._value = value self.value = value
super(Config, self).__init__() super(Config, self).__init__()
def __getattr__(self, item): def __getattr__(self, item):
"""Return instance of deferred config.""" """Return instance of deferred config."""
return _ChildConfig(parents=(item,), root_config=self) return ChildConfig(parents=(item,), root_config=self)
def _provide(self, paths=None): def _provide(self, paths=None):
"""Return provided instance.""" """Return provided instance."""
value = self._value value = self.value
if paths: if paths:
for path in paths: for path in paths:
try: try:
@ -310,10 +305,10 @@ class Config(Provider):
def update_from(self, value): def update_from(self, value):
"""Update current value from another one.""" """Update current value from another one."""
self._value.update(value) self.value.update(value)
class _ChildConfig(Provider): class ChildConfig(Provider):
"""Child config provider. """Child config provider.
@ -321,19 +316,19 @@ class _ChildConfig(Provider):
the current path in the config tree. the current path in the config tree.
""" """
__slots__ = ('_parents', '_root_config') __slots__ = ('parents', 'root_config')
def __init__(self, parents, root_config): def __init__(self, parents, root_config):
"""Initializer.""" """Initializer."""
self._parents = parents self.parents = parents
self._root_config = root_config self.root_config = root_config
super(_ChildConfig, self).__init__() super(ChildConfig, self).__init__()
def __getattr__(self, item): def __getattr__(self, item):
"""Return instance of deferred config.""" """Return instance of deferred config."""
return _ChildConfig(parents=self._parents + (item,), return ChildConfig(parents=self.parents + (item,),
root_config=self._root_config) root_config=self.root_config)
def _provide(self, *args, **kwargs): def _provide(self, *args, **kwargs):
"""Return provided instance.""" """Return provided instance."""
return self._root_config(self._parents) return self.root_config(self.parents)

View File

@ -13,6 +13,12 @@ Development version
- No featues. - No featues.
0.9.5
-----
- Change provider attributes scope to public.
- Add ``di.Factory.injections`` attribute that represents a tuple of all
``di.Factory`` injections (including kwargs, attributes and methods).
0.9.4 0.9.4
----- -----
- Add minor documentation fixes. - Add minor documentation fixes.

View File

@ -301,6 +301,20 @@ class FactoryTests(unittest.TestCase):
self.assertIsInstance(instance1, list) self.assertIsInstance(instance1, list)
self.assertIsInstance(instance2, list) self.assertIsInstance(instance2, list)
def test_injections(self):
"""Test getting a full list of injections using Factory.injections."""
provider = di.Factory(self.Example,
di.KwArg('init_arg1', 1),
di.KwArg('init_arg2', 2),
di.Attribute('attribute1', 3),
di.Attribute('attribute2', 4),
di.Method('method1', 5),
di.Method('method2', 6))
injections = provider.injections
self.assertEquals(len(injections), 6)
class SingletonTests(unittest.TestCase): class SingletonTests(unittest.TestCase):