mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-04 18:07:44 +03:00 
			
		
		
		
	Merge branch 'release/3.17.0' into master
This commit is contained in:
		
						commit
						827f9b57bb
					
				| 
						 | 
				
			
			@ -7,6 +7,11 @@ that were made in every particular version.
 | 
			
		|||
From version 0.7.6 *Dependency Injector* framework strictly 
 | 
			
		||||
follows `Semantic versioning`_
 | 
			
		||||
 | 
			
		||||
3.17.0
 | 
			
		||||
------
 | 
			
		||||
- Add ``Container`` provider.
 | 
			
		||||
- Add ``Configuration`` providers linking.
 | 
			
		||||
 | 
			
		||||
3.16.1
 | 
			
		||||
------
 | 
			
		||||
- Update ``singleton_thread_locals.py`` to support Python 3 (thanks to
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
"""Dependency injector top-level package."""
 | 
			
		||||
 | 
			
		||||
__version__ = '3.16.1'
 | 
			
		||||
__version__ = '3.17.0'
 | 
			
		||||
"""Version number that follows semantic versioning.
 | 
			
		||||
 | 
			
		||||
:type: str
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												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,6 +92,7 @@ cdef class CoroutineDelegate(Delegate):
 | 
			
		|||
cdef class Configuration(Object):
 | 
			
		||||
    cdef str __name
 | 
			
		||||
    cdef dict __children
 | 
			
		||||
    cdef list __linked
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Factory providers
 | 
			
		||||
| 
						 | 
				
			
			@ -175,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,6 +1029,7 @@ cdef class Configuration(Object):
 | 
			
		|||
 | 
			
		||||
        self.__name = name
 | 
			
		||||
        self.__children = self._create_children(default)
 | 
			
		||||
        self.__linked = list()
 | 
			
		||||
 | 
			
		||||
    def __deepcopy__(self, memo):
 | 
			
		||||
        """Create and return full copy of provider."""
 | 
			
		||||
| 
						 | 
				
			
			@ -1041,6 +1042,7 @@ cdef class Configuration(Object):
 | 
			
		|||
        copied = self.__class__(self.__name)
 | 
			
		||||
        copied.__provides = deepcopy(self.__provides, memo)
 | 
			
		||||
        copied.__children = deepcopy(self.__children, memo)
 | 
			
		||||
        copied.__linked = deepcopy(self.__linked, memo)
 | 
			
		||||
 | 
			
		||||
        self._copy_overridings(copied, memo)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1093,11 +1095,17 @@ cdef class Configuration(Object):
 | 
			
		|||
        """
 | 
			
		||||
        overriding_context = super(Configuration, self).override(provider)
 | 
			
		||||
 | 
			
		||||
        for linked in self.__linked:
 | 
			
		||||
            linked.override(provider)
 | 
			
		||||
 | 
			
		||||
        if isinstance(provider, Configuration):
 | 
			
		||||
            provider.link_provider(self)
 | 
			
		||||
 | 
			
		||||
        value = self.__call__()
 | 
			
		||||
        if not isinstance(value, dict):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        for name in value:
 | 
			
		||||
        for name in value.keys():
 | 
			
		||||
            child_provider = self.__children.get(name)
 | 
			
		||||
            if child_provider is None:
 | 
			
		||||
                continue
 | 
			
		||||
| 
						 | 
				
			
			@ -1129,6 +1137,10 @@ cdef class Configuration(Object):
 | 
			
		|||
            child.reset_override()
 | 
			
		||||
        super(Configuration, self).reset_override()
 | 
			
		||||
 | 
			
		||||
    def link_provider(self, provider):
 | 
			
		||||
        """Configuration link two configuration providers."""
 | 
			
		||||
        self.__linked.append(<Configuration?>provider)
 | 
			
		||||
 | 
			
		||||
    def update(self, value):
 | 
			
		||||
        """Set configuration options.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2077,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."""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
import unittest2 as unittest
 | 
			
		||||
 | 
			
		||||
from dependency_injector import providers
 | 
			
		||||
from dependency_injector import containers, providers
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConfigTests(unittest.TestCase):
 | 
			
		||||
| 
						 | 
				
			
			@ -177,3 +177,72 @@ class ConfigTests(unittest.TestCase):
 | 
			
		|||
                         'Configuration({0}) at {1}>'.format(
 | 
			
		||||
                             repr('config.a.b.c'),
 | 
			
		||||
                             hex(id(self.config.a.b.c))))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConfigLinkingTests(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    class TestCore(containers.DeclarativeContainer):
 | 
			
		||||
        config = providers.Configuration('core')
 | 
			
		||||
        value_getter = providers.Callable(lambda _: _, config.value)
 | 
			
		||||
 | 
			
		||||
    class TestServices(containers.DeclarativeContainer):
 | 
			
		||||
        config = providers.Configuration('services')
 | 
			
		||||
        value_getter = providers.Callable(lambda _: _, config.value)
 | 
			
		||||
 | 
			
		||||
    def test(self):
 | 
			
		||||
        root_config = providers.Configuration('main')
 | 
			
		||||
        core = self.TestCore(config=root_config.core)
 | 
			
		||||
        services = self.TestServices(config=root_config.services)
 | 
			
		||||
 | 
			
		||||
        root_config.override(
 | 
			
		||||
            {
 | 
			
		||||
                'core': {
 | 
			
		||||
                    'value': 'core',
 | 
			
		||||
                },
 | 
			
		||||
                'services': {
 | 
			
		||||
                    'value': 'services',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(core.config(), {'value': 'core'})
 | 
			
		||||
        self.assertEqual(core.config.value(), 'core')
 | 
			
		||||
        self.assertEqual(core.value_getter(), 'core')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(services.config(), {'value': 'services'})
 | 
			
		||||
        self.assertEqual(services.config.value(), 'services')
 | 
			
		||||
        self.assertEqual(services.value_getter(), 'services')
 | 
			
		||||
 | 
			
		||||
    def test_double_override(self):
 | 
			
		||||
        root_config = providers.Configuration('main')
 | 
			
		||||
        core = self.TestCore(config=root_config.core)
 | 
			
		||||
        services = self.TestServices(config=root_config.services)
 | 
			
		||||
 | 
			
		||||
        root_config.override(
 | 
			
		||||
            {
 | 
			
		||||
                'core': {
 | 
			
		||||
                    'value': 'core1',
 | 
			
		||||
                },
 | 
			
		||||
                'services': {
 | 
			
		||||
                    'value': 'services1',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        root_config.override(
 | 
			
		||||
            {
 | 
			
		||||
                'core': {
 | 
			
		||||
                    'value': 'core2',
 | 
			
		||||
                },
 | 
			
		||||
                'services': {
 | 
			
		||||
                    'value': 'services2',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(core.config(), {'value': 'core2'})
 | 
			
		||||
        self.assertEqual(core.config.value(), 'core2')
 | 
			
		||||
        self.assertEqual(core.value_getter(), 'core2')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(services.config(), {'value': 'services2'})
 | 
			
		||||
        self.assertEqual(services.config.value(), 'services2')
 | 
			
		||||
        self.assertEqual(services.value_getter(), 'services2')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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