mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-31 07:57:43 +03:00 
			
		
		
		
	Consolidate all containers in container module
This commit is contained in:
		
							parent
							
								
									6f6853eb85
								
							
						
					
					
						commit
						622a6d08e5
					
				|  | @ -11,6 +11,8 @@ Development version | ||||||
| ------------------- | ------------------- | ||||||
| .. - No features. | .. - No features. | ||||||
| 
 | 
 | ||||||
|  | - [Refactoring] Consolidate all containers in | ||||||
|  |   ``dependency_injector.containers`` module. | ||||||
| - [Refactoring] Consolidate all providers in | - [Refactoring] Consolidate all providers in | ||||||
|   ``dependency_injector.providers`` module. |   ``dependency_injector.providers`` module. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -40,12 +40,15 @@ setup(name='dependency-injector', | ||||||
|       install_requires=requirements, |       install_requires=requirements, | ||||||
|       packages=[ |       packages=[ | ||||||
|           'dependency_injector', |           'dependency_injector', | ||||||
|           'dependency_injector.containers', |  | ||||||
|       ], |       ], | ||||||
|       package_dir={ |       package_dir={ | ||||||
|           '': 'src', |           '': 'src', | ||||||
|       }, |       }, | ||||||
|       ext_modules=[ |       ext_modules=[ | ||||||
|  |           Extension('dependency_injector.containers', | ||||||
|  |                     ['src/dependency_injector/containers.c'], | ||||||
|  |                     define_macros=defined_macros, | ||||||
|  |                     extra_compile_args=['-O2']), | ||||||
|           Extension('dependency_injector.providers', |           Extension('dependency_injector.providers', | ||||||
|                     ['src/dependency_injector/providers.c'], |                     ['src/dependency_injector/providers.c'], | ||||||
|                     define_macros=defined_macros, |                     define_macros=defined_macros, | ||||||
|  |  | ||||||
							
								
								
									
										14262
									
								
								src/dependency_injector/containers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14262
									
								
								src/dependency_injector/containers.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										16
									
								
								src/dependency_injector/containers.pxd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/dependency_injector/containers.pxd
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | """Dependency injector containers. | ||||||
|  | 
 | ||||||
|  | Powered by Cython. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | # Declarative containers are declared as regular types because of metaclasses | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Dynamic container | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Utils | ||||||
|  | cpdef bint is_container(object instance) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cpdef object _check_provider_type(object container, object provider) | ||||||
							
								
								
									
										378
									
								
								src/dependency_injector/containers.pyx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								src/dependency_injector/containers.pyx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,378 @@ | ||||||
|  | """Dependency injector containers. | ||||||
|  | 
 | ||||||
|  | Powered by Cython. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | import six | ||||||
|  | 
 | ||||||
|  | from .errors import Error | ||||||
|  | 
 | ||||||
|  | from .providers cimport ( | ||||||
|  |     Provider, | ||||||
|  |     deepcopy, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DynamicContainer(object): | ||||||
|  |     """Dynamic inversion of control container. | ||||||
|  | 
 | ||||||
|  |     .. code-block:: python | ||||||
|  | 
 | ||||||
|  |         services = DynamicContainer() | ||||||
|  |         services.auth = providers.Factory(AuthService) | ||||||
|  |         services.users = providers.Factory(UsersService, | ||||||
|  |                                            auth_service=services.auth) | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: providers | ||||||
|  | 
 | ||||||
|  |         Read-only dictionary of all providers. | ||||||
|  | 
 | ||||||
|  |         :type: dict[str, :py:class:`dependency_injector.providers.Provider`] | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: overridden | ||||||
|  | 
 | ||||||
|  |         Tuple of overriding containers. | ||||||
|  | 
 | ||||||
|  |         :type: tuple[:py:class:`DynamicContainer`] | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provider_type | ||||||
|  | 
 | ||||||
|  |         Type of providers that could be placed in container. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     __IS_CONTAINER__ = True | ||||||
|  | 
 | ||||||
|  |     def __init__(self): | ||||||
|  |         """Initializer. | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         self.provider_type = Provider | ||||||
|  |         self.providers = dict() | ||||||
|  |         self.overridden = tuple() | ||||||
|  |         super(DynamicContainer, self).__init__() | ||||||
|  | 
 | ||||||
|  |     def __setattr__(self, str name, object value): | ||||||
|  |         """Set instance attribute. | ||||||
|  | 
 | ||||||
|  |         If value of attribute is provider, it will be added into providers | ||||||
|  |         dictionary. | ||||||
|  | 
 | ||||||
|  |         :param name: Attribute's name | ||||||
|  |         :type name: str | ||||||
|  | 
 | ||||||
|  |         :param value: Attribute's value | ||||||
|  |         :type value: object | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if isinstance(value, Provider): | ||||||
|  |             _check_provider_type(self, value) | ||||||
|  |             self.providers[name] = value | ||||||
|  |         super(DynamicContainer, self).__setattr__(name, value) | ||||||
|  | 
 | ||||||
|  |     def __delattr__(self, str name): | ||||||
|  |         """Delete instance attribute. | ||||||
|  | 
 | ||||||
|  |         If value of attribute is provider, it will be deleted from providers | ||||||
|  |         dictionary. | ||||||
|  | 
 | ||||||
|  |         :param name: Attribute's name | ||||||
|  |         :type name: str | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if name in self.providers: | ||||||
|  |             del self.providers[name] | ||||||
|  |         super(DynamicContainer, self).__delattr__(name) | ||||||
|  | 
 | ||||||
|  |     def override(self, overriding): | ||||||
|  |         """Override current container by overriding container. | ||||||
|  | 
 | ||||||
|  |         :param overriding: Overriding container. | ||||||
|  |         :type overriding: :py:class:`DynamicContainer` | ||||||
|  | 
 | ||||||
|  |         :raise: :py:exc:`dependency_injector.errors.Error` if trying to | ||||||
|  |                 override container by itself | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if overriding is self: | ||||||
|  |             raise Error('Container {0} could not be overridden ' | ||||||
|  |                         'with itself'.format(self)) | ||||||
|  | 
 | ||||||
|  |         self.overridden += (overriding,) | ||||||
|  | 
 | ||||||
|  |         for name, provider in six.iteritems(overriding.providers): | ||||||
|  |             try: | ||||||
|  |                 getattr(self, name).override(provider) | ||||||
|  |             except AttributeError: | ||||||
|  |                 pass | ||||||
|  | 
 | ||||||
|  |     def reset_last_overriding(self): | ||||||
|  |         """Reset last overriding provider for each container providers. | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if not self.overridden: | ||||||
|  |             raise Error('Container {0} is not overridden'.format(self)) | ||||||
|  | 
 | ||||||
|  |         self.overridden = self.overridden[:-1] | ||||||
|  | 
 | ||||||
|  |         for provider in six.itervalues(self.providers): | ||||||
|  |             provider.reset_last_overriding() | ||||||
|  | 
 | ||||||
|  |     def reset_override(self): | ||||||
|  |         """Reset all overridings for each container providers. | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         self.overridden = tuple() | ||||||
|  | 
 | ||||||
|  |         for provider in six.itervalues(self.providers): | ||||||
|  |             provider.reset_override() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DeclarativeContainerMetaClass(type): | ||||||
|  |     """Declarative inversion of control container meta class.""" | ||||||
|  | 
 | ||||||
|  |     def __new__(mcs, class_name, bases, attributes): | ||||||
|  |         """Declarative container class factory.""" | ||||||
|  |         cls_providers = tuple((name, provider) | ||||||
|  |                               for name, provider in six.iteritems(attributes) | ||||||
|  |                               if isinstance(provider, Provider)) | ||||||
|  | 
 | ||||||
|  |         inherited_providers = tuple((name, provider) | ||||||
|  |                                     for base in bases if is_container( | ||||||
|  |                                         base) and base is not DynamicContainer | ||||||
|  |                                     for name, provider in six.iteritems( | ||||||
|  |                                         base.cls_providers)) | ||||||
|  | 
 | ||||||
|  |         attributes['cls_providers'] = dict(cls_providers) | ||||||
|  |         attributes['inherited_providers'] = dict(inherited_providers) | ||||||
|  |         attributes['providers'] = dict(cls_providers + inherited_providers) | ||||||
|  | 
 | ||||||
|  |         cls = type.__new__(mcs, class_name, bases, attributes) | ||||||
|  | 
 | ||||||
|  |         for provider in six.itervalues(cls.providers): | ||||||
|  |             _check_provider_type(cls, provider) | ||||||
|  | 
 | ||||||
|  |         return cls | ||||||
|  | 
 | ||||||
|  |     def __setattr__(cls, name, value): | ||||||
|  |         """Set class attribute. | ||||||
|  | 
 | ||||||
|  |         If value of attribute is provider, it will be added into providers | ||||||
|  |         dictionary. | ||||||
|  | 
 | ||||||
|  |         :param name: Attribute's name | ||||||
|  |         :type name: str | ||||||
|  | 
 | ||||||
|  |         :param value: Attribute's value | ||||||
|  |         :type value: object | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if isinstance(value, Provider): | ||||||
|  |             _check_provider_type(cls, value) | ||||||
|  |             cls.providers[name] = value | ||||||
|  |             cls.cls_providers[name] = value | ||||||
|  |         super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) | ||||||
|  | 
 | ||||||
|  |     def __delattr__(cls, name): | ||||||
|  |         """Delete class attribute. | ||||||
|  | 
 | ||||||
|  |         If value of attribute is provider, it will be deleted from providers | ||||||
|  |         dictionary. | ||||||
|  | 
 | ||||||
|  |         :param name: Attribute's name | ||||||
|  |         :type name: str | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if name in cls.providers and name in cls.cls_providers: | ||||||
|  |             del cls.providers[name] | ||||||
|  |             del cls.cls_providers[name] | ||||||
|  |         super(DeclarativeContainerMetaClass, cls).__delattr__(name) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @six.add_metaclass(DeclarativeContainerMetaClass) | ||||||
|  | class DeclarativeContainer(object): | ||||||
|  |     """Declarative inversion of control container. | ||||||
|  | 
 | ||||||
|  |     .. code-block:: python | ||||||
|  | 
 | ||||||
|  |         class Services(DeclarativeContainer): | ||||||
|  |             auth = providers.Factory(AuthService) | ||||||
|  |             users = providers.Factory(UsersService, | ||||||
|  |                                       auth_service=auth) | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     __IS_CONTAINER__ = True | ||||||
|  | 
 | ||||||
|  |     provider_type = Provider | ||||||
|  |     """Type of providers that could be placed in container. | ||||||
|  | 
 | ||||||
|  |     :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     instance_type = DynamicContainer | ||||||
|  |     """Type of container that is returned on instantiating declarative | ||||||
|  |     container. | ||||||
|  | 
 | ||||||
|  |     :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     providers = dict() | ||||||
|  |     """Read-only dictionary of all providers. | ||||||
|  | 
 | ||||||
|  |     :type: dict[str, :py:class:`dependency_injector.providers.Provider`] | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     cls_providers = dict() | ||||||
|  |     """Read-only dictionary of current container providers. | ||||||
|  | 
 | ||||||
|  |     :type: dict[str, :py:class:`dependency_injector.providers.Provider`] | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     inherited_providers = dict() | ||||||
|  |     """Read-only dictionary of inherited providers. | ||||||
|  | 
 | ||||||
|  |     :type: dict[str, :py:class:`dependency_injector.providers.Provider`] | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     overridden = tuple() | ||||||
|  |     """Tuple of overriding containers. | ||||||
|  | 
 | ||||||
|  |     :type: tuple[:py:class:`DeclarativeContainer`] | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __new__(cls, *args, **kwargs): | ||||||
|  |         """Constructor. | ||||||
|  | 
 | ||||||
|  |         :return: Dynamic container with copy of all providers. | ||||||
|  |         :rtype: :py:class:`DynamicContainer` | ||||||
|  |         """ | ||||||
|  |         container = cls.instance_type(*args, **kwargs) | ||||||
|  |         container.provider_type = cls.provider_type | ||||||
|  | 
 | ||||||
|  |         for name, provider in six.iteritems(deepcopy(cls.providers)): | ||||||
|  |             setattr(container, name, provider) | ||||||
|  | 
 | ||||||
|  |         return container | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def override(cls, overriding): | ||||||
|  |         """Override current container by overriding container. | ||||||
|  | 
 | ||||||
|  |         :param overriding: Overriding container. | ||||||
|  |         :type overriding: :py:class:`DeclarativeContainer` | ||||||
|  | 
 | ||||||
|  |         :raise: :py:exc:`dependency_injector.errors.Error` if trying to | ||||||
|  |                 override container by itself or its subclasses | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if issubclass(cls, overriding): | ||||||
|  |             raise Error('Container {0} could not be overridden ' | ||||||
|  |                         'with itself or its subclasses'.format(cls)) | ||||||
|  | 
 | ||||||
|  |         cls.overridden += (overriding,) | ||||||
|  | 
 | ||||||
|  |         for name, provider in six.iteritems(overriding.cls_providers): | ||||||
|  |             try: | ||||||
|  |                 getattr(cls, name).override(provider) | ||||||
|  |             except AttributeError: | ||||||
|  |                 pass | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def reset_last_overriding(cls): | ||||||
|  |         """Reset last overriding provider for each container providers. | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         if not cls.overridden: | ||||||
|  |             raise Error('Container {0} is not overridden'.format(cls)) | ||||||
|  | 
 | ||||||
|  |         cls.overridden = cls.overridden[:-1] | ||||||
|  | 
 | ||||||
|  |         for provider in six.itervalues(cls.providers): | ||||||
|  |             provider.reset_last_overriding() | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def reset_override(cls): | ||||||
|  |         """Reset all overridings for each container providers. | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         cls.overridden = tuple() | ||||||
|  | 
 | ||||||
|  |         for provider in six.itervalues(cls.providers): | ||||||
|  |             provider.reset_override() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def override(object container): | ||||||
|  |     """:py:class:`DeclarativeContainer` overriding decorator. | ||||||
|  | 
 | ||||||
|  |     :param container: Container that should be overridden by decorated | ||||||
|  |                       container. | ||||||
|  |     :type container: :py:class:`DeclarativeContainer` | ||||||
|  | 
 | ||||||
|  |     :return: Declarative container's overriding decorator. | ||||||
|  |     :rtype: callable(:py:class:`DeclarativeContainer`) | ||||||
|  |     """ | ||||||
|  |     def _decorator(overriding_container): | ||||||
|  |         """Overriding decorator.""" | ||||||
|  |         container.override(overriding_container) | ||||||
|  |         return overriding_container | ||||||
|  |     return _decorator | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def copy(object container): | ||||||
|  |     """:py:class:`DeclarativeContainer` copying decorator. | ||||||
|  | 
 | ||||||
|  |     This decorator copy all providers from provided container to decorated one. | ||||||
|  |     If one of the decorated container providers matches to source container | ||||||
|  |     providers by name, it would be replaced by reference. | ||||||
|  | 
 | ||||||
|  |     :param container: Container that should be copied by decorated container. | ||||||
|  |     :type container: :py:class:`DeclarativeContainer` | ||||||
|  | 
 | ||||||
|  |     :return: Declarative container's copying decorator. | ||||||
|  |     :rtype: callable(:py:class:`DeclarativeContainer`) | ||||||
|  |     """ | ||||||
|  |     def _decorator(copied_container): | ||||||
|  |         memo = dict() | ||||||
|  |         for name, provider in six.iteritems(copied_container.cls_providers): | ||||||
|  |             try: | ||||||
|  |                 source_provider = getattr(container, name) | ||||||
|  |             except AttributeError: | ||||||
|  |                 pass | ||||||
|  |             else: | ||||||
|  |                 memo[id(source_provider)] = provider | ||||||
|  | 
 | ||||||
|  |         providers_copy = deepcopy(container.providers, memo) | ||||||
|  |         for name, provider in six.iteritems(providers_copy): | ||||||
|  |             setattr(copied_container, name, provider) | ||||||
|  | 
 | ||||||
|  |         return copied_container | ||||||
|  |     return _decorator | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cpdef bint is_container(object instance): | ||||||
|  |     """Check if instance is container instance. | ||||||
|  | 
 | ||||||
|  |     :param instance: Instance to be checked. | ||||||
|  |     :type instance: object | ||||||
|  | 
 | ||||||
|  |     :rtype: bool | ||||||
|  |     """ | ||||||
|  |     return getattr(instance, '__IS_CONTAINER__', False) is True | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cpdef object _check_provider_type(object container, object provider): | ||||||
|  |     if not isinstance(provider, container.provider_type): | ||||||
|  |         raise Error('{0} can contain only {1} ' | ||||||
|  |                     'instances'.format(container, container.provider_type)) | ||||||
|  | @ -1,36 +0,0 @@ | ||||||
| """Dependency injector containers.""" |  | ||||||
| 
 |  | ||||||
| from .declarative import ( |  | ||||||
|     DeclarativeContainerMetaClass, |  | ||||||
|     DeclarativeContainer, |  | ||||||
| ) |  | ||||||
| from .dynamic import ( |  | ||||||
|     DynamicContainer, |  | ||||||
| ) |  | ||||||
| from .utils import ( |  | ||||||
|     is_container, |  | ||||||
|     override, |  | ||||||
|     copy, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Set package name as a name of module for all public members of this package: |  | ||||||
| for item in (DeclarativeContainerMetaClass, |  | ||||||
|              DeclarativeContainer, |  | ||||||
|              DynamicContainer, |  | ||||||
|              is_container, |  | ||||||
|              override, |  | ||||||
|              copy,): |  | ||||||
|     item.__module__ = __name__ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     'DeclarativeContainerMetaClass', |  | ||||||
|     'DeclarativeContainer', |  | ||||||
| 
 |  | ||||||
|     'DynamicContainer', |  | ||||||
| 
 |  | ||||||
|     'is_container', |  | ||||||
|     'override', |  | ||||||
|     'copy', |  | ||||||
| ) |  | ||||||
|  | @ -1,191 +0,0 @@ | ||||||
| """Dependency injector declarative container.""" |  | ||||||
| 
 |  | ||||||
| import six |  | ||||||
| 
 |  | ||||||
| from dependency_injector.providers import Provider |  | ||||||
| from dependency_injector.errors import Error |  | ||||||
| 
 |  | ||||||
| from .dynamic import DynamicContainer |  | ||||||
| from .utils import ( |  | ||||||
|     is_container, |  | ||||||
|     deepcopy, |  | ||||||
|     _check_provider_type, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DeclarativeContainerMetaClass(type): |  | ||||||
|     """Declarative inversion of control container meta class.""" |  | ||||||
| 
 |  | ||||||
|     def __new__(mcs, class_name, bases, attributes): |  | ||||||
|         """Declarative container class factory.""" |  | ||||||
|         cls_providers = tuple((name, provider) |  | ||||||
|                               for name, provider in six.iteritems(attributes) |  | ||||||
|                               if isinstance(provider, Provider)) |  | ||||||
| 
 |  | ||||||
|         inherited_providers = tuple((name, provider) |  | ||||||
|                                     for base in bases if is_container( |  | ||||||
|                                         base) and base is not DynamicContainer |  | ||||||
|                                     for name, provider in six.iteritems( |  | ||||||
|                                         base.cls_providers)) |  | ||||||
| 
 |  | ||||||
|         attributes['cls_providers'] = dict(cls_providers) |  | ||||||
|         attributes['inherited_providers'] = dict(inherited_providers) |  | ||||||
|         attributes['providers'] = dict(cls_providers + inherited_providers) |  | ||||||
| 
 |  | ||||||
|         cls = type.__new__(mcs, class_name, bases, attributes) |  | ||||||
| 
 |  | ||||||
|         for provider in six.itervalues(cls.providers): |  | ||||||
|             _check_provider_type(cls, provider) |  | ||||||
| 
 |  | ||||||
|         return cls |  | ||||||
| 
 |  | ||||||
|     def __setattr__(cls, name, value): |  | ||||||
|         """Set class attribute. |  | ||||||
| 
 |  | ||||||
|         If value of attribute is provider, it will be added into providers |  | ||||||
|         dictionary. |  | ||||||
| 
 |  | ||||||
|         :param name: Attribute's name |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param value: Attribute's value |  | ||||||
|         :type value: object |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if isinstance(value, Provider): |  | ||||||
|             _check_provider_type(cls, value) |  | ||||||
|             cls.providers[name] = value |  | ||||||
|             cls.cls_providers[name] = value |  | ||||||
|         super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) |  | ||||||
| 
 |  | ||||||
|     def __delattr__(cls, name): |  | ||||||
|         """Delete class attribute. |  | ||||||
| 
 |  | ||||||
|         If value of attribute is provider, it will be deleted from providers |  | ||||||
|         dictionary. |  | ||||||
| 
 |  | ||||||
|         :param name: Attribute's name |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if name in cls.providers and name in cls.cls_providers: |  | ||||||
|             del cls.providers[name] |  | ||||||
|             del cls.cls_providers[name] |  | ||||||
|         super(DeclarativeContainerMetaClass, cls).__delattr__(name) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @six.add_metaclass(DeclarativeContainerMetaClass) |  | ||||||
| class DeclarativeContainer(object): |  | ||||||
|     """Declarative inversion of control container. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: python |  | ||||||
| 
 |  | ||||||
|         class Services(DeclarativeContainer): |  | ||||||
|             auth = providers.Factory(AuthService) |  | ||||||
|             users = providers.Factory(UsersService, |  | ||||||
|                                       auth_service=auth) |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     __IS_CONTAINER__ = True |  | ||||||
| 
 |  | ||||||
|     provider_type = Provider |  | ||||||
|     """Type of providers that could be placed in container. |  | ||||||
| 
 |  | ||||||
|     :type: type |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     instance_type = DynamicContainer |  | ||||||
|     """Type of container that is returned on instantiating declarative |  | ||||||
|     container. |  | ||||||
| 
 |  | ||||||
|     :type: type |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     providers = dict() |  | ||||||
|     """Read-only dictionary of all providers. |  | ||||||
| 
 |  | ||||||
|     :type: dict[str, :py:class:`dependency_injector.providers.Provider`] |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     cls_providers = dict() |  | ||||||
|     """Read-only dictionary of current container providers. |  | ||||||
| 
 |  | ||||||
|     :type: dict[str, :py:class:`dependency_injector.providers.Provider`] |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     inherited_providers = dict() |  | ||||||
|     """Read-only dictionary of inherited providers. |  | ||||||
| 
 |  | ||||||
|     :type: dict[str, :py:class:`dependency_injector.providers.Provider`] |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     overridden = tuple() |  | ||||||
|     """Tuple of overriding containers. |  | ||||||
| 
 |  | ||||||
|     :type: tuple[:py:class:`DeclarativeContainer`] |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __new__(cls, *args, **kwargs): |  | ||||||
|         """Constructor. |  | ||||||
| 
 |  | ||||||
|         :return: Dynamic container with copy of all providers. |  | ||||||
|         :rtype: :py:class:`DynamicContainer` |  | ||||||
|         """ |  | ||||||
|         container = cls.instance_type(*args, **kwargs) |  | ||||||
|         container.provider_type = cls.provider_type |  | ||||||
| 
 |  | ||||||
|         for name, provider in six.iteritems(deepcopy(cls.providers)): |  | ||||||
|             setattr(container, name, provider) |  | ||||||
| 
 |  | ||||||
|         return container |  | ||||||
| 
 |  | ||||||
|     @classmethod |  | ||||||
|     def override(cls, overriding): |  | ||||||
|         """Override current container by overriding container. |  | ||||||
| 
 |  | ||||||
|         :param overriding: Overriding container. |  | ||||||
|         :type overriding: :py:class:`DeclarativeContainer` |  | ||||||
| 
 |  | ||||||
|         :raise: :py:exc:`dependency_injector.errors.Error` if trying to |  | ||||||
|                 override container by itself or its subclasses |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if issubclass(cls, overriding): |  | ||||||
|             raise Error('Container {0} could not be overridden ' |  | ||||||
|                         'with itself or its subclasses'.format(cls)) |  | ||||||
| 
 |  | ||||||
|         cls.overridden += (overriding,) |  | ||||||
| 
 |  | ||||||
|         for name, provider in six.iteritems(overriding.cls_providers): |  | ||||||
|             try: |  | ||||||
|                 getattr(cls, name).override(provider) |  | ||||||
|             except AttributeError: |  | ||||||
|                 pass |  | ||||||
| 
 |  | ||||||
|     @classmethod |  | ||||||
|     def reset_last_overriding(cls): |  | ||||||
|         """Reset last overriding provider for each container providers. |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if not cls.overridden: |  | ||||||
|             raise Error('Container {0} is not overridden'.format(cls)) |  | ||||||
| 
 |  | ||||||
|         cls.overridden = cls.overridden[:-1] |  | ||||||
| 
 |  | ||||||
|         for provider in six.itervalues(cls.providers): |  | ||||||
|             provider.reset_last_overriding() |  | ||||||
| 
 |  | ||||||
|     @classmethod |  | ||||||
|     def reset_override(cls): |  | ||||||
|         """Reset all overridings for each container providers. |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         cls.overridden = tuple() |  | ||||||
| 
 |  | ||||||
|         for provider in six.itervalues(cls.providers): |  | ||||||
|             provider.reset_override() |  | ||||||
|  | @ -1,130 +0,0 @@ | ||||||
| """Dependency injector dynamic container.""" |  | ||||||
| 
 |  | ||||||
| import six |  | ||||||
| 
 |  | ||||||
| from dependency_injector.providers import Provider |  | ||||||
| from dependency_injector.errors import Error |  | ||||||
| 
 |  | ||||||
| from .utils import _check_provider_type |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DynamicContainer(object): |  | ||||||
|     """Dynamic inversion of control container. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: python |  | ||||||
| 
 |  | ||||||
|         services = DynamicContainer() |  | ||||||
|         services.auth = providers.Factory(AuthService) |  | ||||||
|         services.users = providers.Factory(UsersService, |  | ||||||
|                                            auth_service=services.auth) |  | ||||||
| 
 |  | ||||||
|     .. py:attribute:: providers |  | ||||||
| 
 |  | ||||||
|         Read-only dictionary of all providers. |  | ||||||
| 
 |  | ||||||
|         :type: dict[str, :py:class:`dependency_injector.providers.Provider`] |  | ||||||
| 
 |  | ||||||
|     .. py:attribute:: overridden |  | ||||||
| 
 |  | ||||||
|         Tuple of overriding containers. |  | ||||||
| 
 |  | ||||||
|         :type: tuple[:py:class:`DynamicContainer`] |  | ||||||
| 
 |  | ||||||
|     .. py:attribute:: provider_type |  | ||||||
| 
 |  | ||||||
|         Type of providers that could be placed in container. |  | ||||||
| 
 |  | ||||||
|         :type: type |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     __IS_CONTAINER__ = True |  | ||||||
| 
 |  | ||||||
|     def __init__(self): |  | ||||||
|         """Initializer. |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         self.provider_type = Provider |  | ||||||
|         self.providers = dict() |  | ||||||
|         self.overridden = tuple() |  | ||||||
|         super(DynamicContainer, self).__init__() |  | ||||||
| 
 |  | ||||||
|     def __setattr__(self, name, value): |  | ||||||
|         """Set instance attribute. |  | ||||||
| 
 |  | ||||||
|         If value of attribute is provider, it will be added into providers |  | ||||||
|         dictionary. |  | ||||||
| 
 |  | ||||||
|         :param name: Attribute's name |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param value: Attribute's value |  | ||||||
|         :type value: object |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if isinstance(value, Provider): |  | ||||||
|             _check_provider_type(self, value) |  | ||||||
|             self.providers[name] = value |  | ||||||
|         super(DynamicContainer, self).__setattr__(name, value) |  | ||||||
| 
 |  | ||||||
|     def __delattr__(self, name): |  | ||||||
|         """Delete instance attribute. |  | ||||||
| 
 |  | ||||||
|         If value of attribute is provider, it will be deleted from providers |  | ||||||
|         dictionary. |  | ||||||
| 
 |  | ||||||
|         :param name: Attribute's name |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if name in self.providers: |  | ||||||
|             del self.providers[name] |  | ||||||
|         super(DynamicContainer, self).__delattr__(name) |  | ||||||
| 
 |  | ||||||
|     def override(self, overriding): |  | ||||||
|         """Override current container by overriding container. |  | ||||||
| 
 |  | ||||||
|         :param overriding: Overriding container. |  | ||||||
|         :type overriding: :py:class:`DynamicContainer` |  | ||||||
| 
 |  | ||||||
|         :raise: :py:exc:`dependency_injector.errors.Error` if trying to |  | ||||||
|                 override container by itself |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if overriding is self: |  | ||||||
|             raise Error('Container {0} could not be overridden ' |  | ||||||
|                         'with itself'.format(self)) |  | ||||||
| 
 |  | ||||||
|         self.overridden += (overriding,) |  | ||||||
| 
 |  | ||||||
|         for name, provider in six.iteritems(overriding.providers): |  | ||||||
|             try: |  | ||||||
|                 getattr(self, name).override(provider) |  | ||||||
|             except AttributeError: |  | ||||||
|                 pass |  | ||||||
| 
 |  | ||||||
|     def reset_last_overriding(self): |  | ||||||
|         """Reset last overriding provider for each container providers. |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         if not self.overridden: |  | ||||||
|             raise Error('Container {0} is not overridden'.format(self)) |  | ||||||
| 
 |  | ||||||
|         self.overridden = self.overridden[:-1] |  | ||||||
| 
 |  | ||||||
|         for provider in six.itervalues(self.providers): |  | ||||||
|             provider.reset_last_overriding() |  | ||||||
| 
 |  | ||||||
|     def reset_override(self): |  | ||||||
|         """Reset all overridings for each container providers. |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         self.overridden = tuple() |  | ||||||
| 
 |  | ||||||
|         for provider in six.itervalues(self.providers): |  | ||||||
|             provider.reset_override() |  | ||||||
|  | @ -1,72 +0,0 @@ | ||||||
| """Dependency injector container utils.""" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import six |  | ||||||
| 
 |  | ||||||
| from dependency_injector.providers import deepcopy |  | ||||||
| from dependency_injector.errors import Error |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def is_container(instance): |  | ||||||
|     """Check if instance is container instance. |  | ||||||
| 
 |  | ||||||
|     :param instance: Instance to be checked. |  | ||||||
|     :type instance: object |  | ||||||
| 
 |  | ||||||
|     :rtype: bool |  | ||||||
|     """ |  | ||||||
|     return getattr(instance, '__IS_CONTAINER__', False) is True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def override(container): |  | ||||||
|     """:py:class:`DeclarativeContainer` overriding decorator. |  | ||||||
| 
 |  | ||||||
|     :param container: Container that should be overridden by decorated |  | ||||||
|                       container. |  | ||||||
|     :type container: :py:class:`DeclarativeContainer` |  | ||||||
| 
 |  | ||||||
|     :return: Declarative container's overriding decorator. |  | ||||||
|     :rtype: callable(:py:class:`DeclarativeContainer`) |  | ||||||
|     """ |  | ||||||
|     def _decorator(overriding_container): |  | ||||||
|         """Overriding decorator.""" |  | ||||||
|         container.override(overriding_container) |  | ||||||
|         return overriding_container |  | ||||||
|     return _decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def copy(container): |  | ||||||
|     """:py:class:`DeclarativeContainer` copying decorator. |  | ||||||
| 
 |  | ||||||
|     This decorator copy all providers from provided container to decorated one. |  | ||||||
|     If one of the decorated container providers matches to source container |  | ||||||
|     providers by name, it would be replaced by reference. |  | ||||||
| 
 |  | ||||||
|     :param container: Container that should be copied by decorated container. |  | ||||||
|     :type container: :py:class:`DeclarativeContainer` |  | ||||||
| 
 |  | ||||||
|     :return: Declarative container's copying decorator. |  | ||||||
|     :rtype: callable(:py:class:`DeclarativeContainer`) |  | ||||||
|     """ |  | ||||||
|     def _decorator(copied_container): |  | ||||||
|         memo = dict() |  | ||||||
|         for name, provider in six.iteritems(copied_container.cls_providers): |  | ||||||
|             try: |  | ||||||
|                 source_provider = getattr(container, name) |  | ||||||
|             except AttributeError: |  | ||||||
|                 pass |  | ||||||
|             else: |  | ||||||
|                 memo[id(source_provider)] = provider |  | ||||||
| 
 |  | ||||||
|         providers_copy = deepcopy(container.providers, memo) |  | ||||||
|         for name, provider in six.iteritems(providers_copy): |  | ||||||
|             setattr(copied_container, name, provider) |  | ||||||
| 
 |  | ||||||
|         return copied_container |  | ||||||
|     return _decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _check_provider_type(cls, provider): |  | ||||||
|     if not isinstance(provider, cls.provider_type): |  | ||||||
|         raise Error('{0} can contain only {1} ' |  | ||||||
|                     'instances'.format(cls, cls.provider_type)) |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user