mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-31 16:07:51 +03:00 
			
		
		
		
	Make providers stable
This commit is contained in:
		
							parent
							
								
									322ba98f18
								
							
						
					
					
						commit
						7b61464c93
					
				
							
								
								
									
										4
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -63,10 +63,6 @@ setup(name='dependency-injector', | ||||||
|                     ['src/dependency_injector/providers/singletons.c'], |                     ['src/dependency_injector/providers/singletons.c'], | ||||||
|                     define_macros=defined_macros, |                     define_macros=defined_macros, | ||||||
|                     extra_compile_args=['-O2']), |                     extra_compile_args=['-O2']), | ||||||
|           Extension('dependency_injector.providers.static', |  | ||||||
|                     ['src/dependency_injector/providers/static.c'], |  | ||||||
|                     define_macros=defined_macros, |  | ||||||
|                     extra_compile_args=['-O2']), |  | ||||||
|           Extension('dependency_injector.providers.injections', |           Extension('dependency_injector.providers.injections', | ||||||
|                     ['src/dependency_injector/providers/injections.c'], |                     ['src/dependency_injector/providers/injections.c'], | ||||||
|                     define_macros=defined_macros, |                     define_macros=defined_macros, | ||||||
|  |  | ||||||
|  | @ -1,20 +1,12 @@ | ||||||
| """Dependency injector container utils.""" | """Dependency injector container utils.""" | ||||||
| 
 | 
 | ||||||
| import copy as _copy |  | ||||||
| import types |  | ||||||
| 
 | 
 | ||||||
| import six | import six | ||||||
| 
 | 
 | ||||||
|  | from dependency_injector.providers import deepcopy | ||||||
| from dependency_injector.errors import Error | from dependency_injector.errors import Error | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if six.PY2:  # pragma: no cover |  | ||||||
|     _copy._deepcopy_dispatch[types.MethodType] = \ |  | ||||||
|         lambda obj, memo: type(obj)(obj.im_func, |  | ||||||
|                                     _copy.deepcopy(obj.im_self, memo), |  | ||||||
|                                     obj.im_class) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def is_container(instance): | def is_container(instance): | ||||||
|     """Check if instance is container instance. |     """Check if instance is container instance. | ||||||
| 
 | 
 | ||||||
|  | @ -74,11 +66,6 @@ def copy(container): | ||||||
|     return _decorator |     return _decorator | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def deepcopy(instance, memo=None): |  | ||||||
|     """Make full copy of instance.""" |  | ||||||
|     return _copy.deepcopy(instance, memo) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _check_provider_type(cls, provider): | def _check_provider_type(cls, provider): | ||||||
|     if not isinstance(provider, cls.provider_type): |     if not isinstance(provider, cls.provider_type): | ||||||
|         raise Error('{0} can contain only {1} ' |         raise Error('{0} can contain only {1} ' | ||||||
|  |  | ||||||
|  | @ -2,6 +2,10 @@ | ||||||
| 
 | 
 | ||||||
| from .base import ( | from .base import ( | ||||||
|     Provider, |     Provider, | ||||||
|  |     Object, | ||||||
|  |     Delegate, | ||||||
|  |     ExternalDependency, | ||||||
|  |     OverridingContext, | ||||||
| ) | ) | ||||||
| from .callables import ( | from .callables import ( | ||||||
|     Callable, |     Callable, | ||||||
|  | @ -23,27 +27,26 @@ from .singletons import ( | ||||||
|     ThreadLocalSingleton, |     ThreadLocalSingleton, | ||||||
|     DelegatedThreadLocalSingleton, |     DelegatedThreadLocalSingleton, | ||||||
| ) | ) | ||||||
| from .static import ( |  | ||||||
|     Object, |  | ||||||
|     Delegate, |  | ||||||
|     ExternalDependency, |  | ||||||
| ) |  | ||||||
| from .injections import ( | from .injections import ( | ||||||
|     Injection, |     Injection, | ||||||
|     PositionalInjection, |     PositionalInjection, | ||||||
|     NamedInjection, |     NamedInjection, | ||||||
| ) | ) | ||||||
| from .utils import ( | from .utils import ( | ||||||
|     OverridingContext, |  | ||||||
|     is_provider, |     is_provider, | ||||||
|     ensure_is_provider, |     ensure_is_provider, | ||||||
|     is_delegated, |     is_delegated, | ||||||
|     represent_provider, |     represent_provider, | ||||||
|  |     deepcopy, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| __all__ = ( | __all__ = ( | ||||||
|     'Provider', |     'Provider', | ||||||
|  |     'Object', | ||||||
|  |     'Delegate', | ||||||
|  |     'ExternalDependency', | ||||||
|  |     'OverridingContext', | ||||||
| 
 | 
 | ||||||
|     'Callable', |     'Callable', | ||||||
|     'DelegatedCallable', |     'DelegatedCallable', | ||||||
|  | @ -62,17 +65,13 @@ __all__ = ( | ||||||
|     'ThreadLocalSingleton', |     'ThreadLocalSingleton', | ||||||
|     'DelegatedThreadLocalSingleton', |     'DelegatedThreadLocalSingleton', | ||||||
| 
 | 
 | ||||||
|     'Object', |  | ||||||
|     'Delegate', |  | ||||||
|     'ExternalDependency', |  | ||||||
| 
 |  | ||||||
|     'Injection', |     'Injection', | ||||||
|     'PositionalInjection', |     'PositionalInjection', | ||||||
|     'NamedInjection', |     'NamedInjection', | ||||||
| 
 | 
 | ||||||
|     'OverridingContext', |  | ||||||
|     'is_provider', |     'is_provider', | ||||||
|     'ensure_is_provider', |     'ensure_is_provider', | ||||||
|     'is_delegated', |     'is_delegated', | ||||||
|     'represent_provider', |     'represent_provider', | ||||||
|  |     'deepcopy', | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -10,3 +10,22 @@ cdef class Provider(object): | ||||||
| 
 | 
 | ||||||
|     cpdef object _provide(self, tuple args, dict kwargs) |     cpdef object _provide(self, tuple args, dict kwargs) | ||||||
|     cpdef object _call_last_overriding(self, tuple args, dict kwargs) |     cpdef object _call_last_overriding(self, tuple args, dict kwargs) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class Object(Provider): | ||||||
|  |     cdef object __provides | ||||||
|  | 
 | ||||||
|  |     cpdef object _provide(self, tuple args, dict kwargs) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class Delegate(Object): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class ExternalDependency(Provider): | ||||||
|  |     cdef type __instance_of | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class OverridingContext(object): | ||||||
|  |     cdef Provider __overridden | ||||||
|  |     cdef Provider __overriding | ||||||
|  |  | ||||||
|  | @ -7,15 +7,12 @@ cimport cython | ||||||
| 
 | 
 | ||||||
| from dependency_injector.errors import Error | from dependency_injector.errors import Error | ||||||
| 
 | 
 | ||||||
| from .static cimport ( |  | ||||||
|     Object, |  | ||||||
|     Delegate, |  | ||||||
| ) |  | ||||||
| from .utils cimport ( | from .utils cimport ( | ||||||
|  |     CLASS_TYPES, | ||||||
|     is_provider, |     is_provider, | ||||||
|     ensure_is_provider, |     ensure_is_provider, | ||||||
|     represent_provider, |     represent_provider, | ||||||
|     OverridingContext, |     deepcopy, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -83,6 +80,19 @@ cdef class Provider(object): | ||||||
|             return self._call_last_overriding(args, kwargs) |             return self._call_last_overriding(args, kwargs) | ||||||
|         return self._provide(args, kwargs) |         return self._provide(args, kwargs) | ||||||
| 
 | 
 | ||||||
|  |     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__() | ||||||
|  | 
 | ||||||
|  |         for overriding_provider in self.overridden: | ||||||
|  |             copied.override(deepcopy(overriding_provider, memo)) | ||||||
|  | 
 | ||||||
|  |         return copied | ||||||
|  | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         """Return string representation of provider. |         """Return string representation of provider. | ||||||
| 
 | 
 | ||||||
|  | @ -173,3 +183,214 @@ cdef class Provider(object): | ||||||
|             return None |             return None | ||||||
|         return  <object>self.__overridden[self.__overridden_len - 1](*args, |         return  <object>self.__overridden[self.__overridden_len - 1](*args, | ||||||
|                                                                      **kwargs) |                                                                      **kwargs) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class Object(Provider): | ||||||
|  |     """Object provider returns provided instance "as is". | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provides | ||||||
|  | 
 | ||||||
|  |         Value that have to be provided. | ||||||
|  | 
 | ||||||
|  |         :type: object | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, provides): | ||||||
|  |         """Initializer. | ||||||
|  | 
 | ||||||
|  |         :param provides: Value that have to be provided. | ||||||
|  |         :type provides: object | ||||||
|  |         """ | ||||||
|  |         self.__provides = provides | ||||||
|  |         super(Object, 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__(deepcopy(self.__provides, memo)) | ||||||
|  | 
 | ||||||
|  |         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.__provides) | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         """Return string representation of provider. | ||||||
|  | 
 | ||||||
|  |         :rtype: str | ||||||
|  |         """ | ||||||
|  |         return self.__str__() | ||||||
|  | 
 | ||||||
|  |     cpdef object _provide(self, tuple args, dict kwargs): | ||||||
|  |         """Return provided instance. | ||||||
|  | 
 | ||||||
|  |         :param args: Tuple of context positional arguments. | ||||||
|  |         :type args: tuple[object] | ||||||
|  | 
 | ||||||
|  |         :param kwargs: Dictionary of context keyword arguments. | ||||||
|  |         :type kwargs: dict[str, object] | ||||||
|  | 
 | ||||||
|  |         :rtype: object | ||||||
|  |         """ | ||||||
|  |         return self.__provides | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class Delegate(Object): | ||||||
|  |     """Delegate provider returns provider "as is". | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provides | ||||||
|  | 
 | ||||||
|  |         Value that have to be provided. | ||||||
|  | 
 | ||||||
|  |         :type: object | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, provides): | ||||||
|  |         """Initializer. | ||||||
|  | 
 | ||||||
|  |         :param provides: Value that have to be provided. | ||||||
|  |         :type provides: object | ||||||
|  |         """ | ||||||
|  |         super(Delegate, self).__init__(ensure_is_provider(provides)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class ExternalDependency(Provider): | ||||||
|  |     """:py:class:`ExternalDependency` provider describes dependency interface. | ||||||
|  | 
 | ||||||
|  |     This provider is used for description of dependency interface. That might | ||||||
|  |     be useful when dependency could be provided in the client's code only, | ||||||
|  |     but it's interface is known. Such situations could happen when required | ||||||
|  |     dependency has non-determenistic list of dependencies itself. | ||||||
|  | 
 | ||||||
|  |     .. code-block:: python | ||||||
|  | 
 | ||||||
|  |         database_provider = ExternalDependency(sqlite3.dbapi2.Connection) | ||||||
|  |         database_provider.override(Factory(sqlite3.connect, ':memory:')) | ||||||
|  | 
 | ||||||
|  |         database = database_provider() | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: instance_of | ||||||
|  | 
 | ||||||
|  |         Class of required dependency. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, type instance_of): | ||||||
|  |         """Initializer.""" | ||||||
|  |         self.__instance_of = instance_of | ||||||
|  |         super(ExternalDependency, 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.__instance_of) | ||||||
|  | 
 | ||||||
|  |         for overriding_provider in self.overridden: | ||||||
|  |             copied.override(deepcopy(overriding_provider, memo)) | ||||||
|  | 
 | ||||||
|  |         return copied | ||||||
|  | 
 | ||||||
|  |     def __call__(self, *args, **kwargs): | ||||||
|  |         """Return provided instance. | ||||||
|  | 
 | ||||||
|  |         :param args: Tuple of context positional arguments. | ||||||
|  |         :type args: tuple[object] | ||||||
|  | 
 | ||||||
|  |         :param kwargs: Dictionary of context keyword arguments. | ||||||
|  |         :type kwargs: dict[str, object] | ||||||
|  | 
 | ||||||
|  |         :raise: :py:exc:`dependency_injector.errors.Error` | ||||||
|  | 
 | ||||||
|  |         :rtype: object | ||||||
|  |         """ | ||||||
|  |         cdef object instance | ||||||
|  | 
 | ||||||
|  |         if self.__overridden_len == 0: | ||||||
|  |             raise Error('Dependency is not defined') | ||||||
|  | 
 | ||||||
|  |         instance = self._call_last_overriding(args, kwargs) | ||||||
|  | 
 | ||||||
|  |         if not isinstance(instance, self.instance_of): | ||||||
|  |             raise Error('{0} is not an '.format(instance) + | ||||||
|  |                         'instance of {0}'.format(self.instance_of)) | ||||||
|  | 
 | ||||||
|  |         return instance | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         """Return string representation of provider. | ||||||
|  | 
 | ||||||
|  |         :rtype: str | ||||||
|  |         """ | ||||||
|  |         return represent_provider(provider=self, provides=self.__instance_of) | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         """Return string representation of provider. | ||||||
|  | 
 | ||||||
|  |         :rtype: str | ||||||
|  |         """ | ||||||
|  |         return self.__str__() | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def instance_of(self): | ||||||
|  |         """Return class of required dependency.""" | ||||||
|  |         return self.__instance_of | ||||||
|  | 
 | ||||||
|  |     def provided_by(self, provider): | ||||||
|  |         """Set external dependency provider. | ||||||
|  | 
 | ||||||
|  |         :param provider: Provider that provides required dependency. | ||||||
|  |         :type provider: :py:class:`Provider` | ||||||
|  | 
 | ||||||
|  |         :rtype: None | ||||||
|  |         """ | ||||||
|  |         return self.override(provider) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | cdef class OverridingContext(object): | ||||||
|  |     """Provider overriding context. | ||||||
|  | 
 | ||||||
|  |     :py:class:`OverridingContext` is used by :py:meth:`Provider.override` for | ||||||
|  |     implemeting ``with`` contexts. When :py:class:`OverridingContext` is | ||||||
|  |     closed, overriding that was created in this context is dropped also. | ||||||
|  | 
 | ||||||
|  |     .. code-block:: python | ||||||
|  | 
 | ||||||
|  |         with provider.override(another_provider): | ||||||
|  |             assert provider.overridden | ||||||
|  |         assert not provider.overridden | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, Provider overridden, Provider overriding): | ||||||
|  |         """Initializer. | ||||||
|  | 
 | ||||||
|  |         :param overridden: Overridden provider. | ||||||
|  |         :type overridden: :py:class:`Provider` | ||||||
|  | 
 | ||||||
|  |         :param overriding: Overriding provider. | ||||||
|  |         :type overriding: :py:class:`Provider` | ||||||
|  |         """ | ||||||
|  |         self.__overridden = overridden | ||||||
|  |         self.__overriding = overriding | ||||||
|  |         super(OverridingContext, self).__init__() | ||||||
|  | 
 | ||||||
|  |     def __enter__(self): | ||||||
|  |         """Do nothing.""" | ||||||
|  |         return self.__overriding | ||||||
|  | 
 | ||||||
|  |     def __exit__(self, *_): | ||||||
|  |         """Exit overriding context.""" | ||||||
|  |         self.__overridden.reset_last_overriding() | ||||||
|  |  | ||||||
|  | @ -12,7 +12,10 @@ from .injections cimport ( | ||||||
|     parse_positional_injections, |     parse_positional_injections, | ||||||
|     parse_named_injections, |     parse_named_injections, | ||||||
| ) | ) | ||||||
| from .utils cimport represent_provider | from .utils cimport ( | ||||||
|  |     represent_provider, | ||||||
|  |     deepcopy, | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class Callable(Provider): | cdef class Callable(Provider): | ||||||
|  | @ -68,6 +71,21 @@ cdef class Callable(Provider): | ||||||
| 
 | 
 | ||||||
|         super(Callable, self).__init__() |         super(Callable, 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.__provies, | ||||||
|  |                                 *deepcopy(self.args, memo), | ||||||
|  |                                 **deepcopy(self.kwargs, memo)) | ||||||
|  | 
 | ||||||
|  |         for overriding_provider in self.overridden: | ||||||
|  |             copied.override(deepcopy(overriding_provider, memo)) | ||||||
|  | 
 | ||||||
|  |         return copied | ||||||
|  | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         """Return string representation of provider. |         """Return string representation of provider. | ||||||
| 
 | 
 | ||||||
|  | @ -132,13 +150,13 @@ cdef class Callable(Provider): | ||||||
|     def kwargs(self): |     def kwargs(self): | ||||||
|         """Return keyword argument injections.""" |         """Return keyword argument injections.""" | ||||||
|         cdef int index |         cdef int index | ||||||
|         cdef NamedInjection arg |         cdef NamedInjection kwarg | ||||||
|         cdef dict kwargs |         cdef dict kwargs | ||||||
| 
 | 
 | ||||||
|         kwargs = dict() |         kwargs = dict() | ||||||
|         for index in range(self.__args_len): |         for index in range(self.__kwargs_len): | ||||||
|             arg = self.__args[index] |             kwarg = self.__kwargs[index] | ||||||
|             kwargs[arg.__name] = arg.__value |             kwargs[kwarg.__name] = kwarg.__value | ||||||
|         return kwargs |         return kwargs | ||||||
| 
 | 
 | ||||||
|     def add_kwargs(self, **kwargs): |     def add_kwargs(self, **kwargs): | ||||||
|  |  | ||||||
|  | @ -11,7 +11,10 @@ from .injections cimport ( | ||||||
|     NamedInjection, |     NamedInjection, | ||||||
|     parse_named_injections, |     parse_named_injections, | ||||||
| ) | ) | ||||||
| from .utils cimport represent_provider | from .utils cimport ( | ||||||
|  |     represent_provider, | ||||||
|  |     deepcopy, | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class Factory(Provider): | cdef class Factory(Provider): | ||||||
|  | @ -90,6 +93,22 @@ cdef class Factory(Provider): | ||||||
| 
 | 
 | ||||||
|         super(Factory, self).__init__() |         super(Factory, 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.cls, | ||||||
|  |                                 *deepcopy(self.args, memo), | ||||||
|  |                                 **deepcopy(self.kwargs, memo)) | ||||||
|  |         copied.set_attributes(**deepcopy(self.attributes, memo)) | ||||||
|  | 
 | ||||||
|  |         for overriding_provider in self.overridden: | ||||||
|  |             copied.override(deepcopy(overriding_provider, memo)) | ||||||
|  | 
 | ||||||
|  |         return copied | ||||||
|  | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         """Return string representation of provider. |         """Return string representation of provider. | ||||||
| 
 | 
 | ||||||
|  | @ -185,8 +204,8 @@ cdef class Factory(Provider): | ||||||
|         cdef dict attributes |         cdef dict attributes | ||||||
| 
 | 
 | ||||||
|         attributes = dict() |         attributes = dict() | ||||||
|         for index in range(self.__args_len): |         for index in range(self.__attributes_len): | ||||||
|             attribute = self.__args[index] |             attribute = self.__attributes[index] | ||||||
|             attributes[attribute.__name] = attribute.__value |             attributes[attribute.__name] = attribute.__value | ||||||
|         return attributes |         return attributes | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ Powered by Cython. | ||||||
| cimport cython | cimport cython | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class Injection: | cdef class Injection(object): | ||||||
|     pass |     pass | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,10 +8,11 @@ cimport cython | ||||||
| from .utils cimport ( | from .utils cimport ( | ||||||
|     is_provider, |     is_provider, | ||||||
|     is_delegated, |     is_delegated, | ||||||
|  |     deepcopy, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class Injection: | cdef class Injection(object): | ||||||
|     """Abstract injection class.""" |     """Abstract injection class.""" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -25,6 +26,14 @@ cdef class PositionalInjection(Injection): | ||||||
|         self.__is_delegated = <int>is_delegated(value) |         self.__is_delegated = <int>is_delegated(value) | ||||||
|         self.__call = <int>(self.__is_provider == 1 and |         self.__call = <int>(self.__is_provider == 1 and | ||||||
|                             self.__is_delegated == 0) |                             self.__is_delegated == 0) | ||||||
|  |         super(PositionalInjection, 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 | ||||||
|  |         return self.__class__(deepcopy(self.__value, memo)) | ||||||
| 
 | 
 | ||||||
|     def get_value(self): |     def get_value(self): | ||||||
|         """Return injection value.""" |         """Return injection value.""" | ||||||
|  | @ -46,6 +55,15 @@ cdef class NamedInjection(Injection): | ||||||
|         self.__is_delegated = <int>is_delegated(value) |         self.__is_delegated = <int>is_delegated(value) | ||||||
|         self.__call = <int>(self.__is_provider == 1 and |         self.__call = <int>(self.__is_provider == 1 and | ||||||
|                             self.__is_delegated == 0) |                             self.__is_delegated == 0) | ||||||
|  |         super(NamedInjection, 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 | ||||||
|  |         return self.__class__(deepcopy(self.__name, memo), | ||||||
|  |                               deepcopy(self.__value, memo)) | ||||||
| 
 | 
 | ||||||
|     def get_name(self): |     def get_name(self): | ||||||
|         """Return injection value.""" |         """Return injection value.""" | ||||||
|  |  | ||||||
|  | @ -9,7 +9,10 @@ from dependency_injector.errors import Error | ||||||
| 
 | 
 | ||||||
| from .base cimport Provider | from .base cimport Provider | ||||||
| from .factories cimport Factory | from .factories cimport Factory | ||||||
| from .utils cimport represent_provider | from .utils cimport ( | ||||||
|  |     represent_provider, | ||||||
|  |     deepcopy, | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| GLOBAL_LOCK = threading.RLock() | GLOBAL_LOCK = threading.RLock() | ||||||
|  | @ -43,7 +46,7 @@ cdef class BaseSingleton(Provider): | ||||||
| 
 | 
 | ||||||
|         self.__instantiator = Factory(provides, *args, **kwargs) |         self.__instantiator = Factory(provides, *args, **kwargs) | ||||||
| 
 | 
 | ||||||
|         super(Provider, self).__init__() |         super(BaseSingleton, self).__init__() | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         """Return string representation of provider. |         """Return string representation of provider. | ||||||
|  | @ -53,6 +56,22 @@ cdef class BaseSingleton(Provider): | ||||||
|         return represent_provider(provider=self, |         return represent_provider(provider=self, | ||||||
|                                   provides=self.__instantiator.cls) |                                   provides=self.__instantiator.cls) | ||||||
| 
 | 
 | ||||||
|  |     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.cls, | ||||||
|  |                                 *deepcopy(self.args, memo), | ||||||
|  |                                 **deepcopy(self.kwargs, memo)) | ||||||
|  |         copied.set_attributes(**deepcopy(self.attributes, memo)) | ||||||
|  | 
 | ||||||
|  |         for overriding_provider in self.overridden: | ||||||
|  |             copied.override(deepcopy(overriding_provider, memo)) | ||||||
|  | 
 | ||||||
|  |         return copied | ||||||
|  | 
 | ||||||
|     @property |     @property | ||||||
|     def cls(self): |     def cls(self): | ||||||
|         """Return provided type.""" |         """Return provided type.""" | ||||||
|  | @ -178,7 +197,35 @@ cdef class BaseSingleton(Provider): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class Singleton(BaseSingleton): | cdef class Singleton(BaseSingleton): | ||||||
|     """Singleton provider.""" |     """Singleton provider returns same instance on every call. | ||||||
|  | 
 | ||||||
|  |     :py:class:`Singleton` provider creates instance once and returns it on | ||||||
|  |     every call. :py:class:`Singleton` extends :py:class:`Factory`, so, please | ||||||
|  |     follow :py:class:`Factory` documentation for getting familiar with | ||||||
|  |     injections syntax. | ||||||
|  | 
 | ||||||
|  |     Retrieving of provided instance can be performed via calling | ||||||
|  |     :py:class:`Singleton` object: | ||||||
|  | 
 | ||||||
|  |     .. code-block:: python | ||||||
|  | 
 | ||||||
|  |         singleton = Singleton(SomeClass) | ||||||
|  |         some_object = singleton() | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provided_type | ||||||
|  | 
 | ||||||
|  |         If provided type is defined, provider checks that providing class is | ||||||
|  |         its subclass. | ||||||
|  | 
 | ||||||
|  |         :type: type | None | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: cls | ||||||
|  | 
 | ||||||
|  |         Class that provides object. | ||||||
|  |         Alias for :py:attr:`provides`. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, provides, *args, **kwargs): |     def __init__(self, provides, *args, **kwargs): | ||||||
|         """Initializer. |         """Initializer. | ||||||
|  | @ -208,6 +255,23 @@ cdef class Singleton(BaseSingleton): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class DelegatedSingleton(Singleton): | cdef class DelegatedSingleton(Singleton): | ||||||
|  |     """Delegated singleton is injected "as is". | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provided_type | ||||||
|  | 
 | ||||||
|  |         If provided type is defined, provider checks that providing class is | ||||||
|  |         its subclass. | ||||||
|  | 
 | ||||||
|  |         :type: type | None | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: cls | ||||||
|  | 
 | ||||||
|  |         Class that provides object. | ||||||
|  |         Alias for :py:attr:`provides`. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|     __IS_DELEGATED__ = True |     __IS_DELEGATED__ = True | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -243,11 +307,43 @@ cdef class ThreadSafeSingleton(BaseSingleton): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton): | cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton): | ||||||
|  |     """Delegated thread-safe singleton is injected "as is". | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provided_type | ||||||
|  | 
 | ||||||
|  |         If provided type is defined, provider checks that providing class is | ||||||
|  |         its subclass. | ||||||
|  | 
 | ||||||
|  |         :type: type | None | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: cls | ||||||
|  | 
 | ||||||
|  |         Class that provides object. | ||||||
|  |         Alias for :py:attr:`provides`. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|     __IS_DELEGATED__ = True |     __IS_DELEGATED__ = True | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class ThreadLocalSingleton(BaseSingleton): | cdef class ThreadLocalSingleton(BaseSingleton): | ||||||
|     """Thread local singleton provider.""" |     """Thread-local singleton provides single objects in scope of thread. | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provided_type | ||||||
|  | 
 | ||||||
|  |         If provided type is defined, provider checks that providing class is | ||||||
|  |         its subclass. | ||||||
|  | 
 | ||||||
|  |         :type: type | None | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: cls | ||||||
|  | 
 | ||||||
|  |         Class that provides object. | ||||||
|  |         Alias for :py:attr:`provides`. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, provides, *args, **kwargs): |     def __init__(self, provides, *args, **kwargs): | ||||||
|         """Initializer. |         """Initializer. | ||||||
|  | @ -277,4 +373,21 @@ cdef class ThreadLocalSingleton(BaseSingleton): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton): | cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton): | ||||||
|  |     """Delegated thread-local singleton is injected "as is". | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: provided_type | ||||||
|  | 
 | ||||||
|  |         If provided type is defined, provider checks that providing class is | ||||||
|  |         its subclass. | ||||||
|  | 
 | ||||||
|  |         :type: type | None | ||||||
|  | 
 | ||||||
|  |     .. py:attribute:: cls | ||||||
|  | 
 | ||||||
|  |         Class that provides object. | ||||||
|  |         Alias for :py:attr:`provides`. | ||||||
|  | 
 | ||||||
|  |         :type: type | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|     __IS_DELEGATED__ = True |     __IS_DELEGATED__ = True | ||||||
|  |  | ||||||
|  | @ -1,19 +0,0 @@ | ||||||
| """Dependency injector static providers. |  | ||||||
| 
 |  | ||||||
| Powered by Cython. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from .base cimport Provider |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cdef class Object(Provider): |  | ||||||
|     cdef object __provides |  | ||||||
| 
 |  | ||||||
|     cpdef object _provide(self, tuple args, dict kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cdef class Delegate(Object): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| cdef class ExternalDependency(Provider): |  | ||||||
|     cdef type __instance_of |  | ||||||
|  | @ -1,165 +0,0 @@ | ||||||
| """Dependency injector static providers. |  | ||||||
| 
 |  | ||||||
| Powered by Cython. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from dependency_injector.errors import Error |  | ||||||
| 
 |  | ||||||
| from .base cimport Provider |  | ||||||
| from .utils cimport ( |  | ||||||
|     ensure_is_provider, |  | ||||||
|     represent_provider, |  | ||||||
|     CLASS_TYPES, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cdef class Object(Provider): |  | ||||||
|     """Object provider returns provided instance "as is". |  | ||||||
| 
 |  | ||||||
|     .. py:attribute:: provides |  | ||||||
| 
 |  | ||||||
|         Value that have to be provided. |  | ||||||
| 
 |  | ||||||
|         :type: object |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, provides): |  | ||||||
|         """Initializer. |  | ||||||
| 
 |  | ||||||
|         :param provides: Value that have to be provided. |  | ||||||
|         :type provides: object |  | ||||||
|         """ |  | ||||||
|         self.__provides = provides |  | ||||||
|         super(Object, self).__init__() |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         """Return string representation of provider. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
|         """ |  | ||||||
|         return represent_provider(provider=self, provides=self.__provides) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         """Return string representation of provider. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
|         """ |  | ||||||
|         return self.__str__() |  | ||||||
| 
 |  | ||||||
|     cpdef object _provide(self, tuple args, dict kwargs): |  | ||||||
|         """Return provided instance. |  | ||||||
| 
 |  | ||||||
|         :param args: Tuple of context positional arguments. |  | ||||||
|         :type args: tuple[object] |  | ||||||
| 
 |  | ||||||
|         :param kwargs: Dictionary of context keyword arguments. |  | ||||||
|         :type kwargs: dict[str, object] |  | ||||||
| 
 |  | ||||||
|         :rtype: object |  | ||||||
|         """ |  | ||||||
|         return self.__provides |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cdef class Delegate(Object): |  | ||||||
|     """Delegate provider returns provider "as is". |  | ||||||
| 
 |  | ||||||
|     .. py:attribute:: provides |  | ||||||
| 
 |  | ||||||
|         Value that have to be provided. |  | ||||||
| 
 |  | ||||||
|         :type: object |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, provides): |  | ||||||
|         """Initializer. |  | ||||||
| 
 |  | ||||||
|         :param provides: Value that have to be provided. |  | ||||||
|         :type provides: object |  | ||||||
|         """ |  | ||||||
|         super(Delegate, self).__init__(ensure_is_provider(provides)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cdef class ExternalDependency(Provider): |  | ||||||
|     """:py:class:`ExternalDependency` provider describes dependency interface. |  | ||||||
| 
 |  | ||||||
|     This provider is used for description of dependency interface. That might |  | ||||||
|     be useful when dependency could be provided in the client's code only, |  | ||||||
|     but it's interface is known. Such situations could happen when required |  | ||||||
|     dependency has non-determenistic list of dependencies itself. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: python |  | ||||||
| 
 |  | ||||||
|         database_provider = ExternalDependency(sqlite3.dbapi2.Connection) |  | ||||||
|         database_provider.override(Factory(sqlite3.connect, ':memory:')) |  | ||||||
| 
 |  | ||||||
|         database = database_provider() |  | ||||||
| 
 |  | ||||||
|     .. py:attribute:: instance_of |  | ||||||
| 
 |  | ||||||
|         Class of required dependency. |  | ||||||
| 
 |  | ||||||
|         :type: type |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, type instance_of): |  | ||||||
|         """Initializer.""" |  | ||||||
|         if not isinstance(instance_of, CLASS_TYPES): |  | ||||||
|             raise Error('ExternalDependency provider expects to get class, ' + |  | ||||||
|                         'got {0} instead'.format(str(instance_of))) |  | ||||||
|         self.__instance_of = instance_of |  | ||||||
|         super(ExternalDependency, self).__init__() |  | ||||||
| 
 |  | ||||||
|     def __call__(self, *args, **kwargs): |  | ||||||
|         """Return provided instance. |  | ||||||
| 
 |  | ||||||
|         :param args: Tuple of context positional arguments. |  | ||||||
|         :type args: tuple[object] |  | ||||||
| 
 |  | ||||||
|         :param kwargs: Dictionary of context keyword arguments. |  | ||||||
|         :type kwargs: dict[str, object] |  | ||||||
| 
 |  | ||||||
|         :raise: :py:exc:`dependency_injector.errors.Error` |  | ||||||
| 
 |  | ||||||
|         :rtype: object |  | ||||||
|         """ |  | ||||||
|         cdef object instance |  | ||||||
| 
 |  | ||||||
|         if self.__overridden_len == 0: |  | ||||||
|             raise Error('Dependency is not defined') |  | ||||||
| 
 |  | ||||||
|         instance = self._call_last_overriding(args, kwargs) |  | ||||||
| 
 |  | ||||||
|         if not isinstance(instance, self.instance_of): |  | ||||||
|             raise Error('{0} is not an '.format(instance) + |  | ||||||
|                         'instance of {0}'.format(self.instance_of)) |  | ||||||
| 
 |  | ||||||
|         return instance |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         """Return string representation of provider. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
|         """ |  | ||||||
|         return represent_provider(provider=self, provides=self.__instance_of) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         """Return string representation of provider. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
|         """ |  | ||||||
|         return self.__str__() |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def instance_of(self): |  | ||||||
|         """Return class of required dependency.""" |  | ||||||
|         return self.__instance_of |  | ||||||
| 
 |  | ||||||
|     def provided_by(self, provider): |  | ||||||
|         """Set external dependency provider. |  | ||||||
| 
 |  | ||||||
|         :param provider: Provider that provides required dependency. |  | ||||||
|         :type provider: :py:class:`Provider` |  | ||||||
| 
 |  | ||||||
|         :rtype: None |  | ||||||
|         """ |  | ||||||
|         return self.override(provider) |  | ||||||
|  | @ -3,18 +3,11 @@ | ||||||
| Powered by Cython. | Powered by Cython. | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| from .base cimport Provider |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cdef public object CLASS_TYPES | cdef public object CLASS_TYPES | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cdef class OverridingContext(object): |  | ||||||
|     cdef Provider __overridden |  | ||||||
|     cdef Provider __overriding |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cpdef bint is_provider(object instance) | cpdef bint is_provider(object instance) | ||||||
| cpdef object ensure_is_provider(object instance) | cpdef object ensure_is_provider(object instance) | ||||||
| cpdef bint is_delegated(object instance) | cpdef bint is_delegated(object instance) | ||||||
| cpdef str represent_provider(object provider, object provides) | cpdef str represent_provider(object provider, object provides) | ||||||
|  | cpdef object deepcopy(object instance, dict memo=*) | ||||||
|  |  | ||||||
|  | @ -3,55 +3,23 @@ | ||||||
| Powered by Cython. | Powered by Cython. | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
|  | import copy | ||||||
| import sys | import sys | ||||||
| import types | import types | ||||||
| 
 |  | ||||||
| import threading | import threading | ||||||
| 
 | 
 | ||||||
| from dependency_injector.errors import Error | from dependency_injector.errors import Error | ||||||
| 
 | 
 | ||||||
| from .base cimport Provider |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| if sys.version_info[0] == 3:  # pragma: no cover | if sys.version_info[0] == 3:  # pragma: no cover | ||||||
|     CLASS_TYPES = (type,) |     CLASS_TYPES = (type,) | ||||||
| else:  # pragma: no cover | else:  # pragma: no cover | ||||||
|     CLASS_TYPES = (type, types.ClassType) |     CLASS_TYPES = (type, types.ClassType) | ||||||
| 
 | 
 | ||||||
| 
 |     copy._deepcopy_dispatch[types.MethodType] = \ | ||||||
| cdef class OverridingContext(object): |         lambda obj, memo: type(obj)(obj.im_func, | ||||||
|     """Provider overriding context. |                                     copy.deepcopy(obj.im_self, memo), | ||||||
| 
 |                                     obj.im_class) | ||||||
|     :py:class:`OverridingContext` is used by :py:meth:`Provider.override` for |  | ||||||
|     implemeting ``with`` contexts. When :py:class:`OverridingContext` is |  | ||||||
|     closed, overriding that was created in this context is dropped also. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: python |  | ||||||
| 
 |  | ||||||
|         with provider.override(another_provider): |  | ||||||
|             assert provider.overridden |  | ||||||
|         assert not provider.overridden |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, Provider overridden, Provider overriding): |  | ||||||
|         """Initializer. |  | ||||||
| 
 |  | ||||||
|         :param overridden: Overridden provider. |  | ||||||
|         :type overridden: :py:class:`Provider` |  | ||||||
| 
 |  | ||||||
|         :param overriding: Overriding provider. |  | ||||||
|         :type overriding: :py:class:`Provider` |  | ||||||
|         """ |  | ||||||
|         self.__overridden = overridden |  | ||||||
|         self.__overriding = overriding |  | ||||||
| 
 |  | ||||||
|     def __enter__(self): |  | ||||||
|         """Do nothing.""" |  | ||||||
|         return self.__overriding |  | ||||||
| 
 |  | ||||||
|     def __exit__(self, *_): |  | ||||||
|         """Exit overriding context.""" |  | ||||||
|         self.__overridden.reset_last_overriding() |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| cpdef bint is_provider(object instance): | cpdef bint is_provider(object instance): | ||||||
|  | @ -112,3 +80,7 @@ cpdef str represent_provider(object provider, object provides): | ||||||
|                            provider.__class__.__name__)), |                            provider.__class__.__name__)), | ||||||
|         provides=repr(provides) if provides is not None else '', |         provides=repr(provides) if provides is not None else '', | ||||||
|         address=hex(id(provider))) |         address=hex(id(provider))) | ||||||
|  | 
 | ||||||
|  | cpdef object deepcopy(object instance, dict memo=None): | ||||||
|  |     """Return full copy of provider or container with providers.""" | ||||||
|  |     return copy.deepcopy(instance, memo) | ||||||
|  |  | ||||||
|  | @ -84,3 +84,86 @@ class ProviderTests(unittest.TestCase): | ||||||
|         self.assertEqual(repr(self.provider), |         self.assertEqual(repr(self.provider), | ||||||
|                          '<dependency_injector.providers.base.' |                          '<dependency_injector.providers.base.' | ||||||
|                          'Provider() at {0}>'.format(hex(id(self.provider)))) |                          'Provider() at {0}>'.format(hex(id(self.provider)))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ObjectProviderTests(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     def test_is_provider(self): | ||||||
|  |         self.assertTrue(providers.is_provider(providers.Object(object()))) | ||||||
|  | 
 | ||||||
|  |     def test_call_object_provider(self): | ||||||
|  |         obj = object() | ||||||
|  |         self.assertIs(providers.Object(obj)(), obj) | ||||||
|  | 
 | ||||||
|  |     def test_call_overridden_object_provider(self): | ||||||
|  |         obj1 = object() | ||||||
|  |         obj2 = object() | ||||||
|  |         provider = providers.Object(obj1) | ||||||
|  |         provider.override(providers.Object(obj2)) | ||||||
|  |         self.assertIs(provider(), obj2) | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         some_object = object() | ||||||
|  |         provider = providers.Object(some_object) | ||||||
|  |         self.assertEqual(repr(provider), | ||||||
|  |                          '<dependency_injector.providers.base.' | ||||||
|  |                          'Object({0}) at {1}>'.format( | ||||||
|  |                              repr(some_object), | ||||||
|  |                              hex(id(provider)))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DelegateTests(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.delegated = providers.Provider() | ||||||
|  |         self.delegate = providers.Delegate(self.delegated) | ||||||
|  | 
 | ||||||
|  |     def test_is_provider(self): | ||||||
|  |         self.assertTrue(providers.is_provider(self.delegate)) | ||||||
|  | 
 | ||||||
|  |     def test_init_with_not_provider(self): | ||||||
|  |         self.assertRaises(errors.Error, providers.Delegate, object()) | ||||||
|  | 
 | ||||||
|  |     def test_call(self): | ||||||
|  |         delegated1 = self.delegate() | ||||||
|  |         delegated2 = self.delegate() | ||||||
|  | 
 | ||||||
|  |         self.assertIs(delegated1, self.delegated) | ||||||
|  |         self.assertIs(delegated2, self.delegated) | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         self.assertEqual(repr(self.delegate), | ||||||
|  |                          '<dependency_injector.providers.base.' | ||||||
|  |                          'Delegate({0}) at {1}>'.format( | ||||||
|  |                              repr(self.delegated), | ||||||
|  |                              hex(id(self.delegate)))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ExternalDependencyTests(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.provider = providers.ExternalDependency(instance_of=list) | ||||||
|  | 
 | ||||||
|  |     def test_init_with_not_class(self): | ||||||
|  |         self.assertRaises(TypeError, providers.ExternalDependency, object()) | ||||||
|  | 
 | ||||||
|  |     def test_is_provider(self): | ||||||
|  |         self.assertTrue(providers.is_provider(self.provider)) | ||||||
|  | 
 | ||||||
|  |     def test_call_overridden(self): | ||||||
|  |         self.provider.provided_by(providers.Factory(list)) | ||||||
|  |         self.assertIsInstance(self.provider(), list) | ||||||
|  | 
 | ||||||
|  |     def test_call_overridden_but_not_instance_of(self): | ||||||
|  |         self.provider.provided_by(providers.Factory(dict)) | ||||||
|  |         self.assertRaises(errors.Error, self.provider) | ||||||
|  | 
 | ||||||
|  |     def test_call_not_overridden(self): | ||||||
|  |         self.assertRaises(errors.Error, self.provider) | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         self.assertEqual(repr(self.provider), | ||||||
|  |                          '<dependency_injector.providers.base.' | ||||||
|  |                          'ExternalDependency({0}) at {1}>'.format( | ||||||
|  |                              repr(list), | ||||||
|  |                              hex(id(self.provider)))) | ||||||
|  |  | ||||||
|  | @ -1,91 +0,0 @@ | ||||||
| """Dependency injector static providers unit tests.""" |  | ||||||
| 
 |  | ||||||
| import unittest2 as unittest |  | ||||||
| 
 |  | ||||||
| from dependency_injector import ( |  | ||||||
|     providers, |  | ||||||
|     errors, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ObjectProviderTests(unittest.TestCase): |  | ||||||
| 
 |  | ||||||
|     def test_is_provider(self): |  | ||||||
|         self.assertTrue(providers.is_provider(providers.Object(object()))) |  | ||||||
| 
 |  | ||||||
|     def test_call_object_provider(self): |  | ||||||
|         obj = object() |  | ||||||
|         self.assertIs(providers.Object(obj)(), obj) |  | ||||||
| 
 |  | ||||||
|     def test_call_overridden_object_provider(self): |  | ||||||
|         obj1 = object() |  | ||||||
|         obj2 = object() |  | ||||||
|         provider = providers.Object(obj1) |  | ||||||
|         provider.override(providers.Object(obj2)) |  | ||||||
|         self.assertIs(provider(), obj2) |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         some_object = object() |  | ||||||
|         provider = providers.Object(some_object) |  | ||||||
|         self.assertEqual(repr(provider), |  | ||||||
|                          '<dependency_injector.providers.static.' |  | ||||||
|                          'Object({0}) at {1}>'.format( |  | ||||||
|                              repr(some_object), |  | ||||||
|                              hex(id(provider)))) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DelegateTests(unittest.TestCase): |  | ||||||
| 
 |  | ||||||
|     def setUp(self): |  | ||||||
|         self.delegated = providers.Provider() |  | ||||||
|         self.delegate = providers.Delegate(self.delegated) |  | ||||||
| 
 |  | ||||||
|     def test_is_provider(self): |  | ||||||
|         self.assertTrue(providers.is_provider(self.delegate)) |  | ||||||
| 
 |  | ||||||
|     def test_init_with_not_provider(self): |  | ||||||
|         self.assertRaises(errors.Error, providers.Delegate, object()) |  | ||||||
| 
 |  | ||||||
|     def test_call(self): |  | ||||||
|         delegated1 = self.delegate() |  | ||||||
|         delegated2 = self.delegate() |  | ||||||
| 
 |  | ||||||
|         self.assertIs(delegated1, self.delegated) |  | ||||||
|         self.assertIs(delegated2, self.delegated) |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         self.assertEqual(repr(self.delegate), |  | ||||||
|                          '<dependency_injector.providers.static.' |  | ||||||
|                          'Delegate({0}) at {1}>'.format( |  | ||||||
|                              repr(self.delegated), |  | ||||||
|                              hex(id(self.delegate)))) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ExternalDependencyTests(unittest.TestCase): |  | ||||||
| 
 |  | ||||||
|     def setUp(self): |  | ||||||
|         self.provider = providers.ExternalDependency(instance_of=list) |  | ||||||
| 
 |  | ||||||
|     def test_init_with_not_class(self): |  | ||||||
|         self.assertRaises(TypeError, providers.ExternalDependency, object()) |  | ||||||
| 
 |  | ||||||
|     def test_is_provider(self): |  | ||||||
|         self.assertTrue(providers.is_provider(self.provider)) |  | ||||||
| 
 |  | ||||||
|     def test_call_overridden(self): |  | ||||||
|         self.provider.provided_by(providers.Factory(list)) |  | ||||||
|         self.assertIsInstance(self.provider(), list) |  | ||||||
| 
 |  | ||||||
|     def test_call_overridden_but_not_instance_of(self): |  | ||||||
|         self.provider.provided_by(providers.Factory(dict)) |  | ||||||
|         self.assertRaises(errors.Error, self.provider) |  | ||||||
| 
 |  | ||||||
|     def test_call_not_overridden(self): |  | ||||||
|         self.assertRaises(errors.Error, self.provider) |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         self.assertEqual(repr(self.provider), |  | ||||||
|                          '<dependency_injector.providers.static.' |  | ||||||
|                          'ExternalDependency({0}) at {1}>'.format( |  | ||||||
|                              repr(list), |  | ||||||
|                              hex(id(self.provider)))) |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user