mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-30 15:37:39 +03:00 
			
		
		
		
	Merge branch 'release/3.11.0' into master
This commit is contained in:
		
						commit
						0e50b1d379
					
				|  | @ -351,10 +351,10 @@ Next example demonstrates run of example application defined above: | |||
| 
 | ||||
|     if __name__ == '__main__': | ||||
|         # Configure platform: | ||||
|         Core.config.update({'database': {'dsn': ':memory:'}, | ||||
|                             'aws': {'access_key_id': 'KEY', | ||||
|                                     'secret_access_key': 'SECRET'}, | ||||
|                             'auth': {'token_ttl': 3600}}) | ||||
|         Core.config.override({'database': {'dsn': ':memory:'}, | ||||
|                               'aws': {'access_key_id': 'KEY', | ||||
|                                       'secret_access_key': 'SECRET'}, | ||||
|                               'auth': {'token_ttl': 3600}}) | ||||
|         Core.logger().addHandler(logging.StreamHandler(sys.stdout)) | ||||
| 
 | ||||
|         # Run application: | ||||
|  |  | |||
|  | @ -7,6 +7,13 @@ that were made in every particular version. | |||
| From version 0.7.6 *Dependency Injector* framework strictly  | ||||
| follows `Semantic versioning`_ | ||||
| 
 | ||||
| 3.11.0 | ||||
| ------ | ||||
| - Improve ``Configuration`` provider overriding logic. | ||||
| - Refactor ``Configuration`` provider. | ||||
| - Improve ``DependenciesContainer`` provider overriding logic. | ||||
| - Update "services" example miniapp. | ||||
| - Update "bundles" example miniapp. | ||||
| 
 | ||||
| 3.10.0 | ||||
| ------ | ||||
|  |  | |||
|  | @ -23,8 +23,7 @@ class Core(containers.DeclarativeContainer): | |||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     # Initializing containers | ||||
|     core = Core() | ||||
|     core.config.update({'database': {'dsn': ':memory:'}, | ||||
|     core = Core(config={'database': {'dsn': ':memory:'}, | ||||
|                         'aws': {'access_key_id': 'KEY', | ||||
|                                 'secret_access_key': 'SECRET'}}) | ||||
|     users = Users(database=core.sqlite) | ||||
|  |  | |||
|  | @ -8,10 +8,10 @@ from containers import Core, Application | |||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     # Configure platform: | ||||
|     Core.config.update({'database': {'dsn': ':memory:'}, | ||||
|                         'aws': {'access_key_id': 'KEY', | ||||
|                                 'secret_access_key': 'SECRET'}, | ||||
|                         'auth': {'token_ttl': 3600}}) | ||||
|     Core.config.override({'database': {'dsn': ':memory:'}, | ||||
|                           'aws': {'access_key_id': 'KEY', | ||||
|                                   'secret_access_key': 'SECRET'}, | ||||
|                           'auth': {'token_ttl': 3600}}) | ||||
|     Core.logger().addHandler(logging.StreamHandler(sys.stdout)) | ||||
| 
 | ||||
|     # Run application: | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| """Dependency injector top-level package.""" | ||||
| 
 | ||||
| __version__ = '3.10.0' | ||||
| __version__ = '3.11.0' | ||||
| """Version number that follows semantic versioning. | ||||
| 
 | ||||
| :type: str | ||||
|  |  | |||
										
											
												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 | ||||
| cdef class Configuration(Provider): | ||||
| cdef class Configuration(Object): | ||||
|     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) | ||||
| 
 | ||||
| 
 | ||||
| # Factory providers | ||||
| cdef class Factory(Provider): | ||||
|  |  | |||
|  | @ -427,7 +427,6 @@ cdef class DependenciesContainer(Object): | |||
|     Dependencies container provider is used to implement late static binding | ||||
|     for a set of providers of a particular container. | ||||
| 
 | ||||
| 
 | ||||
|     Example code: | ||||
| 
 | ||||
|     .. code-block:: python | ||||
|  | @ -520,6 +519,29 @@ cdef class DependenciesContainer(Object): | |||
|         self._override_providers(container=provider) | ||||
|         return super(DependenciesContainer, self).override(provider) | ||||
| 
 | ||||
|     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.__providers.values(): | ||||
|             try: | ||||
|                 child.reset_last_overriding() | ||||
|             except Error: | ||||
|                 pass | ||||
|         super(DependenciesContainer, self).reset_last_overriding() | ||||
| 
 | ||||
|     def reset_override(self): | ||||
|         """Reset all overriding providers. | ||||
| 
 | ||||
|         :rtype: None | ||||
|         """ | ||||
|         for child in self.__providers.values(): | ||||
|             child.reset_override() | ||||
|         super(DependenciesContainer, self).reset_override() | ||||
| 
 | ||||
|     cpdef object _override_providers(self, object container): | ||||
|         """Override providers with providers from provided container.""" | ||||
|  | @ -823,7 +845,7 @@ cdef class CallableDelegate(Delegate): | |||
|         super(Delegate, self).__init__(callable) | ||||
| 
 | ||||
| 
 | ||||
| cdef class Configuration(Provider): | ||||
| cdef class Configuration(Object): | ||||
|     """Configuration provider. | ||||
| 
 | ||||
|     Configuration provider helps with implementing late static binding of | ||||
|  | @ -836,8 +858,8 @@ cdef class Configuration(Provider): | |||
|         print(config.section1.option1())  # None | ||||
|         print(config.section1.option2())  # None | ||||
| 
 | ||||
|         config.update({'section1': {'option1': 1, | ||||
|                                     'option2': 2}}) | ||||
|         config.override({'section1': {'option1': 1, | ||||
|                                       'option2': 2}}) | ||||
| 
 | ||||
|         print(config.section1.option1())  # 1 | ||||
|         print(config.section1.option2())  # 2 | ||||
|  | @ -852,12 +874,10 @@ cdef class Configuration(Provider): | |||
|         :param default: Default values of configuration unit. | ||||
|         :type default: dict | ||||
|         """ | ||||
|         super(Configuration, self).__init__(default) | ||||
| 
 | ||||
|         self.__name = name | ||||
|         self.__value = None | ||||
|         self.__children = dict() | ||||
|         if default is not None: | ||||
|             self.update(default) | ||||
|         super(Configuration, self).__init__() | ||||
|         self.__children = self._create_children(default) | ||||
| 
 | ||||
|     def __deepcopy__(self, memo): | ||||
|         """Create and return full copy of provider.""" | ||||
|  | @ -868,7 +888,7 @@ cdef class Configuration(Provider): | |||
|             return copied | ||||
| 
 | ||||
|         copied = self.__class__(self.__name) | ||||
|         copied.__value = deepcopy(self.__value, memo) | ||||
|         copied.__provides = deepcopy(self.__provides, memo) | ||||
|         copied.__children = deepcopy(self.__children, memo) | ||||
| 
 | ||||
|         self._copy_overridings(copied) | ||||
|  | @ -884,9 +904,6 @@ cdef class Configuration(Provider): | |||
| 
 | ||||
|     def __getattr__(self, str name): | ||||
|         """Return child configuration provider.""" | ||||
|         cdef Configuration child_provider | ||||
|         cdef object value | ||||
| 
 | ||||
|         if name.startswith('__') and name.endswith('__'): | ||||
|             raise AttributeError( | ||||
|                 '\'{cls}\' object has no attribute ' | ||||
|  | @ -896,55 +913,103 @@ cdef class Configuration(Provider): | |||
|         child_provider = self.__children.get(name) | ||||
| 
 | ||||
|         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): | ||||
|                 child_provider.update(self.__value.get(name)) | ||||
|             value = self.__call__() | ||||
|             if isinstance(value, dict): | ||||
|                 child_value = value.get(name) | ||||
|                 child_provider.override(child_value) | ||||
| 
 | ||||
|             self.__children[name] = child_provider | ||||
| 
 | ||||
|         return child_provider | ||||
| 
 | ||||
|     cpdef str get_name(self): | ||||
|     def get_name(self): | ||||
|         """Name of configuration unit.""" | ||||
|         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. | ||||
| 
 | ||||
|         .. deprecated:: 3.11 | ||||
| 
 | ||||
|             Use :py:meth:`Configuration.override` instead. | ||||
| 
 | ||||
|         :param value: Value of configuration option. | ||||
|         :type value: object | dict | ||||
| 
 | ||||
|         :rtype: None | ||||
|         """ | ||||
|         cdef Configuration child_provider | ||||
|         cdef object child_value | ||||
|         self.override(value) | ||||
| 
 | ||||
|         self.__value = value | ||||
|     def _create_children(self, value): | ||||
|         children = dict() | ||||
| 
 | ||||
|         if not isinstance(self.__value, dict): | ||||
|             return | ||||
|         if not isinstance(value, dict): | ||||
|             return children | ||||
| 
 | ||||
|         for name in self.__value: | ||||
|             child_provider = self.__children.get(name) | ||||
|         for child_name, child_value in value.items(): | ||||
|             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: | ||||
|                 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 | ||||
|         return children | ||||
| 
 | ||||
|     def _get_child_full_name(self, child_name): | ||||
|         child_full_name = '' | ||||
| 
 | ||||
|         if self.__name: | ||||
|             child_full_name += self.__name + '.' | ||||
| 
 | ||||
|         child_full_name += child_name | ||||
| 
 | ||||
|         return child_full_name | ||||
|  |  | |||
|  | @ -341,6 +341,22 @@ class DependenciesContainerTests(unittest.TestCase): | |||
|         self.assertTrue(dependency.overridden) | ||||
|         self.assertIs(dependency.last_overriding, self.container.dependency) | ||||
| 
 | ||||
|     def test_reset_last_overriding(self): | ||||
|         dependency = self.provider.dependency | ||||
|         self.provider.override(self.container) | ||||
|         self.provider.reset_last_overriding() | ||||
| 
 | ||||
|         self.assertIsNone(dependency.last_overriding) | ||||
|         self.assertIsNone(dependency.last_overriding) | ||||
| 
 | ||||
|     def test_reset_override(self): | ||||
|         dependency = self.provider.dependency | ||||
|         self.provider.override(self.container) | ||||
|         self.provider.reset_override() | ||||
| 
 | ||||
|         self.assertFalse(dependency.overridden) | ||||
|         self.assertFalse(dependency.overridden) | ||||
| 
 | ||||
|     def test_init_with_container_and_providers(self): | ||||
|         provider = providers.DependenciesContainer( | ||||
|             self.container, dependency=providers.Dependency()) | ||||
|  |  | |||
|  | @ -60,8 +60,33 @@ class ConfigTests(unittest.TestCase): | |||
|         self.assertEqual(abc(), 1) | ||||
|         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( | ||||
|             name='config', default={'a': {'b': {'c': 1, 'd': 2}}}) | ||||
| 
 | ||||
|  | @ -75,6 +100,27 @@ class ConfigTests(unittest.TestCase): | |||
|         self.assertEqual(abc(), 1) | ||||
|         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): | ||||
|         self.assertIsNone(self.config.a()) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user