mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-04 09:57:37 +03:00 
			
		
		
		
	Refactor configuration provider
This commit is contained in:
		
							parent
							
								
									86a8efa294
								
							
						
					
					
						commit
						e877b33fd1
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -71,16 +71,10 @@ cdef class CallableDelegate(Delegate):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Configuration providers
 | 
					# Configuration providers
 | 
				
			||||||
cdef class Configuration(Provider):
 | 
					cdef class Configuration(Object):
 | 
				
			||||||
    cdef str __name
 | 
					    cdef str __name
 | 
				
			||||||
    cdef object __value
 | 
					 | 
				
			||||||
    cdef dict __children
 | 
					    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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Factory providers
 | 
					# Factory providers
 | 
				
			||||||
cdef class Factory(Provider):
 | 
					cdef class Factory(Provider):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -823,7 +823,7 @@ cdef class CallableDelegate(Delegate):
 | 
				
			||||||
        super(Delegate, self).__init__(callable)
 | 
					        super(Delegate, self).__init__(callable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class Configuration(Provider):
 | 
					cdef class Configuration(Object):
 | 
				
			||||||
    """Configuration provider.
 | 
					    """Configuration provider.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Configuration provider helps with implementing late static binding of
 | 
					    Configuration provider helps with implementing late static binding of
 | 
				
			||||||
| 
						 | 
					@ -836,7 +836,7 @@ cdef class Configuration(Provider):
 | 
				
			||||||
        print(config.section1.option1())  # None
 | 
					        print(config.section1.option1())  # None
 | 
				
			||||||
        print(config.section1.option2())  # None
 | 
					        print(config.section1.option2())  # None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        config.update({'section1': {'option1': 1,
 | 
					        config.override({'section1': {'option1': 1,
 | 
				
			||||||
                                      'option2': 2}})
 | 
					                                      'option2': 2}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print(config.section1.option1())  # 1
 | 
					        print(config.section1.option1())  # 1
 | 
				
			||||||
| 
						 | 
					@ -852,12 +852,10 @@ cdef class Configuration(Provider):
 | 
				
			||||||
        :param default: Default values of configuration unit.
 | 
					        :param default: Default values of configuration unit.
 | 
				
			||||||
        :type default: dict
 | 
					        :type default: dict
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        super(Configuration, self).__init__(default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.__name = name
 | 
					        self.__name = name
 | 
				
			||||||
        self.__value = None
 | 
					        self.__children = self._create_children(default)
 | 
				
			||||||
        self.__children = dict()
 | 
					 | 
				
			||||||
        if default is not None:
 | 
					 | 
				
			||||||
            self.update(default)
 | 
					 | 
				
			||||||
        super(Configuration, self).__init__()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __deepcopy__(self, memo):
 | 
					    def __deepcopy__(self, memo):
 | 
				
			||||||
        """Create and return full copy of provider."""
 | 
					        """Create and return full copy of provider."""
 | 
				
			||||||
| 
						 | 
					@ -868,7 +866,7 @@ cdef class Configuration(Provider):
 | 
				
			||||||
            return copied
 | 
					            return copied
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        copied = self.__class__(self.__name)
 | 
					        copied = self.__class__(self.__name)
 | 
				
			||||||
        copied.__value = deepcopy(self.__value, memo)
 | 
					        copied.__provides = deepcopy(self.__provides, memo)
 | 
				
			||||||
        copied.__children = deepcopy(self.__children, memo)
 | 
					        copied.__children = deepcopy(self.__children, memo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._copy_overridings(copied)
 | 
					        self._copy_overridings(copied)
 | 
				
			||||||
| 
						 | 
					@ -884,9 +882,6 @@ cdef class Configuration(Provider):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getattr__(self, str name):
 | 
					    def __getattr__(self, str name):
 | 
				
			||||||
        """Return child configuration provider."""
 | 
					        """Return child configuration provider."""
 | 
				
			||||||
        cdef Configuration child_provider
 | 
					 | 
				
			||||||
        cdef object value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if name.startswith('__') and name.endswith('__'):
 | 
					        if name.startswith('__') and name.endswith('__'):
 | 
				
			||||||
            raise AttributeError(
 | 
					            raise AttributeError(
 | 
				
			||||||
                '\'{cls}\' object has no attribute '
 | 
					                '\'{cls}\' object has no attribute '
 | 
				
			||||||
| 
						 | 
					@ -896,55 +891,103 @@ cdef class Configuration(Provider):
 | 
				
			||||||
        child_provider = self.__children.get(name)
 | 
					        child_provider = self.__children.get(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if child_provider is None:
 | 
					        if child_provider is None:
 | 
				
			||||||
            child_provider = self.__class__(self._get_child_name(name))
 | 
					            child_name = self._get_child_full_name(name)
 | 
				
			||||||
 | 
					            child_provider = self.__class__(child_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if isinstance(self.__value, dict):
 | 
					            value = self.__call__()
 | 
				
			||||||
                child_provider.update(self.__value.get(name))
 | 
					            if isinstance(value, dict):
 | 
				
			||||||
 | 
					                child_value = value.get(name)
 | 
				
			||||||
 | 
					                child_provider.override(child_value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.__children[name] = child_provider
 | 
					            self.__children[name] = child_provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return child_provider
 | 
					        return child_provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef str get_name(self):
 | 
					    def get_name(self):
 | 
				
			||||||
        """Name of configuration unit."""
 | 
					        """Name of configuration unit."""
 | 
				
			||||||
        return self.__name
 | 
					        return self.__name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object update(self, value):
 | 
					    def override(self, provider):
 | 
				
			||||||
 | 
					        """Override provider with another provider.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param provider: Overriding provider.
 | 
				
			||||||
 | 
					        :type provider: :py:class:`Provider`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :raise: :py:exc:`dependency_injector.errors.Error`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return: Overriding context.
 | 
				
			||||||
 | 
					        :rtype: :py:class:`OverridingContext`
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        overriding_context = super(Configuration, self).override(provider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        value = self.__call__()
 | 
				
			||||||
 | 
					        if not isinstance(value, dict):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for name in value:
 | 
				
			||||||
 | 
					            child_provider = self.__children.get(name)
 | 
				
			||||||
 | 
					            if child_provider is None:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            child_provider.override(value.get(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return overriding_context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_last_overriding(self):
 | 
				
			||||||
 | 
					        """Reset last overriding provider.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :raise: :py:exc:`dependency_injector.errors.Error` if provider is not
 | 
				
			||||||
 | 
					                overridden.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :rtype: None
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for child in self.__children.values():
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                child.reset_last_overriding()
 | 
				
			||||||
 | 
					            except Error:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        super(Configuration, self).reset_last_overriding()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_override(self):
 | 
				
			||||||
 | 
					        """Reset all overriding providers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :rtype: None
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for child in self.__children.values():
 | 
				
			||||||
 | 
					            child.reset_override()
 | 
				
			||||||
 | 
					        super(Configuration, self).reset_override()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update(self, value):
 | 
				
			||||||
        """Set configuration options.
 | 
					        """Set configuration options.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .. deprecated:: 3.11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Use :py:meth:`Configuration.override` instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param value: Value of configuration option.
 | 
					        :param value: Value of configuration option.
 | 
				
			||||||
        :type value: object | dict
 | 
					        :type value: object | dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :rtype: None
 | 
					        :rtype: None
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        cdef Configuration child_provider
 | 
					        self.override(value)
 | 
				
			||||||
        cdef object child_value
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.__value = value
 | 
					    def _create_children(self, value):
 | 
				
			||||||
 | 
					        children = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not isinstance(self.__value, dict):
 | 
					        if not isinstance(value, dict):
 | 
				
			||||||
            return
 | 
					            return children
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for name in self.__value:
 | 
					        for child_name, child_value in value.items():
 | 
				
			||||||
            child_provider = self.__children.get(name)
 | 
					            child_full_name = self._get_child_full_name(child_name)
 | 
				
			||||||
 | 
					            child_provider = self.__class__(child_full_name, child_value)
 | 
				
			||||||
 | 
					            children[child_name] = child_provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if child_provider is None:
 | 
					        return children
 | 
				
			||||||
                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
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_child_full_name(self, child_name):
 | 
				
			||||||
        child_full_name = ''
 | 
					        child_full_name = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.__name:
 | 
					        if self.__name:
 | 
				
			||||||
            child_full_name += self.__name + '.'
 | 
					            child_full_name += self.__name + '.'
 | 
				
			||||||
 | 
					 | 
				
			||||||
        child_full_name += child_name
 | 
					        child_full_name += child_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return child_full_name
 | 
					        return child_full_name
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,8 +60,33 @@ class ConfigTests(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(abc(), 1)
 | 
					        self.assertEqual(abc(), 1)
 | 
				
			||||||
        self.assertEqual(abd(), 2)
 | 
					        self.assertEqual(abd(), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_providers_with_default_value(self):
 | 
					    def test_providers_value_override(self):
 | 
				
			||||||
 | 
					        a = self.config.a
 | 
				
			||||||
 | 
					        ab = self.config.a.b
 | 
				
			||||||
 | 
					        abc = self.config.a.b.c
 | 
				
			||||||
 | 
					        abd = self.config.a.b.d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.config.override({'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_providers_with_already_overridden_value(self):
 | 
				
			||||||
 | 
					        self.config.override({'a': {'b': {'c': 1, 'd': 2}}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        a = self.config.a
 | 
				
			||||||
 | 
					        ab = self.config.a.b
 | 
				
			||||||
 | 
					        abc = self.config.a.b.c
 | 
				
			||||||
 | 
					        abd = self.config.a.b.d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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_providers_with_default_value(self):
 | 
				
			||||||
        self.config = providers.Configuration(
 | 
					        self.config = providers.Configuration(
 | 
				
			||||||
            name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
 | 
					            name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +100,27 @@ class ConfigTests(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(abc(), 1)
 | 
					        self.assertEqual(abc(), 1)
 | 
				
			||||||
        self.assertEqual(abd(), 2)
 | 
					        self.assertEqual(abd(), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_providers_with_default_value_overriding(self):
 | 
				
			||||||
 | 
					        self.config = providers.Configuration(
 | 
				
			||||||
 | 
					            name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a(), {'b': {'c': 1, 'd': 2}})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b(), {'c': 1, 'd': 2})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b.c(), 1)
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b.d(), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.config.override({'a': {'b': {'c': 3, 'd': 4}}})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a(), {'b': {'c': 3, 'd': 4}})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b(), {'c': 3, 'd': 4})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b.c(), 3)
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b.d(), 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.config.reset_override()
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a(), {'b': {'c': 1, 'd': 2}})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b(), {'c': 1, 'd': 2})
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b.c(), 1)
 | 
				
			||||||
 | 
					        self.assertEqual(self.config.a.b.d(), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_value_of_undefined_option(self):
 | 
					    def test_value_of_undefined_option(self):
 | 
				
			||||||
        self.assertIsNone(self.config.a())
 | 
					        self.assertIsNone(self.config.a())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user