mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Add DelegatedCallable, DelegatedFactory & DelegatedSingleton providers
This commit is contained in:
parent
0d00e2b0f5
commit
319128260a
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
------
|
------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
22
examples/providers/delegated_callable.py
Normal file
22
examples/providers/delegated_callable.py
Normal 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
|
46
examples/providers/delegated_factory.py
Normal file
46
examples/providers/delegated_factory.py
Normal 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
|
18
examples/providers/delegated_singleton.py
Normal file
18
examples/providers/delegated_singleton.py
Normal 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
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user