Add DelegatedCallable, DelegatedFactory & DelegatedSingleton providers

This commit is contained in:
Roman Mogilatov 2015-12-28 17:25:25 +02:00
parent 0d00e2b0f5
commit 319128260a
13 changed files with 476 additions and 133 deletions

View File

@ -8,15 +8,18 @@ from .catalogs import override
from .providers import Provider from .providers import Provider
from .providers import Delegate from .providers import Delegate
from .providers import Callable
from .providers import DelegatedCallable
from .providers import Factory from .providers import Factory
from .providers import DelegatedFactory
from .providers import Singleton from .providers import Singleton
from .providers import DelegatedSingleton
from .providers import ExternalDependency from .providers import ExternalDependency
from .providers import StaticProvider 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
from .providers import Value from .providers import Value
from .providers import Callable
from .providers import Config from .providers import Config
from .injections import Injection from .injections import Injection
@ -28,6 +31,7 @@ from .injections import inject
from .utils import is_provider from .utils import is_provider
from .utils import ensure_is_provider from .utils import ensure_is_provider
from .utils import is_delegated_provider
from .utils import is_injection from .utils import is_injection
from .utils import ensure_is_injection from .utils import ensure_is_injection
from .utils import is_arg_injection from .utils import is_arg_injection
@ -65,15 +69,18 @@ __all__ = (
# Providers # Providers
'Provider', 'Provider',
'Delegate', 'Delegate',
'Callable',
'DelegatedCallable',
'Factory', 'Factory',
'DelegatedFactory',
'Singleton', 'Singleton',
'DelegatedSingleton',
'ExternalDependency', 'ExternalDependency',
'StaticProvider', 'StaticProvider',
'Class', 'Class',
'Object', 'Object',
'Function', 'Function',
'Value', 'Value',
'Callable',
'Config', 'Config',
# Injections # Injections
@ -87,6 +94,7 @@ __all__ = (
# Utils # Utils
'is_provider', 'is_provider',
'ensure_is_provider', 'ensure_is_provider',
'is_delegated_provider',
'is_injection', 'is_injection',
'ensure_is_injection', 'ensure_is_injection',
'is_arg_injection', 'is_arg_injection',

View File

@ -6,6 +6,7 @@ import itertools
import six import six
from .utils import is_provider from .utils import is_provider
from .utils import is_delegated_provider
from .utils import is_injection from .utils import is_injection
from .utils import is_arg_injection from .utils import is_arg_injection
from .utils import is_kwarg_injection from .utils import is_kwarg_injection
@ -32,15 +33,17 @@ class Injection(object):
:type: object | :py:class:`dependency_injector.providers.Provider` :type: object | :py:class:`dependency_injector.providers.Provider`
.. py:attribute:: injectable_is_provider .. py:attribute:: call_injectable
Flag that is set to ``True`` if injectable value is provider. Flag that is set to ``True`` if it is needed to call injectable.
Injectable needs to be called if it is not delegated provider.
:type: bool :type: bool
""" """
__IS_INJECTION__ = True __IS_INJECTION__ = True
__slots__ = ('injectable', 'injectable_is_provider') __slots__ = ('injectable', 'call_injectable')
def __init__(self, injectable): def __init__(self, injectable):
"""Initializer. """Initializer.
@ -51,20 +54,21 @@ class Injection(object):
:py:class:`dependency_injector.providers.Provider` :py:class:`dependency_injector.providers.Provider`
""" """
self.injectable = injectable self.injectable = injectable
self.injectable_is_provider = is_provider(injectable) self.call_injectable = (is_provider(injectable) and
not is_delegated_provider(injectable))
super(Injection, self).__init__() super(Injection, self).__init__()
@property @property
def value(self): def value(self):
"""Read-only property that represents injectable value. """Read-only property that represents injectable value.
Injectable values are provided "as is", except of providers Injectable values and delegated providers are provided "as is".
(subclasses of :py:class:`dependency_injector.providers.Provider`). Other providers will be called every time, when injection needs to
Providers will be called every time, when injection needs to be done. be done.
:rtype: object :rtype: object
""" """
if self.injectable_is_provider: if self.call_injectable:
return self.injectable() return self.injectable()
return self.injectable return self.injectable

View File

@ -319,6 +319,34 @@ class Callable(Provider):
__repr__ = __str__ __repr__ = __str__
class DelegatedCallable(Callable):
""":py:class:`DelegatedCallable` is a delegated :py:class:`Callable`.
:py:class:`DelegatedCallable` is a :py:class:`Callable`, that is injected
"as is".
.. py:attribute:: provides
Provided callable.
:type: callable
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
"""
__IS_DELEGATED__ = True
class Factory(Callable): class Factory(Callable):
""":py:class:`Factory` provider creates new instance on every call. """:py:class:`Factory` provider creates new instance on every call.
@ -448,6 +476,54 @@ class Factory(Callable):
return instance 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:: provides
Class or other callable that provides object.
:type: type | callable
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
.. py:attribute:: attributes
Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
.. py:attribute:: methods
Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
__IS_DELEGATED__ = True
class Singleton(Factory): class Singleton(Factory):
""":py:class:`Singleton` provider returns same instance on every call. """:py:class:`Singleton` provider returns same instance on every call.
@ -556,6 +632,60 @@ class Singleton(Factory):
return self.instance return self.instance
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:: instance
Read-only reference to singleton's instance.
:type: object
.. py:attribute:: provides
Class or other callable that provides object.
:type: type | callable
.. py:attribute:: args
Tuple of positional argument injections.
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
.. py:attribute:: kwargs
Tuple of keyword argument injections.
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
.. py:attribute:: attributes
Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
.. py:attribute:: methods
Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
__IS_DELEGATED__ = True
@six.python_2_unicode_compatible @six.python_2_unicode_compatible
class ExternalDependency(Provider): class ExternalDependency(Provider):
""":py:class:`ExternalDependency` provider describes dependency interface. """:py:class:`ExternalDependency` provider describes dependency interface.

View File

@ -44,6 +44,19 @@ def ensure_is_provider(instance):
return instance return instance
def is_delegated_provider(instance):
"""Check if instance is delegated provider instance.
:param instance: Instance to be checked.
:type instance: object
:rtype: bool
"""
return (is_provider(instance) and
hasattr(instance, '__IS_DELEGATED__') and
getattr(instance, '__IS_DELEGATED__') is True)
def is_injection(instance): def is_injection(instance):
"""Check if instance is injection instance. """Check if instance is injection instance.

View File

@ -9,7 +9,9 @@ follows `Semantic versioning`_
Development version Development version
------------------- -------------------
- No features. - Add ``DelegatedCallable`` provider.
- Add ``DelegatedFactory`` provider.
- Add ``DelegatedSingleton`` provider.
1.12.0 1.12.0
------ ------

View File

@ -16,12 +16,17 @@ arguments that are used as decorated callable injections. Every time, when
would be passed as an callable arguments. would be passed as an callable arguments.
Such behaviour is very similar to the standard Python ``functools.partial`` Such behaviour is very similar to the standard Python ``functools.partial``
object, except of one thing: all injectable values are provided object with several more things:
*"as is"*, except of providers (subclasses of :py:class:`Provider`). Providers
will be called every time, when injection needs to be done. For example, + All providers (instances of :py:class:`Provider`) are called every time
if injectable value of injection is a :py:class:`Factory`, it will provide when injection needs to be done.
new one instance (as a result of its call) every time, when injection needs + Providers could be injected "as is" (delegated), if it is defined obviously.
to be done. Check out `Callable providers delegation`_.
+ All other injectable values are provided *"as is"*
For example, if injectable value of injection is a :py:class:`Factory`, it
will provide new one instance (as a result of its call) every time, when
injection needs to be done.
:py:class:`Callable` behaviour with context positional and keyword arguments :py:class:`Callable` behaviour with context positional and keyword arguments
is very like a standard Python ``functools.partial``: is very like a standard Python ``functools.partial``:
@ -47,6 +52,8 @@ injections:
.. literalinclude:: ../../examples/providers/callable_kwargs.py .. literalinclude:: ../../examples/providers/callable_kwargs.py
:language: python :language: python
.. _callable_delegation:
Callable providers delegation Callable providers delegation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -62,3 +69,12 @@ Example:
.. literalinclude:: ../../examples/providers/callable_delegation.py .. literalinclude:: ../../examples/providers/callable_delegation.py
:language: python :language: python
Alternative way of doing :py:class:`Callable` delegation is an usage of
:py:class:`DelegatedCallable`. :py:class:`DelegatedCallable` is a
:py:class:`Callable` that is always injected "as is".
Example:
.. literalinclude:: ../../examples/providers/delegated_callable.py
:language: python

View File

@ -24,12 +24,17 @@ that are used as ``__init__()`` injections. Every time, when
argument injections would be passed as an instance's arguments. argument injections would be passed as an instance's arguments.
Such behaviour is very similar to the standard Python ``functools.partial`` Such behaviour is very similar to the standard Python ``functools.partial``
object, except of one thing: all injectable values are provided object with several more things:
*"as is"*, except of providers (subclasses of :py:class:`Provider`). Providers
will be called every time, when injection needs to be done. For example, + All providers (instances of :py:class:`Provider`) are called every time
if injectable value of injection is a :py:class:`Factory`, it will provide when injection needs to be done.
new one instance (as a result of its call) every time, when injection needs + Providers could be injected "as is" (delegated), if it is defined obviously.
to be done. Check out `Factory providers delegation`_.
+ All other injectable values are provided *"as is"*
For example, if injectable value of injection is a :py:class:`Factory`, it
will provide new one instance (as a result of its call) every time, when
injection needs to be done.
Example below is a little bit more complicated. It shows how to create Example below is a little bit more complicated. It shows how to create
:py:class:`Factory` of particular class with ``__init__()`` argument :py:class:`Factory` of particular class with ``__init__()`` argument
@ -175,6 +180,15 @@ Example:
.. literalinclude:: ../../examples/providers/factory_delegation.py .. literalinclude:: ../../examples/providers/factory_delegation.py
:language: python :language: python
Alternative way of doing :py:class:`Factory` delegation is an usage of
:py:class:`DelegatedFactory`. :py:class:`DelegatedFactory` is a
:py:class:`Factory` that is always injected "as is".
Example:
.. literalinclude:: ../../examples/providers/delegated_factory.py
:language: python
Factory providers specialization Factory providers specialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -24,8 +24,8 @@ Providers module API docs - :py:mod:`dependency_injector.providers`
factory factory
singleton singleton
static
callable callable
external_dependency external_dependency
static
overriding overriding
custom custom

View File

@ -36,9 +36,10 @@ provider.
during the first call). Be aware that such behaviour was made with opened during the first call). Be aware that such behaviour was made with opened
eyes and is not a bug. eyes and is not a bug.
By the way, in such case, :py:class:`Delegate` provider can be useful. It By the way, in such case, :py:class:`Delegate` or
makes possible to inject providers *as is*. Please check out full example :py:class:`DelegatedSingleton` provider can be useful
in *Providers delegation* section. . It makes possible to inject providers *as is*. Please check out
`Singleton providers delegation`_ section.
Singleton providers resetting Singleton providers resetting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -70,6 +71,15 @@ Example:
.. literalinclude:: ../../examples/providers/singleton_delegation.py .. literalinclude:: ../../examples/providers/singleton_delegation.py
:language: python :language: python
Alternative way of doing :py:class:`Singleton` delegation is an usage of
:py:class:`DelegatedSingleton`. :py:class:`DelegatedSingleton` is a
:py:class:`Singleton` that is always injected "as is".
Example:
.. literalinclude:: ../../examples/providers/delegated_singleton.py
:language: python
Singleton providers specialization Singleton providers specialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,22 @@
"""`DelegatedCallable` providers example."""
from dependency_injector import providers
def command1(config):
"""Some example command."""
return config['some_value'] * 5
def command2(command1):
"""Some example command."""
return command1() / 2
# Creating callable providers for commands:
command1_provider = providers.DelegatedCallable(command1,
config={'some_value': 4})
command2_provider = providers.DelegatedCallable(command2,
command1=command1_provider)
# Making some asserts:
assert command2_provider() == 10

View File

@ -0,0 +1,46 @@
"""`DelegatedFactory` providers example."""
from dependency_injector import providers
class User(object):
"""Example class User."""
def __init__(self, photos_factory):
"""Initializer.
:param photos_factory: providers.Factory -> Photo
"""
self.photos_factory = photos_factory
self._main_photo = None
super(User, self).__init__()
@property
def main_photo(self):
"""Return user's main photo."""
if not self._main_photo:
self._main_photo = self.photos_factory()
return self._main_photo
class Photo(object):
"""Example class Photo."""
# User and Photo factories:
photos_factory = providers.DelegatedFactory(Photo)
users_factory = providers.DelegatedFactory(User,
photos_factory=photos_factory)
# Creating several User objects:
user1 = users_factory()
user2 = users_factory()
# Making some asserts:
assert isinstance(user1, User)
assert isinstance(user1.main_photo, Photo)
assert isinstance(user2, User)
assert isinstance(user2.main_photo, Photo)
assert user1 is not user2
assert user1.main_photo is not user2.main_photo

View File

@ -0,0 +1,18 @@
"""`DelegatedSingleton` providers example."""
from dependency_injector import providers
# Some delegated singleton provider:
singleton_provider = providers.DelegatedSingleton(object)
registry = providers.DelegatedSingleton(dict,
object1=singleton_provider,
object2=singleton_provider)
# Getting several references to singleton object:
registry = registry()
singleton_object1 = registry['object1']()
singleton_object2 = registry['object2']()
# Making some asserts:
assert singleton_object1 is singleton_object2

View File

@ -165,6 +165,136 @@ class DelegateTests(unittest.TestCase):
hex(id(self.delegate)))) hex(id(self.delegate))))
class CallableTests(unittest.TestCase):
"""Callable test cases."""
def example(self, arg1, arg2, arg3, arg4):
"""Example callback."""
return arg1, arg2, arg3, arg4
def test_init_with_callable(self):
"""Test creation of provider with a callable."""
self.assertTrue(providers.Callable(self.example))
def test_init_with_not_callable(self):
"""Test creation of provider with not a callable."""
self.assertRaises(errors.Error, providers.Callable, 123)
def test_call(self):
"""Test call."""
provider = providers.Callable(lambda: True)
self.assertTrue(provider())
def test_call_with_positional_args(self):
"""Test call with positional args.
New simplified syntax.
"""
provider = providers.Callable(self.example, 1, 2, 3, 4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_keyword_args(self):
"""Test call with keyword args.
New simplified syntax.
"""
provider = providers.Callable(self.example,
arg1=1,
arg2=2,
arg3=3,
arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args(self):
"""Test call with positional and keyword args.
Simplified syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args_extended_syntax(self):
"""Test call with positional and keyword args.
Extended syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('arg3', 3),
injections.KwArg('arg4', 4))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_context_args(self):
"""Test call with context args."""
provider = providers.Callable(self.example, 1, 2)
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
def test_call_with_context_kwargs(self):
"""Test call with context kwargs."""
provider = providers.Callable(self.example,
injections.KwArg('arg1', 1))
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_with_context_args_and_kwargs(self):
"""Test call with context args and kwargs."""
provider = providers.Callable(self.example, 1)
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_overridden(self):
"""Test creation of new instances on overridden provider."""
provider = providers.Callable(self.example)
provider.override(providers.Value((4, 3, 2, 1)))
provider.override(providers.Value((1, 2, 3, 4)))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_injections(self):
"""Test getting a full list of injections using injections property."""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertEquals(len(provider.injections), 4)
def test_repr(self):
"""Test representation of provider."""
provider = providers.Callable(self.example,
injections.KwArg(
'arg1',
providers.Factory(dict)),
injections.KwArg(
'arg2',
providers.Factory(list)),
injections.KwArg(
'arg3',
providers.Factory(set)),
injections.KwArg(
'arg4',
providers.Factory(tuple)))
self.assertEqual(repr(provider),
'<dependency_injector.providers.'
'Callable({0}) at {1}>'.format(
repr(self.example),
hex(id(provider))))
class DelegatedCallableTests(unittest.TestCase):
"""DelegatedCallable test cases."""
def test_inheritance(self):
"""Test inheritance."""
self.assertIsInstance(providers.DelegatedCallable(len),
providers.Callable)
def test_is_provider(self):
"""Test is_provider."""
self.assertTrue(utils.is_provider(providers.DelegatedCallable(len)))
def test_is_delegated_provider(self):
"""Test is_delegated_provider."""
self.assertTrue(utils.is_delegated_provider(
providers.DelegatedCallable(len)))
self.assertFalse(utils.is_delegated_provider(providers.Callable(len)))
class FactoryTests(unittest.TestCase): class FactoryTests(unittest.TestCase):
"""Factory test cases.""" """Factory test cases."""
@ -419,6 +549,26 @@ class FactoryTests(unittest.TestCase):
hex(id(provider)))) hex(id(provider))))
class DelegatedFactoryTests(unittest.TestCase):
"""DelegatedFactory test cases."""
def test_inheritance(self):
"""Test inheritance."""
self.assertIsInstance(providers.DelegatedFactory(object),
providers.Factory)
def test_is_provider(self):
"""Test is_provider."""
self.assertTrue(utils.is_provider(providers.DelegatedFactory(object)))
def test_is_delegated_provider(self):
"""Test is_delegated_provider."""
self.assertTrue(utils.is_delegated_provider(
providers.DelegatedFactory(object)))
self.assertFalse(utils.is_delegated_provider(
providers.Factory(object)))
class SingletonTests(unittest.TestCase): class SingletonTests(unittest.TestCase):
"""Singleton test cases.""" """Singleton test cases."""
@ -719,115 +869,25 @@ class SingletonTests(unittest.TestCase):
hex(id(provider)))) hex(id(provider))))
class CallableTests(unittest.TestCase): class DelegatedSingletonTests(unittest.TestCase):
"""Callable test cases.""" """DelegatedSingleton test cases."""
def example(self, arg1, arg2, arg3, arg4): def test_inheritance(self):
"""Example callback.""" """Test inheritance."""
return arg1, arg2, arg3, arg4 self.assertIsInstance(providers.DelegatedSingleton(object),
providers.Singleton)
def test_init_with_callable(self): def test_is_provider(self):
"""Test creation of provider with a callable.""" """Test is_provider."""
self.assertTrue(providers.Callable(self.example)) self.assertTrue(utils.is_provider(
providers.DelegatedSingleton(object)))
def test_init_with_not_callable(self): def test_is_delegated_provider(self):
"""Test creation of provider with not a callable.""" """Test is_delegated_provider."""
self.assertRaises(errors.Error, providers.Callable, 123) self.assertTrue(utils.is_delegated_provider(
providers.DelegatedSingleton(object)))
def test_call(self): self.assertFalse(utils.is_delegated_provider(
"""Test call.""" providers.Singleton(object)))
provider = providers.Callable(lambda: True)
self.assertTrue(provider())
def test_call_with_positional_args(self):
"""Test call with positional args.
New simplified syntax.
"""
provider = providers.Callable(self.example, 1, 2, 3, 4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_keyword_args(self):
"""Test call with keyword args.
New simplified syntax.
"""
provider = providers.Callable(self.example,
arg1=1,
arg2=2,
arg3=3,
arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args(self):
"""Test call with positional and keyword args.
Simplified syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_positional_and_keyword_args_extended_syntax(self):
"""Test call with positional and keyword args.
Extended syntax of positional and keyword arg injections.
"""
provider = providers.Callable(self.example,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('arg3', 3),
injections.KwArg('arg4', 4))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_call_with_context_args(self):
"""Test call with context args."""
provider = providers.Callable(self.example, 1, 2)
self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4))
def test_call_with_context_kwargs(self):
"""Test call with context kwargs."""
provider = providers.Callable(self.example,
injections.KwArg('arg1', 1))
self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_with_context_args_and_kwargs(self):
"""Test call with context args and kwargs."""
provider = providers.Callable(self.example, 1)
self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4))
def test_call_overridden(self):
"""Test creation of new instances on overridden provider."""
provider = providers.Callable(self.example)
provider.override(providers.Value((4, 3, 2, 1)))
provider.override(providers.Value((1, 2, 3, 4)))
self.assertTupleEqual(provider(), (1, 2, 3, 4))
def test_injections(self):
"""Test getting a full list of injections using injections property."""
provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4)
self.assertEquals(len(provider.injections), 4)
def test_repr(self):
"""Test representation of provider."""
provider = providers.Callable(self.example,
injections.KwArg(
'arg1',
providers.Factory(dict)),
injections.KwArg(
'arg2',
providers.Factory(list)),
injections.KwArg(
'arg3',
providers.Factory(set)),
injections.KwArg(
'arg4',
providers.Factory(tuple)))
self.assertEqual(repr(provider),
'<dependency_injector.providers.'
'Callable({0}) at {1}>'.format(
repr(self.example),
hex(id(provider))))
class ExternalDependencyTests(unittest.TestCase): class ExternalDependencyTests(unittest.TestCase):