Merge pull request #154 from ets-labs/dev-3.4

Dev 3.4
This commit is contained in:
Roman 2017-04-07 01:08:50 +03:00 committed by GitHub
commit 48e0e5bedf
16 changed files with 5429 additions and 2509 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -11,6 +11,13 @@ Development version
------------------- -------------------
- No features. - No features.
3.4.0
-----
- Add ``AbstractCallable`` provider.
- Add ``AbstractFactory`` provider.
- Add ``AbstractSingleton`` provider.
- Optimize calling of overridden providers (~15% faster).
3.3.7 3.3.7
----- -----
- Fix minor bug related to patch of ``Configuration`` provider in version - Fix minor bug related to patch of ``Configuration`` provider in version

View File

@ -54,8 +54,18 @@ any kind of injection.
Delegation of :py:class:`Callable` providers is the same as Delegation of :py:class:`Callable` providers is the same as
:py:class:`Factory` providers delegation, please follow :py:class:`Factory` providers delegation, please follow
:ref:`factory_providers_delegation` section for examples (with exception :ref:`factory_providers_delegation` section for examples (with exception
about using :py:class:`DelegatedCallable` instead of of using :py:class:`DelegatedCallable` instead of
:py:class:`DelegatedFactory`). :py:class:`DelegatedFactory`).
Abstract callable providers
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`AbstractCallable` provider is a :py:class:`Callable` provider that
must be explicitly overridden before calling.
Behaviour of :py:class:`AbstractCallable` providers is the same as of
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
section for examples (with exception of using :py:class:`AbstractCallable`
provider instead of :py:class:`AbstractFactory`).
.. disqus:: .. disqus::

View File

@ -106,5 +106,45 @@ provided type:
:language: python :language: python
:linenos: :linenos:
.. _abstract_factory_providers:
Abstract factory providers
~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`AbstractFactory` provider is a :py:class:`Factory` provider that
must be explicitly overridden before calling.
.. note::
Overriding of :py:class:`AbstractFactory` provider is possible only by
another :py:class:`Factory` provider.
:py:class:`AbstractFactory` provider is useful when it is needed to specify
explicitly that it only provides abstraction, but not an implementation.
Client code must override such factories with factories that provide particular
implementations. Otherwise, :py:class:`AbstractFactory` will raise an error
on attempt of calling it. At the same time, :py:class:`AbstractFactory` is
regular provider that could be injected into other providers (or used for
any other kind of bindings) without being overridden. After
:py:class:`AbstractFactory` provider has been overridden, its behaviour is
identical to regular :py:class:`Factory` provider.
Example:
.. image:: /images/providers/abstract_factory.png
:width: 100%
:align: center
Listing of ``cache.py``:
.. literalinclude:: ../../examples/providers/abstract_factory/cache.py
:language: python
:linenos:
Listing of ``example.py``:
.. literalinclude:: ../../examples/providers/abstract_factory/example.py
:language: python
:linenos:
.. disqus:: .. disqus::

View File

@ -65,7 +65,7 @@ any kind of injection.
Delegation of :py:class:`Singleton` providers is the same as Delegation of :py:class:`Singleton` providers is the same as
:py:class:`Factory` providers delegation, please follow :py:class:`Factory` providers delegation, please follow
:ref:`factory_providers_delegation` section for examples (with exception :ref:`factory_providers_delegation` section for examples (with exception
about using :py:class:`DelegatedSingleton` instead of of using :py:class:`DelegatedSingleton` instead of
:py:class:`DelegatedFactory`). :py:class:`DelegatedFactory`).
Singleton providers specialization Singleton providers specialization
@ -78,6 +78,17 @@ Specialization of :py:class:`Singleton` providers is the same as
:py:class:`Factory` providers specialization, please follow :py:class:`Factory` providers specialization, please follow
:ref:`factory_providers_specialization` section for examples. :ref:`factory_providers_specialization` section for examples.
Abstract singleton providers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:py:class:`AbstractSingleton` provider is a :py:class:`Singleton` provider that
must be explicitly overridden before calling.
Behaviour of :py:class:`AbstractSingleton` providers is the same as of
:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers`
section for examples (with exception of using :py:class:`AbstractSingleton`
provider instead of :py:class:`AbstractFactory`).
Singleton providers and multi-threading Singleton providers and multi-threading
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,25 @@
"""Example hierarchy of cache clients with abstract base class."""
class AbstractCacheClient(object):
"""Abstract cache client."""
class RedisCacheClient(AbstractCacheClient):
"""Cache client implementation based on Redis."""
def __init__(self, host, port, db):
"""Initializer."""
self.host = host
self.port = port
self.db = db
class MemcacheCacheClient(AbstractCacheClient):
"""Cache client implementation based on Memcached."""
def __init__(self, hosts, port, prefix):
"""Initializer."""
self.hosts = hosts
self.port = port
self.prefix = prefix

View File

@ -0,0 +1,28 @@
"""`AbstractFactory` providers example."""
import cache
import dependency_injector.providers as providers
# Define abstract cache client factory:
cache_client_factory = providers.AbstractFactory(cache.AbstractCacheClient)
if __name__ == '__main__':
# Override abstract factory with redis client factory:
cache_client_factory.override(providers.Factory(cache.RedisCacheClient,
host='localhost',
port=6379,
db=0))
redis_cache = cache_client_factory()
print(redis_cache) # <cache.RedisCacheClient object at 0x10975bc50>
# Override abstract factory with memcache client factory:
cache_client_factory.override(providers.Factory(cache.MemcacheCacheClient,
hosts=['10.0.1.1',
'10.0.1.2',
'10.0.1.3'],
port=11211,
prefix='my_app'))
memcache_cache = cache_client_factory()
print(memcache_cache) # <cache.MemcacheCacheClient object at 0x10975bc90>

View File

@ -1,6 +1,6 @@
"""Dependency injector top-level package.""" """Dependency injector top-level package."""
__version__ = '3.3.7' __version__ = '3.4.0'
"""Version number that follows semantic versioning. """Version number that follows semantic versioning.
:type: str :type: str

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,9 @@ cimport cython
# Base providers # Base providers
cdef class Provider(object): cdef class Provider(object):
cdef tuple __overridden cdef tuple __overridden
cdef int __overridden_len cdef Provider __last_overriding
cpdef object _provide(self, tuple args, dict kwargs) cpdef object _provide(self, tuple args, dict kwargs)
cpdef object _call_last_overriding(self, tuple args, dict kwargs)
cdef class Object(Provider): cdef class Object(Provider):
@ -51,6 +50,10 @@ cdef class DelegatedCallable(Callable):
pass pass
cdef class AbstractCallable(Callable):
cpdef object _provide(self, tuple args, dict kwargs)
# Configuration providers # Configuration providers
cdef class Configuration(Provider): cdef class Configuration(Provider):
cdef str __name cdef str __name
@ -77,6 +80,10 @@ cdef class DelegatedFactory(Factory):
pass pass
cdef class AbstractFactory(Factory):
cpdef object _provide(self, tuple args, dict kwargs)
# Singleton providers # Singleton providers
cdef class BaseSingleton(Provider): cdef class BaseSingleton(Provider):
cdef Factory __instantiator cdef Factory __instantiator
@ -113,6 +120,10 @@ cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
pass pass
cdef class AbstractSingleton(BaseSingleton):
pass
# Injections # Injections
cdef class Injection(object): cdef class Injection(object):
cdef object __value cdef object __value

View File

@ -83,7 +83,7 @@ cdef class Provider(object):
def __init__(self): def __init__(self):
"""Initializer.""" """Initializer."""
self.__overridden = tuple() self.__overridden = tuple()
self.__overridden_len = 0 self.__last_overriding = None
super(Provider, self).__init__() super(Provider, self).__init__()
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
@ -91,8 +91,8 @@ cdef class Provider(object):
Callable interface implementation. Callable interface implementation.
""" """
if self.__overridden_len != 0: if self.__last_overriding is not None:
return self._call_last_overriding(args, kwargs) return self.__last_overriding._provide(args, kwargs)
return self._provide(args, kwargs) return self._provide(args, kwargs)
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
@ -146,12 +146,10 @@ cdef class Provider(object):
provider = Object(provider) provider = Object(provider)
self.__overridden += (provider,) self.__overridden += (provider,)
self.__overridden_len += 1 self.__last_overriding = provider
return OverridingContext(self, provider) return OverridingContext(self, provider)
@cython.boundscheck(False)
@cython.wraparound(False)
def reset_last_overriding(self): def reset_last_overriding(self):
"""Reset last overriding provider. """Reset last overriding provider.
@ -160,11 +158,14 @@ cdef class Provider(object):
:rtype: None :rtype: None
""" """
if self.__overridden_len == 0: if len(self.__overridden) == 0:
raise Error('Provider {0} is not overridden'.format(str(self))) raise Error('Provider {0} is not overridden'.format(str(self)))
self.__overridden = self.__overridden[:self.__overridden_len - 1] self.__overridden = self.__overridden[:-1]
self.__overridden_len -= 1 try:
self.__last_overriding = self.__overridden[-1]
except IndexError:
self.__last_overriding = None
def reset_override(self): def reset_override(self):
"""Reset all overriding providers. """Reset all overriding providers.
@ -172,7 +173,7 @@ cdef class Provider(object):
:rtype: None :rtype: None
""" """
self.__overridden = tuple() self.__overridden = tuple()
self.__overridden_len = 0 self.__last_overriding = None
def delegate(self): def delegate(self):
"""Return provider's delegate. """Return provider's delegate.
@ -190,13 +191,6 @@ cdef class Provider(object):
""" """
raise NotImplementedError() raise NotImplementedError()
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef object _call_last_overriding(self, tuple args, dict kwargs):
"""Call last overriding provider and return result."""
return <object>self.__overridden[self.__overridden_len - 1](*args,
**kwargs)
cdef class Object(Provider): cdef class Object(Provider):
"""Object provider returns provided instance "as is". """Object provider returns provided instance "as is".
@ -332,10 +326,10 @@ cdef class ExternalDependency(Provider):
""" """
cdef object instance cdef object instance
if self.__overridden_len == 0: if self.__last_overriding is None:
raise Error('Dependency is not defined') raise Error('Dependency is not defined')
instance = self._call_last_overriding(args, kwargs) instance = self.__last_overriding._provide(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) +
@ -599,6 +593,47 @@ cdef class DelegatedCallable(Callable):
__IS_DELEGATED__ = True __IS_DELEGATED__ = True
cdef class AbstractCallable(Callable):
"""Abstract callable provider.
:py:class:`AbstractCallable` is a :py:class:`Callable` provider that must
be explicitly overridden before calling.
Overriding of :py:class:`AbstractCallable` is possible only by another
:py:class:`Callable` provider.
"""
def __call__(self, *args, **kwargs):
"""Return provided object.
Callable interface implementation.
"""
if self.__last_overriding is None:
raise Error('{0} must be overridden before calling'.format(self))
return self.__last_overriding._provide(args, kwargs)
def override(self, provider):
"""Override provider with another provider.
:param provider: Overriding provider.
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
:return: Overriding context.
:rtype: :py:class:`OverridingContext`
"""
if not isinstance(provider, Callable):
raise Error('{0} must be overridden only by '
'{1} providers'.format(self, Callable))
return super(AbstractCallable, self).override(provider)
cpdef object _provide(self, tuple args, dict kwargs):
"""Return result of provided callable's call."""
raise NotImplementedError('Abstract provider forward providing logic '
'to overriding provider')
cdef class Configuration(Provider): cdef class Configuration(Provider):
"""Configuration provider. """Configuration provider.
@ -973,6 +1008,46 @@ cdef class DelegatedFactory(Factory):
__IS_DELEGATED__ = True __IS_DELEGATED__ = True
cdef class AbstractFactory(Factory):
"""Abstract factory provider.
:py:class:`AbstractFactory` is a :py:class:`Factory` provider that must
be explicitly overridden before calling.
Overriding of :py:class:`AbstractFactory` is possible only by another
:py:class:`Factory` provider.
"""
def __call__(self, *args, **kwargs):
"""Return provided object.
Callable interface implementation.
"""
if self.__last_overriding is None:
raise Error('{0} must be overridden before calling'.format(self))
return self.__last_overriding._provide(args, kwargs)
def override(self, provider):
"""Override provider with another provider.
:param provider: Overriding provider.
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
:return: Overriding context.
:rtype: :py:class:`OverridingContext`
"""
if not isinstance(provider, Factory):
raise Error('{0} must be overridden only by '
'{1} providers'.format(self, Factory))
return super(AbstractFactory, self).override(provider)
cpdef object _provide(self, tuple args, dict kwargs):
"""Return result of provided callable's call."""
raise NotImplementedError('Abstract provider forward providing logic '
'to overriding provider')
cdef class BaseSingleton(Provider): cdef class BaseSingleton(Provider):
"""Base class of singleton providers.""" """Base class of singleton providers."""
@ -1359,6 +1434,51 @@ cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
__IS_DELEGATED__ = True __IS_DELEGATED__ = True
cdef class AbstractSingleton(BaseSingleton):
"""Abstract singleton provider.
:py:class:`AbstractSingleton` is a :py:class:`Singleton` provider that must
be explicitly overridden before calling.
Overriding of :py:class:`AbstractSingleton` is possible only by another
:py:class:`BaseSingleton` provider.
"""
def __call__(self, *args, **kwargs):
"""Return provided object.
Callable interface implementation.
"""
if self.__last_overriding is None:
raise Error('{0} must be overridden before calling'.format(self))
return self.__last_overriding._provide(args, kwargs)
def override(self, provider):
"""Override provider with another provider.
:param provider: Overriding provider.
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
:return: Overriding context.
:rtype: :py:class:`OverridingContext`
"""
if not isinstance(provider, BaseSingleton):
raise Error('{0} must be overridden only by '
'{1} providers'.format(self, BaseSingleton))
return super(AbstractSingleton, self).override(provider)
def reset(self):
"""Reset cached instance, if any.
:rtype: None
"""
if self.__last_overriding is None:
raise Error('{0} must be overridden before calling'.format(self))
return self.__last_overriding.reset()
cdef class Injection(object): cdef class Injection(object):
"""Abstract injection class.""" """Abstract injection class."""

View File

@ -74,7 +74,7 @@ class Tester(object):
# for x in xrange(int(5000000 * self.duration_factor)): # for x in xrange(int(5000000 * self.duration_factor)):
# test_factory(1, 2, 3) # test_factory(1, 2, 3)
def test_instance_3_kw_injections(self, providers): def test_raw_3_kw_injections(self, providers):
"""Test 3 keyword argument injections.""" """Test 3 keyword argument injections."""
class A(object): class A(object):
pass pass
@ -92,7 +92,7 @@ class Tester(object):
for x in xrange(int(5000000 * self.duration_factor)): for x in xrange(int(5000000 * self.duration_factor)):
Test(a=A(), b=B(), c=C()) Test(a=A(), b=B(), c=C())
def test_instance_factory_3_factory_kw_injections(self, providers): def test_factory_3_factory_kw_injections(self, providers):
"""Test factory with 3 keyword argument injections via factories.""" """Test factory with 3 keyword argument injections via factories."""
class A(object): class A(object):
pass pass
@ -117,6 +117,32 @@ class Tester(object):
for x in xrange(int(5000000 * self.duration_factor)): for x in xrange(int(5000000 * self.duration_factor)):
test_factory() test_factory()
def test_abstract_factory_3_factory_kw_injections(self, providers):
"""Test factory with 3 keyword argument injections via factories."""
class A(object):
pass
class B(object):
pass
class C(object):
pass
class Test(object):
def __init__(self, a, b, c):
pass
a_factory = providers.Factory(A)
b_factory = providers.Factory(B)
c_factory = providers.Factory(C)
test_factory = providers.AbstractFactory(object)
test_factory.override(providers.Factory(Test,
a=a_factory,
b=b_factory,
c=c_factory))
for x in xrange(int(5000000 * self.duration_factor)):
test_factory()
# def test_factory_subcls_3_factory_subcls_kw_injections(self, providers): # def test_factory_subcls_3_factory_subcls_kw_injections(self, providers):
# """Test factory with 3 keyword argument injections via factories.""" # """Test factory with 3 keyword argument injections via factories."""
# class MyFactory(providers.Factory): # class MyFactory(providers.Factory):

View File

@ -8,13 +8,14 @@ from dependency_injector import (
) )
class CallableTests(unittest.TestCase): def _example(arg1, arg2, arg3, arg4):
def example(self, arg1, arg2, arg3, arg4):
return arg1, arg2, arg3, arg4 return arg1, arg2, arg3, arg4
class CallableTests(unittest.TestCase):
def test_init_with_callable(self): def test_init_with_callable(self):
self.assertTrue(providers.Callable(self.example)) self.assertTrue(providers.Callable(_example))
def test_init_with_not_callable(self): def test_init_with_not_callable(self):
self.assertRaises(errors.Error, providers.Callable, 123) self.assertRaises(errors.Error, providers.Callable, 123)
@ -24,66 +25,66 @@ class CallableTests(unittest.TestCase):
self.assertTrue(provider()) self.assertTrue(provider())
def test_call_with_positional_args(self): def test_call_with_positional_args(self):
provider = providers.Callable(self.example, provider = providers.Callable(_example,
1, 2, 3, 4) 1, 2, 3, 4)
self.assertTupleEqual(provider(), (1, 2, 3, 4)) self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_keyword_args(self): def test_call_with_keyword_args(self):
provider = providers.Callable(self.example, provider = providers.Callable(_example,
arg1=1, arg2=2, arg3=3, arg4=4) arg1=1, arg2=2, arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4)) self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args(self): def test_call_with_positional_and_keyword_args(self):
provider = providers.Callable(self.example, provider = providers.Callable(_example,
1, 2, 1, 2,
arg3=3, arg4=4) arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4)) self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_context_args(self): def test_call_with_context_args(self):
provider = providers.Callable(self.example, 1, 2) provider = providers.Callable(_example, 1, 2)
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4)) self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
def test_call_with_context_kwargs(self): def test_call_with_context_kwargs(self):
provider = providers.Callable(self.example, arg1=1) provider = providers.Callable(_example, arg1=1)
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4)) self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_with_context_args_and_kwargs(self): def test_call_with_context_args_and_kwargs(self):
provider = providers.Callable(self.example, 1) provider = providers.Callable(_example, 1)
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4)) self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_fluent_interface(self): def test_fluent_interface(self):
provider = providers.Singleton(self.example) \ provider = providers.Singleton(_example) \
.add_args(1, 2) \ .add_args(1, 2) \
.add_kwargs(arg3=3, arg4=4) .add_kwargs(arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4)) self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_set_args(self): def test_set_args(self):
provider = providers.Callable(self.example) \ provider = providers.Callable(_example) \
.add_args(1, 2) \ .add_args(1, 2) \
.set_args(3, 4) .set_args(3, 4)
self.assertEqual(provider.args, tuple([3, 4])) self.assertEqual(provider.args, tuple([3, 4]))
def test_set_kwargs(self): def test_set_kwargs(self):
provider = providers.Callable(self.example) \ provider = providers.Callable(_example) \
.add_kwargs(init_arg3=3, init_arg4=4) \ .add_kwargs(init_arg3=3, init_arg4=4) \
.set_kwargs(init_arg3=4, init_arg4=5) .set_kwargs(init_arg3=4, init_arg4=5)
self.assertEqual(provider.kwargs, dict(init_arg3=4, init_arg4=5)) self.assertEqual(provider.kwargs, dict(init_arg3=4, init_arg4=5))
def test_clear_args(self): def test_clear_args(self):
provider = providers.Callable(self.example) \ provider = providers.Callable(_example) \
.add_args(1, 2) \ .add_args(1, 2) \
.clear_args() .clear_args()
self.assertEqual(provider.args, tuple()) self.assertEqual(provider.args, tuple())
def test_clear_kwargs(self): def test_clear_kwargs(self):
provider = providers.Callable(self.example) \ provider = providers.Callable(_example) \
.add_kwargs(init_arg3=3, init_arg4=4) \ .add_kwargs(init_arg3=3, init_arg4=4) \
.clear_kwargs() .clear_kwargs()
self.assertEqual(provider.kwargs, dict()) self.assertEqual(provider.kwargs, dict())
def test_call_overridden(self): def test_call_overridden(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
provider.override(providers.Object((4, 3, 2, 1))) provider.override(providers.Object((4, 3, 2, 1)))
provider.override(providers.Object((1, 2, 3, 4))) provider.override(providers.Object((1, 2, 3, 4)))
@ -91,7 +92,7 @@ class CallableTests(unittest.TestCase):
self.assertTupleEqual(provider(), (1, 2, 3, 4)) self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_deepcopy(self): def test_deepcopy(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
provider_copy = providers.deepcopy(provider) provider_copy = providers.deepcopy(provider)
@ -100,8 +101,8 @@ class CallableTests(unittest.TestCase):
self.assertIsInstance(provider, providers.Callable) self.assertIsInstance(provider, providers.Callable)
def test_deepcopy_from_memo(self): def test_deepcopy_from_memo(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
provider_copy_memo = providers.Callable(self.example) provider_copy_memo = providers.Callable(_example)
provider_copy = providers.deepcopy( provider_copy = providers.deepcopy(
provider, memo={id(provider): provider_copy_memo}) provider, memo={id(provider): provider_copy_memo})
@ -109,7 +110,7 @@ class CallableTests(unittest.TestCase):
self.assertIs(provider_copy, provider_copy_memo) self.assertIs(provider_copy, provider_copy_memo)
def test_deepcopy_args(self): def test_deepcopy_args(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
dependent_provider1 = providers.Callable(list) dependent_provider1 = providers.Callable(list)
dependent_provider2 = providers.Callable(dict) dependent_provider2 = providers.Callable(dict)
@ -130,7 +131,7 @@ class CallableTests(unittest.TestCase):
self.assertIsNot(dependent_provider2, dependent_provider_copy2) self.assertIsNot(dependent_provider2, dependent_provider_copy2)
def test_deepcopy_kwargs(self): def test_deepcopy_kwargs(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
dependent_provider1 = providers.Callable(list) dependent_provider1 = providers.Callable(list)
dependent_provider2 = providers.Callable(dict) dependent_provider2 = providers.Callable(dict)
@ -151,7 +152,7 @@ class CallableTests(unittest.TestCase):
self.assertIsNot(dependent_provider2, dependent_provider_copy2) self.assertIsNot(dependent_provider2, dependent_provider_copy2)
def test_deepcopy_overridden(self): def test_deepcopy_overridden(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
object_provider = providers.Object(object()) object_provider = providers.Object(object())
provider.override(object_provider) provider.override(object_provider)
@ -167,34 +168,86 @@ class CallableTests(unittest.TestCase):
self.assertIsInstance(object_provider_copy, providers.Object) self.assertIsInstance(object_provider_copy, providers.Object)
def test_repr(self): def test_repr(self):
provider = providers.Callable(self.example) provider = providers.Callable(_example)
self.assertEqual(repr(provider), self.assertEqual(repr(provider),
'<dependency_injector.providers.' '<dependency_injector.providers.'
'Callable({0}) at {1}>'.format( 'Callable({0}) at {1}>'.format(
repr(self.example), repr(_example),
hex(id(provider)))) hex(id(provider))))
class DelegatedCallableTests(unittest.TestCase): class DelegatedCallableTests(unittest.TestCase):
def test_inheritance(self): def test_inheritance(self):
self.assertIsInstance(providers.DelegatedCallable(len), self.assertIsInstance(providers.DelegatedCallable(_example),
providers.Callable) providers.Callable)
def test_is_provider(self): def test_is_provider(self):
self.assertTrue( self.assertTrue(
providers.is_provider(providers.DelegatedCallable(len))) providers.is_provider(providers.DelegatedCallable(_example)))
def test_is_delegated_provider(self): def test_is_delegated_provider(self):
provider = providers.DelegatedCallable(len) provider = providers.DelegatedCallable(_example)
self.assertTrue(providers.is_delegated(provider)) self.assertTrue(providers.is_delegated(provider))
def test_repr(self): def test_repr(self):
provider = providers.DelegatedCallable(len) provider = providers.DelegatedCallable(_example)
self.assertEqual(repr(provider), self.assertEqual(repr(provider),
'<dependency_injector.providers.' '<dependency_injector.providers.'
'DelegatedCallable({0}) at {1}>'.format( 'DelegatedCallable({0}) at {1}>'.format(
repr(len), repr(_example),
hex(id(provider))))
class AbstractCallableTests(unittest.TestCase):
def test_inheritance(self):
self.assertIsInstance(providers.AbstractCallable(_example),
providers.Callable)
def test_call_overridden_by_callable(self):
def _abstract_example():
pass
provider = providers.AbstractCallable(_abstract_example)
provider.override(providers.Callable(_example))
self.assertTrue(provider(1, 2, 3, 4), (1, 2, 3, 4))
def test_call_overridden_by_delegated_callable(self):
def _abstract_example():
pass
provider = providers.AbstractCallable(_abstract_example)
provider.override(providers.DelegatedCallable(_example))
self.assertTrue(provider(1, 2, 3, 4), (1, 2, 3, 4))
def test_call_not_overridden(self):
provider = providers.AbstractCallable(_example)
with self.assertRaises(errors.Error):
provider(1, 2, 3, 4)
def test_override_by_not_callable(self):
provider = providers.AbstractCallable(_example)
with self.assertRaises(errors.Error):
provider.override(providers.Factory(object))
def test_provide_not_implemented(self):
provider = providers.AbstractCallable(_example)
with self.assertRaises(NotImplementedError):
provider._provide((1, 2, 3, 4), dict())
def test_repr(self):
provider = providers.AbstractCallable(_example)
self.assertEqual(repr(provider),
'<dependency_injector.providers.'
'AbstractCallable({0}) at {1}>'.format(
repr(_example),
hex(id(provider)))) hex(id(provider))))

View File

@ -353,3 +353,49 @@ class DelegatedFactoryTests(unittest.TestCase):
'DelegatedFactory({0}) at {1}>'.format( 'DelegatedFactory({0}) at {1}>'.format(
repr(Example), repr(Example),
hex(id(provider)))) hex(id(provider))))
class AbstractFactoryTests(unittest.TestCase):
def test_inheritance(self):
self.assertIsInstance(providers.AbstractFactory(Example),
providers.Factory)
def test_call_overridden_by_factory(self):
provider = providers.AbstractFactory(object)
provider.override(providers.Factory(Example))
self.assertIsInstance(provider(), Example)
def test_call_overridden_by_delegated_factory(self):
provider = providers.AbstractFactory(object)
provider.override(providers.DelegatedFactory(Example))
self.assertIsInstance(provider(), Example)
def test_call_not_overridden(self):
provider = providers.AbstractFactory(object)
with self.assertRaises(errors.Error):
provider()
def test_override_by_not_factory(self):
provider = providers.AbstractFactory(object)
with self.assertRaises(errors.Error):
provider.override(providers.Callable(object))
def test_provide_not_implemented(self):
provider = providers.AbstractFactory(Example)
with self.assertRaises(NotImplementedError):
provider._provide(tuple(), dict())
def test_repr(self):
provider = providers.AbstractFactory(Example)
self.assertEqual(repr(provider),
'<dependency_injector.providers.'
'AbstractFactory({0}) at {1}>'.format(
repr(Example),
hex(id(provider))))

View File

@ -432,3 +432,63 @@ class DelegatedThreadSafeSingletonTests(_BaseSingletonTestCase,
'DelegatedThreadSafeSingleton({0}) at {1}>'.format( 'DelegatedThreadSafeSingleton({0}) at {1}>'.format(
repr(Example), repr(Example),
hex(id(provider)))) hex(id(provider))))
class AbstractSingletonTests(unittest.TestCase):
def test_inheritance(self):
self.assertIsInstance(providers.AbstractSingleton(Example),
providers.BaseSingleton)
def test_call_overridden_by_singleton(self):
provider = providers.AbstractSingleton(object)
provider.override(providers.Singleton(Example))
self.assertIsInstance(provider(), Example)
def test_call_overridden_by_delegated_singleton(self):
provider = providers.AbstractSingleton(object)
provider.override(providers.DelegatedSingleton(Example))
self.assertIsInstance(provider(), Example)
def test_call_not_overridden(self):
provider = providers.AbstractSingleton(object)
with self.assertRaises(errors.Error):
provider()
def test_reset_overridden(self):
provider = providers.AbstractSingleton(object)
provider.override(providers.Singleton(Example))
instance1 = provider()
provider.reset()
instance2 = provider()
self.assertIsNot(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_reset_not_overridden(self):
provider = providers.AbstractSingleton(object)
with self.assertRaises(errors.Error):
provider.reset()
def test_override_by_not_singleton(self):
provider = providers.AbstractSingleton(object)
with self.assertRaises(errors.Error):
provider.override(providers.Factory(object))
def test_repr(self):
provider = providers.AbstractSingleton(Example)
self.assertEqual(repr(provider),
'<dependency_injector.providers.'
'AbstractSingleton({0}) at {1}>'.format(
repr(Example),
hex(id(provider))))