mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-29 13:04:02 +03:00
Merge remote-tracking branch 'origin/configuration_provider'
This commit is contained in:
commit
3295e979fa
4
setup.py
4
setup.py
|
@ -51,6 +51,10 @@ setup(name='dependency-injector',
|
|||
['src/dependency_injector/providers/base.c'],
|
||||
define_macros=defined_macros,
|
||||
extra_compile_args=['-O2']),
|
||||
Extension('dependency_injector.providers.configuration',
|
||||
['src/dependency_injector/providers/configuration.c'],
|
||||
define_macros=defined_macros,
|
||||
extra_compile_args=['-O2']),
|
||||
Extension('dependency_injector.providers.callables',
|
||||
['src/dependency_injector/providers/callables.c'],
|
||||
define_macros=defined_macros,
|
||||
|
|
|
@ -7,6 +7,9 @@ from .base import (
|
|||
ExternalDependency,
|
||||
OverridingContext,
|
||||
)
|
||||
from .configuration import (
|
||||
Configuration,
|
||||
)
|
||||
from .callables import (
|
||||
Callable,
|
||||
DelegatedCallable,
|
||||
|
@ -48,6 +51,8 @@ __all__ = (
|
|||
'ExternalDependency',
|
||||
'OverridingContext',
|
||||
|
||||
'Configuration',
|
||||
|
||||
'Callable',
|
||||
'DelegatedCallable',
|
||||
|
||||
|
|
4868
src/dependency_injector/providers/configuration.c
Normal file
4868
src/dependency_injector/providers/configuration.c
Normal file
File diff suppressed because it is too large
Load Diff
19
src/dependency_injector/providers/configuration.pxd
Normal file
19
src/dependency_injector/providers/configuration.pxd
Normal file
|
@ -0,0 +1,19 @@
|
|||
"""Dependency injector configuration providers.
|
||||
|
||||
Powered by Cython.
|
||||
"""
|
||||
|
||||
from .base cimport (
|
||||
Provider,
|
||||
)
|
||||
|
||||
|
||||
cdef class Configuration(Provider):
|
||||
cdef str __name
|
||||
cdef object __value
|
||||
cdef dict __children
|
||||
|
||||
cpdef str get_name(self)
|
||||
cpdef object update(self, object value)
|
||||
cpdef object _provide(self, tuple args, dict kwargs)
|
||||
cpdef str _get_child_name(self, str child_name)
|
116
src/dependency_injector/providers/configuration.pyx
Normal file
116
src/dependency_injector/providers/configuration.pyx
Normal file
|
@ -0,0 +1,116 @@
|
|||
"""Dependency injector configuration providers.
|
||||
|
||||
Powered by Cython.
|
||||
"""
|
||||
|
||||
from .base cimport (
|
||||
Provider,
|
||||
)
|
||||
from .utils cimport (
|
||||
represent_provider,
|
||||
deepcopy,
|
||||
)
|
||||
|
||||
|
||||
cdef class Configuration(Provider):
|
||||
"""Configuration provider.
|
||||
|
||||
Configudation provider helps with implementing late static binding of
|
||||
configuration options - use first, set last.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
config = Configuration('config')
|
||||
|
||||
print(config.section1.option1()) # None
|
||||
print(config.section1.option2()) # None
|
||||
|
||||
config.update({'section1': {'option1': 1,
|
||||
'option2': 2}})
|
||||
|
||||
print(config.section1.option1()) # 1
|
||||
print(config.section1.option2()) # 2
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
"""Initializer."""
|
||||
self.__name = name
|
||||
self.__value = None
|
||||
self.__children = dict()
|
||||
super(Configuration, 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.__name)
|
||||
copied.update(deepcopy(self.__value))
|
||||
|
||||
for overriding_provider in self.overridden:
|
||||
copied.override(deepcopy(overriding_provider, memo))
|
||||
|
||||
return copied
|
||||
|
||||
def __str__(self):
|
||||
"""Return string representation of provider.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return represent_provider(provider=self, provides=self.__name)
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Return child configuration provider."""
|
||||
cdef Configuration child_provider
|
||||
cdef object value
|
||||
|
||||
child_provider = self.__children.get(name)
|
||||
|
||||
if child_provider is None:
|
||||
child_provider = self.__class__(self._get_child_name(name))
|
||||
|
||||
if isinstance(self.__value, dict):
|
||||
child_provider.update(self.__value.get(name))
|
||||
|
||||
self.__children[name] = child_provider
|
||||
|
||||
return child_provider
|
||||
|
||||
cpdef str get_name(self):
|
||||
"""Name of configuration unit."""
|
||||
return self.__name
|
||||
|
||||
cpdef object update(self, value):
|
||||
"""Set configuration options."""
|
||||
cdef Configuration child_provider
|
||||
cdef object child_value
|
||||
|
||||
self.__value = value
|
||||
|
||||
if not isinstance(self.__value, dict):
|
||||
return
|
||||
|
||||
for name in self.__value:
|
||||
child_provider = self.__children.get(name)
|
||||
|
||||
if child_provider is None:
|
||||
continue
|
||||
|
||||
child_provider.update(self.__value.get(name))
|
||||
|
||||
cpdef object _provide(self, tuple args, dict kwargs):
|
||||
"""Return result of provided callable's call."""
|
||||
return self.__value
|
||||
|
||||
cpdef str _get_child_name(self, str child_name):
|
||||
cdef str child_full_name
|
||||
|
||||
child_full_name = ''
|
||||
|
||||
if self.__name:
|
||||
child_full_name += self.__name + '.'
|
||||
|
||||
child_full_name += child_name
|
||||
|
||||
return child_full_name
|
96
tests/unit/providers/test_configuration.py
Normal file
96
tests/unit/providers/test_configuration.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
"""Dependency injector config providers unit tests."""
|
||||
|
||||
import unittest2 as unittest
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class ConfigTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = providers.Configuration(name='config')
|
||||
|
||||
def tearDown(self):
|
||||
del self.config
|
||||
|
||||
def test_providers_are_providers(self):
|
||||
self.assertTrue(providers.is_provider(self.config.a))
|
||||
self.assertTrue(providers.is_provider(self.config.a.b))
|
||||
self.assertTrue(providers.is_provider(self.config.a.b.c))
|
||||
self.assertTrue(providers.is_provider(self.config.a.b.d))
|
||||
|
||||
def test_providers_are_not_delegates(self):
|
||||
self.assertFalse(providers.is_delegated(self.config.a))
|
||||
self.assertFalse(providers.is_delegated(self.config.a.b))
|
||||
self.assertFalse(providers.is_delegated(self.config.a.b.c))
|
||||
self.assertFalse(providers.is_delegated(self.config.a.b.d))
|
||||
|
||||
def test_providers_identity(self):
|
||||
self.assertIs(self.config.a, self.config.a)
|
||||
self.assertIs(self.config.a.b, self.config.a.b)
|
||||
self.assertIs(self.config.a.b.c, self.config.a.b.c)
|
||||
self.assertIs(self.config.a.b.d, self.config.a.b.d)
|
||||
|
||||
def test_get_name(self):
|
||||
self.assertEqual(self.config.a.b.c.get_name(), 'config.a.b.c')
|
||||
|
||||
def test_providers_value_setting(self):
|
||||
a = self.config.a
|
||||
ab = self.config.a.b
|
||||
abc = self.config.a.b.c
|
||||
abd = self.config.a.b.d
|
||||
|
||||
self.config.update({'a': {'b': {'c': 1, 'd': 2}}})
|
||||
|
||||
self.assertEqual(a(), {'b': {'c': 1, 'd': 2}})
|
||||
self.assertEqual(ab(), {'c': 1, 'd': 2})
|
||||
self.assertEqual(abc(), 1)
|
||||
self.assertEqual(abd(), 2)
|
||||
|
||||
def test_value_of_undefined_option(self):
|
||||
self.assertIsNone(self.config.a())
|
||||
|
||||
def test_deepcopy(self):
|
||||
provider = providers.Configuration('config')
|
||||
provider_copy = providers.deepcopy(provider)
|
||||
|
||||
self.assertIsNot(provider, provider_copy)
|
||||
self.assertIsInstance(provider, providers.Configuration)
|
||||
|
||||
def test_deepcopy_from_memo(self):
|
||||
provider = providers.Configuration('config')
|
||||
provider_copy_memo = providers.Configuration('config')
|
||||
|
||||
provider_copy = providers.deepcopy(
|
||||
provider, memo={id(provider): provider_copy_memo})
|
||||
|
||||
self.assertIs(provider_copy, provider_copy_memo)
|
||||
|
||||
def test_deepcopy_overridden(self):
|
||||
provider = providers.Configuration('config')
|
||||
object_provider = providers.Object(object())
|
||||
|
||||
provider.override(object_provider)
|
||||
|
||||
provider_copy = providers.deepcopy(provider)
|
||||
object_provider_copy = provider_copy.overridden[0]
|
||||
|
||||
self.assertIsNot(provider, provider_copy)
|
||||
self.assertIsInstance(provider, providers.Configuration)
|
||||
|
||||
self.assertIsNot(object_provider, object_provider_copy)
|
||||
self.assertIsInstance(object_provider_copy, providers.Object)
|
||||
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(self.config),
|
||||
'<dependency_injector.providers.configuration.'
|
||||
'Configuration({0}) at {1}>'.format(
|
||||
repr('config'),
|
||||
hex(id(self.config))))
|
||||
|
||||
def test_repr_child(self):
|
||||
self.assertEqual(repr(self.config.a.b.c),
|
||||
'<dependency_injector.providers.configuration.'
|
||||
'Configuration({0}) at {1}>'.format(
|
||||
repr('config.a.b.c'),
|
||||
hex(id(self.config.a.b.c))))
|
Loading…
Reference in New Issue
Block a user