mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 11:04:01 +03:00
Container provider (#256)
* Add unit tests * Add Container provider * Update changelog
This commit is contained in:
parent
e6f096270e
commit
c8b781e744
|
@ -9,6 +9,7 @@ follows `Semantic versioning`_
|
|||
|
||||
Development version
|
||||
-------------------
|
||||
- Add ``Container`` provider.
|
||||
- Add ``Configuration`` providers linking.
|
||||
|
||||
3.16.1
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -54,6 +54,19 @@ class DynamicContainer(object):
|
|||
self.overridden = tuple()
|
||||
super(DynamicContainer, self).__init__()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""Create and return full copy of container."""
|
||||
copied = memo.get(id(self))
|
||||
if copied is not None:
|
||||
return copied
|
||||
|
||||
copied = self.__class__()
|
||||
copied.provider_type = Provider
|
||||
copied.providers = deepcopy(self.providers, memo)
|
||||
copied.overridden = deepcopy(self.overridden, memo)
|
||||
|
||||
return copied
|
||||
|
||||
def __setattr__(self, str name, object value):
|
||||
"""Set instance attribute.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -92,7 +92,7 @@ cdef class CoroutineDelegate(Delegate):
|
|||
cdef class Configuration(Object):
|
||||
cdef str __name
|
||||
cdef dict __children
|
||||
cdef tuple __linked
|
||||
cdef list __linked
|
||||
|
||||
|
||||
# Factory providers
|
||||
|
@ -176,6 +176,14 @@ cdef class List(Provider):
|
|||
cpdef object _provide(self, tuple args, dict kwargs)
|
||||
|
||||
|
||||
cdef class Container(Provider):
|
||||
cdef object container_cls
|
||||
cdef dict overriding_providers
|
||||
cdef object container
|
||||
|
||||
cpdef object _provide(self, tuple args, dict kwargs)
|
||||
|
||||
|
||||
# Injections
|
||||
cdef class Injection(object):
|
||||
cdef object __value
|
||||
|
|
|
@ -1029,7 +1029,7 @@ cdef class Configuration(Object):
|
|||
|
||||
self.__name = name
|
||||
self.__children = self._create_children(default)
|
||||
self.__linked = tuple()
|
||||
self.__linked = list()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""Create and return full copy of provider."""
|
||||
|
@ -1139,7 +1139,7 @@ cdef class Configuration(Object):
|
|||
|
||||
def link_provider(self, provider):
|
||||
"""Configuration link two configuration providers."""
|
||||
self.__linked += (<Configuration?>provider,)
|
||||
self.__linked.append(<Configuration?>provider)
|
||||
|
||||
def update(self, value):
|
||||
"""Set configuration options.
|
||||
|
@ -2089,6 +2089,58 @@ cdef class List(Provider):
|
|||
return list(__provide_positional_args(args, self.__args, self.__args_len))
|
||||
|
||||
|
||||
cdef class Container(Provider):
|
||||
"""Container provider provides an instance of declarative container.
|
||||
|
||||
.. warning::
|
||||
Provider is experimental. Its interface may change.
|
||||
"""
|
||||
|
||||
def __init__(self, container_cls, container=None, **overriding_providers):
|
||||
"""Initialize provider."""
|
||||
self.container_cls = container_cls
|
||||
self.overriding_providers = overriding_providers
|
||||
|
||||
if container is None:
|
||||
container = container_cls()
|
||||
container.override_providers(**overriding_providers)
|
||||
self.container = container
|
||||
|
||||
super(Container, self).__init__()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""Create and return full copy of provider."""
|
||||
copied = memo.get(id(self))
|
||||
if copied is not None:
|
||||
return copied
|
||||
|
||||
copied = self.__class__(
|
||||
self.container_cls,
|
||||
deepcopy(self.container, memo),
|
||||
**deepcopy(self.overriding_providers, memo),
|
||||
)
|
||||
# self._copy_overridings(copied, memo)
|
||||
|
||||
return copied
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Return dependency provider."""
|
||||
if name.startswith('__') and name.endswith('__'):
|
||||
raise AttributeError(
|
||||
'\'{cls}\' object has no attribute '
|
||||
'\'{attribute_name}\''.format(cls=self.__class__.__name__,
|
||||
attribute_name=name))
|
||||
return getattr(self.container, name)
|
||||
|
||||
def override(self, provider):
|
||||
"""Override provider with another provider."""
|
||||
raise Error('Provider {0} can not be overridden'.format(self))
|
||||
|
||||
cpdef object _provide(self, tuple args, dict kwargs):
|
||||
"""Return single instance."""
|
||||
return self.container
|
||||
|
||||
|
||||
cdef class Injection(object):
|
||||
"""Abstract injection class."""
|
||||
|
||||
|
|
54
tests/unit/providers/test_container_py2_py3.py
Normal file
54
tests/unit/providers/test_container_py2_py3.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
"""Dependency injector container provider unit tests."""
|
||||
|
||||
import copy
|
||||
|
||||
import unittest2 as unittest
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
TEST_VALUE_1 = 'core_section_value1'
|
||||
TEST_CONFIG_1 = {
|
||||
'core': {
|
||||
'section': {
|
||||
'value': TEST_VALUE_1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
TEST_VALUE_2 = 'core_section_value2'
|
||||
TEST_CONFIG_2 = {
|
||||
'core': {
|
||||
'section': {
|
||||
'value': TEST_VALUE_2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _copied(value):
|
||||
return copy.deepcopy(value)
|
||||
|
||||
|
||||
class TestCore(containers.DeclarativeContainer):
|
||||
config = providers.Configuration('core')
|
||||
value_getter = providers.Callable(lambda _: _, config.section.value)
|
||||
|
||||
|
||||
class TestApplication(containers.DeclarativeContainer):
|
||||
config = providers.Configuration('config')
|
||||
core = providers.Container(TestCore, config=config.core)
|
||||
dict_factory = providers.Factory(dict, value=core.value_getter)
|
||||
|
||||
|
||||
class ContainerTests(unittest.TestCase):
|
||||
|
||||
def test(self):
|
||||
application = TestApplication(config=_copied(TEST_CONFIG_1))
|
||||
self.assertEqual(application.dict_factory(), {'value': TEST_VALUE_1})
|
||||
|
||||
def test_double_override(self):
|
||||
application = TestApplication()
|
||||
application.config.override(_copied(TEST_CONFIG_1))
|
||||
application.config.override(_copied(TEST_CONFIG_2))
|
||||
self.assertEqual(application.dict_factory(), {'value': TEST_VALUE_2})
|
Loading…
Reference in New Issue
Block a user