mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Provided attributes (#282)
* Add sketch * Cythonize MethodCaller * Cythonize ItemGetter, AttributeGetter & ProvidedInstance providers * Add docblock for .provided attribute * Refactor repr methods * Add .provided attribute to the Dependency provider * Add tests for the .provided attribute to the majority of the providers * Add docblock for the ProvidedInstance provider * Add docblocks for the rest of the providers * Add example of the provided instance usage * Add tests for provided instance* providers * Add complex provided instance example * Update example provided_instance.py * Add docs
This commit is contained in:
parent
50a9dda192
commit
cf862fe8b5
|
@ -29,4 +29,5 @@ Providers package API docs - :py:mod:`dependency_injector.providers`
|
||||||
selector
|
selector
|
||||||
dependency
|
dependency
|
||||||
overriding
|
overriding
|
||||||
|
provided_instance
|
||||||
custom
|
custom
|
||||||
|
|
64
docs/providers/provided_instance.rst
Normal file
64
docs/providers/provided_instance.rst
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
Injecting attributes, items, or call methods of the provided instance
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
.. currentmodule:: dependency_injector.providers
|
||||||
|
|
||||||
|
In this section you will know how to inject provided instance attribute or item into the other
|
||||||
|
provider.
|
||||||
|
|
||||||
|
It also describes how to call a method of the provided instance and use the result of
|
||||||
|
this call as an injection value.
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/providers/provided_instance.py
|
||||||
|
:language: python
|
||||||
|
:emphasize-lines: 26-32
|
||||||
|
:lines: 3-
|
||||||
|
|
||||||
|
To use the feature you should use the ``.provided`` attribute of the injected provider. This
|
||||||
|
attribute helps to specify what happens with the provided instance. You can retrieve an injection
|
||||||
|
value from:
|
||||||
|
|
||||||
|
- an attribute of the provided instance
|
||||||
|
- an item of the provided instance
|
||||||
|
- a call of the provided instance method
|
||||||
|
|
||||||
|
When you use the call of the provided instance method you can specify the injections into this
|
||||||
|
method like you do with any other provider.
|
||||||
|
|
||||||
|
You can do nested constructions:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/providers/provided_instance_complex.py
|
||||||
|
:language: python
|
||||||
|
:emphasize-lines: 24-30
|
||||||
|
:lines: 3-
|
||||||
|
|
||||||
|
Attribute ``.provided`` is available for the providers that return instances. Providers that
|
||||||
|
have ``.provided`` attribute:
|
||||||
|
|
||||||
|
- :py:class:`Callable` and its subclasses
|
||||||
|
- :py:class:`Factory` and its subclasses
|
||||||
|
- :py:class:`Singleton` and its subclasses
|
||||||
|
- :py:class:`Object`
|
||||||
|
- :py:class:`List`
|
||||||
|
- :py:class:`Selector`
|
||||||
|
- :py:class:`Dependency`
|
||||||
|
|
||||||
|
Special providers like :py:class:`Configuration` or :py:class:`Delegate` do not have the
|
||||||
|
``.provided`` attribute.
|
||||||
|
|
||||||
|
Provider subclasses
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
When you create a new provider subclass and want to implement the ``.provided`` attribute, you
|
||||||
|
should use the :py:class:`ProvidedInstance` provider.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
|
In all other cases you should not use :py:class:`ProvidedInstance`, :py:class:`AttributeGetter`,
|
||||||
|
:py:class:`ItemGetter`, or :py:class:`MethodCaller` providers directly. Use the ``.provided``
|
||||||
|
attribute of the injected provider instead.
|
38
examples/providers/provided_instance.py
Normal file
38
examples/providers/provided_instance.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
"""Example of the injecting of provided instance attributes and items."""
|
||||||
|
|
||||||
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
|
class Service:
|
||||||
|
def __init__(self):
|
||||||
|
self.value = 'foo'
|
||||||
|
self.values = [self.value]
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return self.values[item]
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
def __init__(self, value1, value2, value3, value4):
|
||||||
|
self.value1 = value1
|
||||||
|
self.value2 = value2
|
||||||
|
self.value3 = value3
|
||||||
|
self.value4 = value4
|
||||||
|
|
||||||
|
|
||||||
|
service = providers.Singleton(Service)
|
||||||
|
|
||||||
|
client_factory = providers.Factory(
|
||||||
|
Client,
|
||||||
|
value1=service.provided[0],
|
||||||
|
value2=service.provided.value,
|
||||||
|
value3=service.provided.values[0],
|
||||||
|
value4=service.provided.get_value.call(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
client = client_factory()
|
||||||
|
assert client.value1 == client.value2 == client.value3 == 'foo'
|
41
examples/providers/provided_instance_complex.py
Normal file
41
examples/providers/provided_instance_complex.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
"""Complex example of the injecting of provided instance attributes and items."""
|
||||||
|
|
||||||
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
|
class Service:
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
service = providers.Singleton(Service, value=42)
|
||||||
|
|
||||||
|
dependency = providers.Object(
|
||||||
|
{
|
||||||
|
'foo': {
|
||||||
|
'bar': 10,
|
||||||
|
'baz': lambda arg: {'arg': arg}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
demo_list = providers.List(
|
||||||
|
dependency.provided['foo']['bar'],
|
||||||
|
dependency.provided['foo']['baz'].call(22)['arg'],
|
||||||
|
dependency.provided['foo']['baz'].call(service)['arg'],
|
||||||
|
dependency.provided['foo']['baz'].call(service)['arg'].value,
|
||||||
|
dependency.provided['foo']['baz'].call(service)['arg'].get_value.call(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
assert demo_list() == [
|
||||||
|
10,
|
||||||
|
22,
|
||||||
|
service(),
|
||||||
|
42,
|
||||||
|
42,
|
||||||
|
]
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -197,6 +197,37 @@ cdef class Selector(Provider):
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
# Provided instance
|
||||||
|
|
||||||
|
cdef class ProvidedInstance(Provider):
|
||||||
|
cdef Provider __provider
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class AttributeGetter(Provider):
|
||||||
|
cdef Provider __provider
|
||||||
|
cdef object __attribute
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ItemGetter(Provider):
|
||||||
|
cdef Provider __provider
|
||||||
|
cdef object __item
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class MethodCaller(Provider):
|
||||||
|
cdef Provider __provider
|
||||||
|
cdef tuple __args
|
||||||
|
cdef int __args_len
|
||||||
|
cdef tuple __kwargs
|
||||||
|
cdef int __kwargs_len
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
# Injections
|
# Injections
|
||||||
cdef class Injection(object):
|
cdef class Injection(object):
|
||||||
|
@ -352,18 +383,42 @@ cdef inline object __inject_attributes(
|
||||||
__get_value(attr_injection))
|
__get_value(attr_injection))
|
||||||
|
|
||||||
|
|
||||||
cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
|
cdef inline object __call(
|
||||||
|
object call,
|
||||||
|
tuple context_args,
|
||||||
|
tuple injection_args,
|
||||||
|
int injection_args_len,
|
||||||
|
dict kwargs,
|
||||||
|
tuple injection_kwargs,
|
||||||
|
int injection_kwargs_len,
|
||||||
|
):
|
||||||
cdef tuple positional_args
|
cdef tuple positional_args
|
||||||
cdef dict keyword_args
|
cdef dict keyword_args
|
||||||
|
|
||||||
positional_args = __provide_positional_args(args,
|
positional_args = __provide_positional_args(
|
||||||
self.__args,
|
context_args,
|
||||||
self.__args_len)
|
injection_args,
|
||||||
keyword_args = __provide_keyword_args(kwargs,
|
injection_args_len,
|
||||||
self.__kwargs,
|
)
|
||||||
self.__kwargs_len)
|
keyword_args = __provide_keyword_args(
|
||||||
|
kwargs,
|
||||||
|
injection_kwargs,
|
||||||
|
injection_kwargs_len,
|
||||||
|
)
|
||||||
|
|
||||||
return self.__provides(*positional_args, **keyword_args)
|
return call(*positional_args, **keyword_args)
|
||||||
|
|
||||||
|
|
||||||
|
cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
|
||||||
|
return __call(
|
||||||
|
self.__provides,
|
||||||
|
args,
|
||||||
|
self.__args,
|
||||||
|
self.__args_len,
|
||||||
|
kwargs,
|
||||||
|
self.__kwargs,
|
||||||
|
self.__kwargs_len,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
cdef inline object __factory_call(Factory self, tuple args, dict kwargs):
|
cdef inline object __factory_call(Factory self, tuple args, dict kwargs):
|
||||||
|
|
|
@ -324,6 +324,11 @@ cdef class Object(Provider):
|
||||||
"""
|
"""
|
||||||
return self.__str__()
|
return self.__str__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs):
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
"""Return provided instance.
|
"""Return provided instance.
|
||||||
|
|
||||||
|
@ -479,6 +484,11 @@ cdef class Dependency(Provider):
|
||||||
"""
|
"""
|
||||||
return self.__str__()
|
return self.__str__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def instance_of(self):
|
def instance_of(self):
|
||||||
"""Return class of required dependency."""
|
"""Return class of required dependency."""
|
||||||
|
@ -769,6 +779,11 @@ cdef class Callable(Provider):
|
||||||
"""Return wrapped callable."""
|
"""Return wrapped callable."""
|
||||||
return self.__provides
|
return self.__provides
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def args(self):
|
def args(self):
|
||||||
"""Return positional argument injections."""
|
"""Return positional argument injections."""
|
||||||
|
@ -1599,6 +1614,11 @@ cdef class Factory(Provider):
|
||||||
"""Return provided type."""
|
"""Return provided type."""
|
||||||
return self.__instantiator.provides
|
return self.__instantiator.provides
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def args(self):
|
def args(self):
|
||||||
"""Return positional argument injections."""
|
"""Return positional argument injections."""
|
||||||
|
@ -1932,6 +1952,11 @@ cdef class BaseSingleton(Provider):
|
||||||
"""Return provided type."""
|
"""Return provided type."""
|
||||||
return self.__instantiator.cls
|
return self.__instantiator.cls
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def args(self):
|
def args(self):
|
||||||
"""Return positional argument injections."""
|
"""Return positional argument injections."""
|
||||||
|
@ -2360,6 +2385,11 @@ cdef class List(Provider):
|
||||||
"""
|
"""
|
||||||
return represent_provider(provider=self, provides=list(self.args))
|
return represent_provider(provider=self, provides=list(self.args))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def args(self):
|
def args(self):
|
||||||
"""Return positional argument injections."""
|
"""Return positional argument injections."""
|
||||||
|
@ -2537,6 +2567,11 @@ cdef class Selector(Provider):
|
||||||
address=hex(id(self)),
|
address=hex(id(self)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provided(self):
|
||||||
|
"""Return :py:class:`ProvidedInstance` provider."""
|
||||||
|
return ProvidedInstance(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def providers(self):
|
def providers(self):
|
||||||
"""Return providers."""
|
"""Return providers."""
|
||||||
|
@ -2555,6 +2590,207 @@ cdef class Selector(Provider):
|
||||||
return self.__providers[selector_value](*args, **kwargs)
|
return self.__providers[selector_value](*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ProvidedInstance(Provider):
|
||||||
|
"""Provider that helps to inject attributes and items of the injected instance.
|
||||||
|
|
||||||
|
You can use it like that:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
service = providers.Singleton(Service)
|
||||||
|
|
||||||
|
client_factory = providers.Factory(
|
||||||
|
Client,
|
||||||
|
value1=service.provided[0],
|
||||||
|
value2=service.provided.value,
|
||||||
|
value3=service.provided.values[0],
|
||||||
|
value4=service.provided.get_value.call(),
|
||||||
|
)
|
||||||
|
|
||||||
|
You should not create this provider directly. Get it from the ``.provided`` attribute of the
|
||||||
|
injected provider. This attribute returns the :py:class:`ProvidedInstance` for that provider.
|
||||||
|
|
||||||
|
Providers that have ``.provided`` attribute:
|
||||||
|
|
||||||
|
- :py:class:`Callable` and its subclasses
|
||||||
|
- :py:class:`Factory` and its subclasses
|
||||||
|
- :py:class:`Singleton` and its subclasses
|
||||||
|
- :py:class:`Object`
|
||||||
|
- :py:class:`List`
|
||||||
|
- :py:class:`Selector`
|
||||||
|
- :py:class:`Dependency`
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, provider):
|
||||||
|
self.__provider = provider
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'{self.__class__.__name__}(\'{self.__provider}\')'
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo=None):
|
||||||
|
cdef ProvidedInstance copied
|
||||||
|
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
return self.__class__(
|
||||||
|
deepcopy(self.__provider, memo),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
return AttributeGetter(self, item)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return ItemGetter(self, item)
|
||||||
|
|
||||||
|
def call(self, *args, **kwargs):
|
||||||
|
return MethodCaller(self, *args, **kwargs)
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
return self.__provider(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class AttributeGetter(Provider):
|
||||||
|
"""Provider that returns the attribute of the injected instance.
|
||||||
|
|
||||||
|
You should not create this provider directly. See :py:class:`ProvidedInstance` instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, provider, attribute):
|
||||||
|
self.__provider = provider
|
||||||
|
self.__attribute = attribute
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'{self.__class__.__name__}(\'{self.__attribute}\')'
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo=None):
|
||||||
|
cdef AttributeGetter copied
|
||||||
|
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
return self.__class__(
|
||||||
|
deepcopy(self.__provider, memo),
|
||||||
|
self.__attribute,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
return AttributeGetter(self, item)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return ItemGetter(self, item)
|
||||||
|
|
||||||
|
def call(self, *args, **kwargs):
|
||||||
|
return MethodCaller(self, *args, **kwargs)
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
provided = self.__provider(*args, **kwargs)
|
||||||
|
return getattr(provided, self.__attribute)
|
||||||
|
|
||||||
|
|
||||||
|
cdef class ItemGetter(Provider):
|
||||||
|
"""Provider that returns the item of the injected instance.
|
||||||
|
|
||||||
|
You should not create this provider directly. See :py:class:`ProvidedInstance` instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, Provider provider, object item):
|
||||||
|
self.__provider = provider
|
||||||
|
self.__item = item
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'{self.__class__.__name__}(\'{self.__item}\')'
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo=None):
|
||||||
|
cdef ItemGetter copied
|
||||||
|
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
return self.__class__(
|
||||||
|
deepcopy(self.__provider, memo),
|
||||||
|
self.__item,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
return AttributeGetter(self, item)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return ItemGetter(self, item)
|
||||||
|
|
||||||
|
def call(self, *args, **kwargs):
|
||||||
|
return MethodCaller(self, *args, **kwargs)
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
provided = self.__provider(*args, **kwargs)
|
||||||
|
return provided[self.__item]
|
||||||
|
|
||||||
|
|
||||||
|
cdef class MethodCaller(Provider):
|
||||||
|
"""Provider that calls the method of the injected instance.
|
||||||
|
|
||||||
|
You should not create this provider directly. See :py:class:`ProvidedInstance` instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, provider, *args, **kwargs):
|
||||||
|
self.__provider = provider
|
||||||
|
|
||||||
|
self.__args = parse_positional_injections(args)
|
||||||
|
self.__args_len = len(self.__args)
|
||||||
|
|
||||||
|
self.__kwargs = parse_named_injections(kwargs)
|
||||||
|
self.__kwargs_len = len(self.__kwargs)
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'{self.__class__.__name__}({self.__provider})'
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo=None):
|
||||||
|
cdef MethodCaller copied
|
||||||
|
|
||||||
|
copied = memo.get(id(self))
|
||||||
|
if copied is not None:
|
||||||
|
return copied
|
||||||
|
|
||||||
|
copied = self.__class__(deepcopy(self.__provider, memo))
|
||||||
|
copied.__args = deepcopy(self.__args, memo)
|
||||||
|
copied.__args_len = self.__args_len
|
||||||
|
copied.__kwargs = deepcopy(self.__kwargs, memo)
|
||||||
|
copied.__kwargs_len = self.__kwargs_len
|
||||||
|
|
||||||
|
self._copy_overridings(copied, memo)
|
||||||
|
|
||||||
|
return copied
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
return AttributeGetter(self, item)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return ItemGetter(self, item)
|
||||||
|
|
||||||
|
def call(self, *args, **kwargs):
|
||||||
|
return MethodCaller(self, *args, **kwargs)
|
||||||
|
|
||||||
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
|
call = self.__provider()
|
||||||
|
return __call(
|
||||||
|
call,
|
||||||
|
args,
|
||||||
|
self.__args,
|
||||||
|
self.__args_len,
|
||||||
|
kwargs,
|
||||||
|
self.__kwargs,
|
||||||
|
self.__kwargs_len,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
cdef class Injection(object):
|
cdef class Injection(object):
|
||||||
"""Abstract injection class."""
|
"""Abstract injection class."""
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,10 @@ class ObjectProviderTests(unittest.TestCase):
|
||||||
def test_is_provider(self):
|
def test_is_provider(self):
|
||||||
self.assertTrue(providers.is_provider(providers.Object(object())))
|
self.assertTrue(providers.is_provider(providers.Object(object())))
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
provider = providers.Object(object())
|
||||||
|
self.assertIsInstance(provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call_object_provider(self):
|
def test_call_object_provider(self):
|
||||||
obj = object()
|
obj = object()
|
||||||
self.assertIs(providers.Object(obj)(), obj)
|
self.assertIs(providers.Object(obj)(), obj)
|
||||||
|
@ -264,6 +268,9 @@ class DependencyTests(unittest.TestCase):
|
||||||
def test_is_provider(self):
|
def test_is_provider(self):
|
||||||
self.assertTrue(providers.is_provider(self.provider))
|
self.assertTrue(providers.is_provider(self.provider))
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
self.assertIsInstance(self.provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call_overridden(self):
|
def test_call_overridden(self):
|
||||||
self.provider.provided_by(providers.Factory(list))
|
self.provider.provided_by(providers.Factory(list))
|
||||||
self.assertIsInstance(self.provider(), list)
|
self.assertIsInstance(self.provider(), list)
|
||||||
|
|
|
@ -22,6 +22,10 @@ class CallableTests(unittest.TestCase):
|
||||||
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)
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
provider = providers.Callable(_example)
|
||||||
|
self.assertIsInstance(provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call(self):
|
def test_call(self):
|
||||||
provider = providers.Callable(lambda: True)
|
provider = providers.Callable(lambda: True)
|
||||||
self.assertTrue(provider())
|
self.assertTrue(provider())
|
||||||
|
|
|
@ -60,6 +60,10 @@ class FactoryTests(unittest.TestCase):
|
||||||
with self.assertRaises(errors.Error):
|
with self.assertRaises(errors.Error):
|
||||||
ExampleProvider(list)
|
ExampleProvider(list)
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
provider = providers.Factory(Example)
|
||||||
|
self.assertIsInstance(provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call(self):
|
def test_call(self):
|
||||||
provider = providers.Factory(Example)
|
provider = providers.Factory(Example)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ class ListTests(unittest.TestCase):
|
||||||
def test_is_provider(self):
|
def test_is_provider(self):
|
||||||
self.assertTrue(providers.is_provider(providers.List()))
|
self.assertTrue(providers.is_provider(providers.List()))
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
provider = providers.List()
|
||||||
|
self.assertIsInstance(provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call_with_init_positional_args(self):
|
def test_call_with_init_positional_args(self):
|
||||||
provider = providers.List('i1', 'i2')
|
provider = providers.List('i1', 'i2')
|
||||||
|
|
||||||
|
|
139
tests/unit/providers/test_provided_instance_py2_py3.py
Normal file
139
tests/unit/providers/test_provided_instance_py2_py3.py
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
"""Dependency injector provided instance provider unit tests."""
|
||||||
|
|
||||||
|
import unittest2 as unittest
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
|
||||||
|
class Service:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
self.values = [self.value]
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return self.values[item]
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
service = providers.Singleton(Service, value='foo')
|
||||||
|
|
||||||
|
client_attribute = providers.Factory(
|
||||||
|
Client,
|
||||||
|
value=service.provided.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
client_item = providers.Factory(
|
||||||
|
Client,
|
||||||
|
value=service.provided[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
client_attribute_item = providers.Factory(
|
||||||
|
Client,
|
||||||
|
value=service.provided.values[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
client_method_call = providers.Factory(
|
||||||
|
Client,
|
||||||
|
value=service.provided.get_value.call(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProvidedInstanceTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.container = Container()
|
||||||
|
|
||||||
|
def test_is_provider(self):
|
||||||
|
self.assertTrue(providers.is_provider(self.container.service.provided))
|
||||||
|
|
||||||
|
def test_attribute(self):
|
||||||
|
client = self.container.client_attribute()
|
||||||
|
self.assertEqual(client.value, 'foo')
|
||||||
|
|
||||||
|
def test_item(self):
|
||||||
|
client = self.container.client_item()
|
||||||
|
self.assertEqual(client.value, 'foo')
|
||||||
|
|
||||||
|
def test_attribute_item(self):
|
||||||
|
client = self.container.client_attribute_item()
|
||||||
|
self.assertEqual(client.value, 'foo')
|
||||||
|
|
||||||
|
def test_method_call(self):
|
||||||
|
client = self.container.client_method_call()
|
||||||
|
self.assertEqual(client.value, 'foo')
|
||||||
|
|
||||||
|
def test_call_overridden(self):
|
||||||
|
value = 'bar'
|
||||||
|
with self.container.service.override(Service(value)):
|
||||||
|
self.assertEqual(self.container.client_attribute().value, value)
|
||||||
|
self.assertEqual(self.container.client_item().value, value)
|
||||||
|
self.assertEqual(self.container.client_attribute_item().value, value)
|
||||||
|
self.assertEqual(self.container.client_method_call().value, value)
|
||||||
|
|
||||||
|
def test_repr_provided_instance(self):
|
||||||
|
provider = self.container.service.provided
|
||||||
|
self.assertEqual(
|
||||||
|
'ProvidedInstance(\'{0}\')'.format(repr(self.container.service)),
|
||||||
|
repr(provider),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_repr_attribute_getter(self):
|
||||||
|
provider = self.container.service.provided.value
|
||||||
|
self.assertEqual(
|
||||||
|
'AttributeGetter(\'value\')',
|
||||||
|
repr(provider),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_repr_item_getter(self):
|
||||||
|
provider = self.container.service.provided['test-test']
|
||||||
|
self.assertEqual(
|
||||||
|
'ItemGetter(\'test-test\')',
|
||||||
|
repr(provider),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProvidedInstancePuzzleTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_puzzled(self):
|
||||||
|
service = providers.Singleton(Service, value='foo-bar')
|
||||||
|
|
||||||
|
dependency = providers.Object(
|
||||||
|
{
|
||||||
|
'a': {
|
||||||
|
'b': {
|
||||||
|
'c1': 10,
|
||||||
|
'c2': lambda arg: {'arg': arg}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
test_list = providers.List(
|
||||||
|
dependency.provided['a']['b']['c1'],
|
||||||
|
dependency.provided['a']['b']['c2'].call(22)['arg'],
|
||||||
|
dependency.provided['a']['b']['c2'].call(service)['arg'],
|
||||||
|
dependency.provided['a']['b']['c2'].call(service)['arg'].value,
|
||||||
|
dependency.provided['a']['b']['c2'].call(service)['arg'].get_value.call(),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = test_list()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
result,
|
||||||
|
[
|
||||||
|
10,
|
||||||
|
22,
|
||||||
|
service(),
|
||||||
|
'foo-bar',
|
||||||
|
'foo-bar',
|
||||||
|
],
|
||||||
|
)
|
|
@ -16,6 +16,10 @@ class SelectorTests(unittest.TestCase):
|
||||||
def test_is_provider(self):
|
def test_is_provider(self):
|
||||||
self.assertTrue(providers.is_provider(providers.Selector(self.selector)))
|
self.assertTrue(providers.is_provider(providers.Selector(self.selector)))
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
provider = providers.Selector(self.selector)
|
||||||
|
self.assertIsInstance(provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call(self):
|
def test_call(self):
|
||||||
provider = providers.Selector(
|
provider = providers.Selector(
|
||||||
self.selector,
|
self.selector,
|
||||||
|
|
|
@ -62,6 +62,10 @@ class _BaseSingletonTestCase(object):
|
||||||
with self.assertRaises(errors.Error):
|
with self.assertRaises(errors.Error):
|
||||||
ExampleProvider(list)
|
ExampleProvider(list)
|
||||||
|
|
||||||
|
def test_provided_instance_provider(self):
|
||||||
|
provider = providers.Singleton(Example)
|
||||||
|
self.assertIsInstance(provider.provided, providers.ProvidedInstance)
|
||||||
|
|
||||||
def test_call(self):
|
def test_call(self):
|
||||||
provider = self.singleton_cls(Example)
|
provider = self.singleton_cls(Example)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user