mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 19:14:00 +03:00
Merge branch 'release/4.21.0' into master
This commit is contained in:
commit
2127e3cef9
|
@ -7,6 +7,11 @@ that were made in every particular version.
|
||||||
From version 0.7.6 *Dependency Injector* framework strictly
|
From version 0.7.6 *Dependency Injector* framework strictly
|
||||||
follows `Semantic versioning`_
|
follows `Semantic versioning`_
|
||||||
|
|
||||||
|
4.21.0
|
||||||
|
------
|
||||||
|
- Improve ``Dependency`` provider error message: when dependency is undefined,
|
||||||
|
error message contains its name.
|
||||||
|
|
||||||
4.20.2
|
4.20.2
|
||||||
------
|
------
|
||||||
- Move docs on container "self" injections to "Providers" section.
|
- Move docs on container "self" injections to "Providers" section.
|
||||||
|
|
|
@ -15,7 +15,12 @@ Dependency provider will control that returned object is an instance of ``instan
|
||||||
|
|
||||||
To provide a dependency you need to override the ``Dependency`` provider. You can call
|
To provide a dependency you need to override the ``Dependency`` provider. You can call
|
||||||
provider ``.override()`` method or provide an overriding provider when creating a container.
|
provider ``.override()`` method or provide an overriding provider when creating a container.
|
||||||
See :ref:`provider-overriding`.
|
See :ref:`provider-overriding`. If you don't provide a dependency, ``Dependency`` provider
|
||||||
|
will raise an error:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/providers/dependency_undefined_error.py
|
||||||
|
:language: python
|
||||||
|
:lines: 18-
|
||||||
|
|
||||||
You also can provide a default for the dependency. To provide a default use ``default`` argument:
|
You also can provide a default for the dependency. To provide a default use ``default`` argument:
|
||||||
``Dependency(..., default=...)``. Default can be a value or a provider. If default is not a provider,
|
``Dependency(..., default=...)``. Default can be a value or a provider. If default is not a provider,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import abc
|
import abc
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
|
||||||
from dependency_injector import containers, providers, errors
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
|
||||||
class DbAdapter(metaclass=abc.ABCMeta):
|
class DbAdapter(metaclass=abc.ABCMeta):
|
||||||
|
@ -41,10 +41,5 @@ if __name__ == '__main__':
|
||||||
assert isinstance(container2.user_service().database, PostgresDbAdapter)
|
assert isinstance(container2.user_service().database, PostgresDbAdapter)
|
||||||
|
|
||||||
container3 = Container(database=providers.Singleton(object))
|
container3 = Container(database=providers.Singleton(object))
|
||||||
try:
|
container3.user_service() # <-- raises error:
|
||||||
container3.user_service()
|
# <object ...> is not an instance of DbAdapter
|
||||||
except errors.Error as exception:
|
|
||||||
print(exception)
|
|
||||||
# The output is:
|
|
||||||
# <object object at 0x107ce5c40> is not an
|
|
||||||
# instance of <class '__main__.DbAdapter'>
|
|
||||||
|
|
31
examples/providers/dependency_undefined_error.py
Normal file
31
examples/providers/dependency_undefined_error.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
"""`Dependency` provider undefined error example."""
|
||||||
|
|
||||||
|
import abc
|
||||||
|
import dataclasses
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
|
||||||
|
class DbAdapter(metaclass=abc.ABCMeta):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class UserService:
|
||||||
|
database: DbAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
database = providers.Dependency(instance_of=DbAdapter)
|
||||||
|
|
||||||
|
user_service = providers.Factory(
|
||||||
|
UserService,
|
||||||
|
database=database,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container()
|
||||||
|
container.user_service() # <-- raises error:
|
||||||
|
# Dependency "Container.database" is not defined
|
|
@ -1,6 +1,6 @@
|
||||||
"""Top-level package."""
|
"""Top-level package."""
|
||||||
|
|
||||||
__version__ = '4.20.2'
|
__version__ = '4.21.0'
|
||||||
"""Version number.
|
"""Version number.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,12 +8,13 @@ from typing import (
|
||||||
ClassVar,
|
ClassVar,
|
||||||
Callable as _Callable,
|
Callable as _Callable,
|
||||||
Iterable,
|
Iterable,
|
||||||
|
Iterator,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Awaitable,
|
Awaitable,
|
||||||
overload,
|
overload,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .providers import Provider, Self
|
from .providers import Provider, Self, ProviderParent
|
||||||
|
|
||||||
|
|
||||||
C_Base = TypeVar('C_Base', bound='Container')
|
C_Base = TypeVar('C_Base', bound='Container')
|
||||||
|
@ -38,7 +39,6 @@ class Container:
|
||||||
def override_providers(self, **overriding_providers: Provider) -> None: ...
|
def override_providers(self, **overriding_providers: Provider) -> None: ...
|
||||||
def reset_last_overriding(self) -> None: ...
|
def reset_last_overriding(self) -> None: ...
|
||||||
def reset_override(self) -> None: ...
|
def reset_override(self) -> None: ...
|
||||||
def resolve_provider_name(self, provider_to_resolve: Provider) -> Optional[str]: ...
|
|
||||||
def wire(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None) -> None: ...
|
def wire(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None) -> None: ...
|
||||||
def unwire(self) -> None: ...
|
def unwire(self) -> None: ...
|
||||||
def init_resources(self) -> Optional[Awaitable]: ...
|
def init_resources(self) -> Optional[Awaitable]: ...
|
||||||
|
@ -46,10 +46,20 @@ class Container:
|
||||||
def apply_container_providers_overridings(self) -> None: ...
|
def apply_container_providers_overridings(self) -> None: ...
|
||||||
def reset_singletons(self) -> None: ...
|
def reset_singletons(self) -> None: ...
|
||||||
@overload
|
@overload
|
||||||
def traverse(self, types: Optional[Iterable[Type[TT]]] = None) -> _Iterator[TT]: ...
|
def resolve_provider_name(self, provider: Provider) -> str: ...
|
||||||
@classmethod
|
@classmethod
|
||||||
@overload
|
@overload
|
||||||
def traverse(self, types: Optional[Iterable[Type[TT]]] = None) -> _Iterator[TT]: ...
|
def resolve_provider_name(cls, provider: Provider) -> str: ...
|
||||||
|
@property
|
||||||
|
def parent(self) -> Optional[ProviderParent]: ...
|
||||||
|
@property
|
||||||
|
def parent_name(self) -> Optional[str]: ...
|
||||||
|
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||||
|
@overload
|
||||||
|
def traverse(self, types: Optional[Iterable[Type[TT]]] = None) -> Iterator[TT]: ...
|
||||||
|
@classmethod
|
||||||
|
@overload
|
||||||
|
def traverse(cls, types: Optional[Iterable[Type[TT]]] = None) -> Iterator[TT]: ...
|
||||||
|
|
||||||
|
|
||||||
class DynamicContainer(Container): ...
|
class DynamicContainer(Container): ...
|
||||||
|
|
|
@ -66,6 +66,7 @@ class DynamicContainer(Container):
|
||||||
self.provider_type = providers.Provider
|
self.provider_type = providers.Provider
|
||||||
self.providers = {}
|
self.providers = {}
|
||||||
self.overridden = tuple()
|
self.overridden = tuple()
|
||||||
|
self.parent = None
|
||||||
self.declarative_parent = None
|
self.declarative_parent = None
|
||||||
self.wired_to_modules = []
|
self.wired_to_modules = []
|
||||||
self.wired_to_packages = []
|
self.wired_to_packages = []
|
||||||
|
@ -92,6 +93,8 @@ class DynamicContainer(Container):
|
||||||
for name, provider in providers.deepcopy(self.providers, memo).items():
|
for name, provider in providers.deepcopy(self.providers, memo).items():
|
||||||
copied.set_provider(name, provider)
|
copied.set_provider(name, provider)
|
||||||
|
|
||||||
|
copied.parent = providers.deepcopy(self.parent, memo)
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
def __setattr__(self, str name, object value):
|
def __setattr__(self, str name, object value):
|
||||||
|
@ -108,9 +111,16 @@ class DynamicContainer(Container):
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
if isinstance(value, providers.Provider) and not isinstance(value, providers.Self):
|
if isinstance(value, providers.Provider) \
|
||||||
|
and not isinstance(value, providers.Self) \
|
||||||
|
and name != 'parent':
|
||||||
_check_provider_type(self, value)
|
_check_provider_type(self, value)
|
||||||
|
|
||||||
self.providers[name] = value
|
self.providers[name] = value
|
||||||
|
|
||||||
|
if isinstance(value, providers.CHILD_PROVIDERS):
|
||||||
|
value.assign_parent(self)
|
||||||
|
|
||||||
super(DynamicContainer, self).__setattr__(name, value)
|
super(DynamicContainer, self).__setattr__(name, value)
|
||||||
|
|
||||||
def __delattr__(self, str name):
|
def __delattr__(self, str name):
|
||||||
|
@ -295,6 +305,29 @@ class DynamicContainer(Container):
|
||||||
for provider in self.traverse(types=[providers.BaseSingleton]):
|
for provider in self.traverse(types=[providers.BaseSingleton]):
|
||||||
provider.reset()
|
provider.reset()
|
||||||
|
|
||||||
|
def resolve_provider_name(self, provider):
|
||||||
|
"""Try to resolve provider name."""
|
||||||
|
for provider_name, container_provider in self.providers.items():
|
||||||
|
if container_provider is provider:
|
||||||
|
return provider_name
|
||||||
|
else:
|
||||||
|
raise errors.Error(f'Can not resolve name for provider "{provider}"')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent_name(self):
|
||||||
|
"""Return parent name."""
|
||||||
|
if self.parent:
|
||||||
|
return self.parent.parent_name
|
||||||
|
|
||||||
|
if self.declarative_parent:
|
||||||
|
return self.declarative_parent.__name__
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def assign_parent(self, parent):
|
||||||
|
"""Assign parent."""
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
|
||||||
class DeclarativeContainerMetaClass(type):
|
class DeclarativeContainerMetaClass(type):
|
||||||
"""Declarative inversion of control container meta class."""
|
"""Declarative inversion of control container meta class."""
|
||||||
|
@ -341,6 +374,10 @@ class DeclarativeContainerMetaClass(type):
|
||||||
for provider in six.itervalues(cls.providers):
|
for provider in six.itervalues(cls.providers):
|
||||||
_check_provider_type(cls, provider)
|
_check_provider_type(cls, provider)
|
||||||
|
|
||||||
|
for provider in six.itervalues(cls.cls_providers):
|
||||||
|
if isinstance(provider, providers.CHILD_PROVIDERS):
|
||||||
|
provider.assign_parent(cls)
|
||||||
|
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
def __setattr__(cls, str name, object value):
|
def __setattr__(cls, str name, object value):
|
||||||
|
@ -359,6 +396,10 @@ class DeclarativeContainerMetaClass(type):
|
||||||
"""
|
"""
|
||||||
if isinstance(value, providers.Provider) and name != '__self__':
|
if isinstance(value, providers.Provider) and name != '__self__':
|
||||||
_check_provider_type(cls, value)
|
_check_provider_type(cls, value)
|
||||||
|
|
||||||
|
if isinstance(value, providers.CHILD_PROVIDERS):
|
||||||
|
value.assign_parent(cls)
|
||||||
|
|
||||||
cls.providers[name] = value
|
cls.providers[name] = value
|
||||||
cls.cls_providers[name] = value
|
cls.cls_providers[name] = value
|
||||||
super(DeclarativeContainerMetaClass, cls).__setattr__(name, value)
|
super(DeclarativeContainerMetaClass, cls).__setattr__(name, value)
|
||||||
|
@ -399,6 +440,19 @@ class DeclarativeContainerMetaClass(type):
|
||||||
"""Return providers traversal generator."""
|
"""Return providers traversal generator."""
|
||||||
yield from providers.traverse(*cls.providers.values(), types=types)
|
yield from providers.traverse(*cls.providers.values(), types=types)
|
||||||
|
|
||||||
|
def resolve_provider_name(cls, provider):
|
||||||
|
"""Try to resolve provider name."""
|
||||||
|
for provider_name, container_provider in cls.providers.items():
|
||||||
|
if container_provider is provider:
|
||||||
|
return provider_name
|
||||||
|
else:
|
||||||
|
raise errors.Error(f'Can not resolve name for provider "{provider}"')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent_name(cls):
|
||||||
|
"""Return parent name."""
|
||||||
|
return cls.__name__
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __fetch_self(attributes):
|
def __fetch_self(attributes):
|
||||||
self = None
|
self = None
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -41,6 +41,7 @@ cdef class Delegate(Provider):
|
||||||
cdef class Dependency(Provider):
|
cdef class Dependency(Provider):
|
||||||
cdef object __instance_of
|
cdef object __instance_of
|
||||||
cdef object __default
|
cdef object __default
|
||||||
|
cdef object __parent
|
||||||
|
|
||||||
|
|
||||||
cdef class ExternalDependency(Dependency):
|
cdef class ExternalDependency(Dependency):
|
||||||
|
@ -49,6 +50,7 @@ cdef class ExternalDependency(Dependency):
|
||||||
|
|
||||||
cdef class DependenciesContainer(Object):
|
cdef class DependenciesContainer(Object):
|
||||||
cdef dict __providers
|
cdef dict __providers
|
||||||
|
cdef object __parent
|
||||||
|
|
||||||
cpdef object _override_providers(self, object container)
|
cpdef object _override_providers(self, object container)
|
||||||
|
|
||||||
|
@ -225,6 +227,7 @@ cdef class Container(Provider):
|
||||||
cdef object __container_cls
|
cdef object __container_cls
|
||||||
cdef dict __overriding_providers
|
cdef dict __overriding_providers
|
||||||
cdef object __container
|
cdef object __container
|
||||||
|
cdef object __parent
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
@ -305,6 +308,12 @@ cpdef bint is_delegated(object instance)
|
||||||
cpdef str represent_provider(object provider, object provides)
|
cpdef str represent_provider(object provider, object provides)
|
||||||
|
|
||||||
|
|
||||||
|
cpdef bint is_container_instance(object instance)
|
||||||
|
|
||||||
|
|
||||||
|
cpdef bint is_container_class(object instance)
|
||||||
|
|
||||||
|
|
||||||
cpdef object deepcopy(object instance, dict memo=*)
|
cpdef object deepcopy(object instance, dict memo=*)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ from . import resources
|
||||||
|
|
||||||
|
|
||||||
Injection = Any
|
Injection = Any
|
||||||
|
ProviderParent = Union['Provider', Any]
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
TT = TypeVar('TT')
|
TT = TypeVar('TT')
|
||||||
|
|
||||||
|
@ -106,6 +107,11 @@ class Dependency(Provider[T]):
|
||||||
@property
|
@property
|
||||||
def default(self) -> Provider[T]: ...
|
def default(self) -> Provider[T]: ...
|
||||||
def provided_by(self, provider: Provider) -> OverridingContext: ...
|
def provided_by(self, provider: Provider) -> OverridingContext: ...
|
||||||
|
@property
|
||||||
|
def parent(self) -> Optional[ProviderParent]: ...
|
||||||
|
@property
|
||||||
|
def parent_name(self) -> Optional[str]: ...
|
||||||
|
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
class ExternalDependency(Dependency[T]): ...
|
class ExternalDependency(Dependency[T]): ...
|
||||||
|
@ -116,6 +122,12 @@ class DependenciesContainer(Object):
|
||||||
def __getattr__(self, name: str) -> Provider: ...
|
def __getattr__(self, name: str) -> Provider: ...
|
||||||
@property
|
@property
|
||||||
def providers(self) -> _Dict[str, Provider]: ...
|
def providers(self) -> _Dict[str, Provider]: ...
|
||||||
|
def resolve_provider_name(self, provider: Provider) -> str: ...
|
||||||
|
@property
|
||||||
|
def parent(self) -> Optional[ProviderParent]: ...
|
||||||
|
@property
|
||||||
|
def parent_name(self) -> Optional[str]: ...
|
||||||
|
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
class Callable(Provider[T]):
|
class Callable(Provider[T]):
|
||||||
|
@ -358,6 +370,12 @@ class Container(Provider[T]):
|
||||||
def __getattr__(self, name: str) -> Provider: ...
|
def __getattr__(self, name: str) -> Provider: ...
|
||||||
@property
|
@property
|
||||||
def container(self) -> T: ...
|
def container(self) -> T: ...
|
||||||
|
def resolve_provider_name(self, provider: Provider) -> str: ...
|
||||||
|
@property
|
||||||
|
def parent(self) -> Optional[ProviderParent]: ...
|
||||||
|
@property
|
||||||
|
def parent_name(self) -> Optional[str]: ...
|
||||||
|
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
class Selector(Provider[Any]):
|
class Selector(Provider[Any]):
|
||||||
|
@ -419,3 +437,6 @@ if pydantic:
|
||||||
PydanticSettings = pydantic.BaseSettings
|
PydanticSettings = pydantic.BaseSettings
|
||||||
else:
|
else:
|
||||||
PydanticSettings = Any
|
PydanticSettings = Any
|
||||||
|
|
||||||
|
|
||||||
|
CHILD_PROVIDERS: Tuple[Provider]
|
||||||
|
|
|
@ -474,6 +474,8 @@ cdef class Self(Provider):
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
copied = self.__class__()
|
copied = self.__class__()
|
||||||
|
memo[id(self)] = copied
|
||||||
|
|
||||||
copied.set_container(deepcopy(self.__container, memo))
|
copied.set_container(deepcopy(self.__container, memo))
|
||||||
copied.set_alt_names(self.__alt_names)
|
copied.set_alt_names(self.__alt_names)
|
||||||
|
|
||||||
|
@ -617,6 +619,8 @@ cdef class Dependency(Provider):
|
||||||
default = Object(default)
|
default = Object(default)
|
||||||
self.__default = default
|
self.__default = default
|
||||||
|
|
||||||
|
self.__parent = None
|
||||||
|
|
||||||
super(Dependency, self).__init__()
|
super(Dependency, self).__init__()
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
|
@ -625,9 +629,16 @@ cdef class Dependency(Provider):
|
||||||
if copied is not None:
|
if copied is not None:
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
copied_default = deepcopy(self.__default, memo) if self.__default is not UNDEFINED else UNDEFINED
|
copied_default = (
|
||||||
copied = self.__class__(self.__instance_of, copied_default)
|
deepcopy(self.__default, memo)
|
||||||
|
if self.__default is not UNDEFINED
|
||||||
|
else UNDEFINED
|
||||||
|
)
|
||||||
|
|
||||||
|
copied = self.__class__(self.__instance_of, copied_default)
|
||||||
|
memo[id(self)] = copied
|
||||||
|
|
||||||
|
self._copy_parent(copied, memo)
|
||||||
self._copy_overridings(copied, memo)
|
self._copy_overridings(copied, memo)
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
@ -644,7 +655,7 @@ cdef class Dependency(Provider):
|
||||||
elif not self.__last_overriding and self.__default is not UNDEFINED:
|
elif not self.__last_overriding and self.__default is not UNDEFINED:
|
||||||
result = self.__default(*args, **kwargs)
|
result = self.__default(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
raise Error('Dependency is not defined')
|
self._raise_undefined_error()
|
||||||
|
|
||||||
if self.is_async_mode_disabled():
|
if self.is_async_mode_disabled():
|
||||||
self._check_instance_type(result)
|
self._check_instance_type(result)
|
||||||
|
@ -697,13 +708,6 @@ cdef class Dependency(Provider):
|
||||||
"""Return default provider."""
|
"""Return default provider."""
|
||||||
return self.__default
|
return self.__default
|
||||||
|
|
||||||
@property
|
|
||||||
def related(self):
|
|
||||||
"""Return related providers generator."""
|
|
||||||
if self.__default is not UNDEFINED:
|
|
||||||
yield self.__default
|
|
||||||
yield from super().related
|
|
||||||
|
|
||||||
def provided_by(self, provider):
|
def provided_by(self, provider):
|
||||||
"""Set external dependency provider.
|
"""Set external dependency provider.
|
||||||
|
|
||||||
|
@ -714,6 +718,38 @@ cdef class Dependency(Provider):
|
||||||
"""
|
"""
|
||||||
return self.override(provider)
|
return self.override(provider)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def related(self):
|
||||||
|
"""Return related providers generator."""
|
||||||
|
if self.__default is not UNDEFINED:
|
||||||
|
yield self.__default
|
||||||
|
yield from super().related
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent(self):
|
||||||
|
"""Return parent."""
|
||||||
|
return self.__parent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent_name(self):
|
||||||
|
"""Return parent name."""
|
||||||
|
if not self.__parent:
|
||||||
|
return None
|
||||||
|
|
||||||
|
name = ''
|
||||||
|
if self.__parent.parent_name:
|
||||||
|
name += f'{self.__parent.parent_name}.'
|
||||||
|
name += f'{self.__parent.resolve_provider_name(self)}'
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
def assign_parent(self, parent):
|
||||||
|
"""Assign parent."""
|
||||||
|
self.__parent = parent
|
||||||
|
|
||||||
|
def _copy_parent(self, copied, memo):
|
||||||
|
_copy_parent(self, copied, memo)
|
||||||
|
|
||||||
def _async_provide(self, future_result, future):
|
def _async_provide(self, future_result, future):
|
||||||
instance = future.result()
|
instance = future.result()
|
||||||
try:
|
try:
|
||||||
|
@ -727,6 +763,11 @@ cdef class Dependency(Provider):
|
||||||
if not isinstance(instance, self.instance_of):
|
if not isinstance(instance, self.instance_of):
|
||||||
raise Error('{0} is not an instance of {1}'.format(instance, self.instance_of))
|
raise Error('{0} is not an instance of {1}'.format(instance, self.instance_of))
|
||||||
|
|
||||||
|
def _raise_undefined_error(self):
|
||||||
|
if self.parent_name:
|
||||||
|
raise Error(f'Dependency "{self.parent_name}" is not defined')
|
||||||
|
raise Error('Dependency is not defined')
|
||||||
|
|
||||||
|
|
||||||
cdef class ExternalDependency(Dependency):
|
cdef class ExternalDependency(Dependency):
|
||||||
""":py:class:`ExternalDependency` provider describes dependency interface.
|
""":py:class:`ExternalDependency` provider describes dependency interface.
|
||||||
|
@ -792,7 +833,13 @@ cdef class DependenciesContainer(Object):
|
||||||
|
|
||||||
def __init__(self, **dependencies):
|
def __init__(self, **dependencies):
|
||||||
"""Initializer."""
|
"""Initializer."""
|
||||||
|
for provider in dependencies.values():
|
||||||
|
if isinstance(provider, CHILD_PROVIDERS):
|
||||||
|
provider.assign_parent(self)
|
||||||
|
|
||||||
self.__providers = dependencies
|
self.__providers = dependencies
|
||||||
|
self.__parent = None
|
||||||
|
|
||||||
super(DependenciesContainer, self).__init__(None)
|
super(DependenciesContainer, self).__init__(None)
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
|
@ -804,9 +851,12 @@ cdef class DependenciesContainer(Object):
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
copied = self.__class__()
|
copied = self.__class__()
|
||||||
|
memo[id(self)] = copied
|
||||||
|
|
||||||
copied.__provides = deepcopy(self.__provides, memo)
|
copied.__provides = deepcopy(self.__provides, memo)
|
||||||
copied.__providers = deepcopy(self.__providers, memo)
|
copied.__providers = deepcopy(self.__providers, memo)
|
||||||
|
|
||||||
|
self._copy_parent(copied, memo)
|
||||||
self._copy_overridings(copied, memo)
|
self._copy_overridings(copied, memo)
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
@ -822,6 +872,8 @@ cdef class DependenciesContainer(Object):
|
||||||
provider = self.__providers.get(name)
|
provider = self.__providers.get(name)
|
||||||
if not provider:
|
if not provider:
|
||||||
provider = Dependency()
|
provider = Dependency()
|
||||||
|
provider.assign_parent(self)
|
||||||
|
|
||||||
self.__providers[name] = provider
|
self.__providers[name] = provider
|
||||||
|
|
||||||
container = self.__call__()
|
container = self.__call__()
|
||||||
|
@ -881,6 +933,39 @@ cdef class DependenciesContainer(Object):
|
||||||
yield from self.providers.values()
|
yield from self.providers.values()
|
||||||
yield from super().related
|
yield from super().related
|
||||||
|
|
||||||
|
def resolve_provider_name(self, provider):
|
||||||
|
"""Try to resolve provider name."""
|
||||||
|
for provider_name, container_provider in self.providers.items():
|
||||||
|
if container_provider is provider:
|
||||||
|
return provider_name
|
||||||
|
else:
|
||||||
|
raise Error(f'Can not resolve name for provider "{provider}"')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent(self):
|
||||||
|
"""Return parent."""
|
||||||
|
return self.__parent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent_name(self):
|
||||||
|
"""Return parent name."""
|
||||||
|
if not self.__parent:
|
||||||
|
return None
|
||||||
|
|
||||||
|
name = ''
|
||||||
|
if self.__parent.parent_name:
|
||||||
|
name += f'{self.__parent.parent_name}.'
|
||||||
|
name += f'{self.__parent.resolve_provider_name(self)}'
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
def assign_parent(self, parent):
|
||||||
|
"""Assign parent."""
|
||||||
|
self.__parent = parent
|
||||||
|
|
||||||
|
def _copy_parent(self, copied, memo):
|
||||||
|
_copy_parent(self, copied, memo)
|
||||||
|
|
||||||
cpdef object _override_providers(self, object container):
|
cpdef object _override_providers(self, object container):
|
||||||
"""Override providers with providers from provided container."""
|
"""Override providers with providers from provided container."""
|
||||||
for name, dependency_provider in container.providers.items():
|
for name, dependency_provider in container.providers.items():
|
||||||
|
@ -3443,23 +3528,32 @@ cdef class Container(Provider):
|
||||||
|
|
||||||
if container is None:
|
if container is None:
|
||||||
container = container_cls()
|
container = container_cls()
|
||||||
|
container.assign_parent(self)
|
||||||
self.__container = container
|
self.__container = container
|
||||||
|
|
||||||
|
if self.__container and self.__overriding_providers:
|
||||||
self.apply_overridings()
|
self.apply_overridings()
|
||||||
|
|
||||||
|
self.__parent = None
|
||||||
|
|
||||||
super(Container, self).__init__()
|
super(Container, self).__init__()
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
"""Create and return full copy of provider."""
|
"""Create and return full copy of provider."""
|
||||||
|
cdef Container copied
|
||||||
|
|
||||||
copied = memo.get(id(self))
|
copied = memo.get(id(self))
|
||||||
if copied is not None:
|
if copied is not None:
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
copied = self.__class__(
|
copied = self.__class__(self.__container_cls, UNDEFINED)
|
||||||
self.__container_cls,
|
memo[id(self)] = copied
|
||||||
deepcopy(self.__container, memo),
|
|
||||||
**deepcopy(self.__overriding_providers, memo),
|
copied.__container = deepcopy(self.__container, memo)
|
||||||
)
|
copied.__overriding_providers = deepcopy(self.__overriding_providers, memo)
|
||||||
|
copied.apply_overridings()
|
||||||
|
|
||||||
|
self._copy_parent(copied, memo)
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
|
@ -3501,6 +3595,39 @@ cdef class Container(Provider):
|
||||||
yield from self.providers.values()
|
yield from self.providers.values()
|
||||||
yield from super().related
|
yield from super().related
|
||||||
|
|
||||||
|
def resolve_provider_name(self, provider):
|
||||||
|
"""Try to resolve provider name."""
|
||||||
|
for provider_name, container_provider in self.providers.items():
|
||||||
|
if container_provider is provider:
|
||||||
|
return provider_name
|
||||||
|
else:
|
||||||
|
raise Error(f'Can not resolve name for provider "{provider}"')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent(self):
|
||||||
|
"""Return parent."""
|
||||||
|
return self.__parent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent_name(self):
|
||||||
|
"""Return parent name."""
|
||||||
|
if not self.__parent:
|
||||||
|
return None
|
||||||
|
|
||||||
|
name = ''
|
||||||
|
if self.__parent.parent_name:
|
||||||
|
name += f'{self.__parent.parent_name}.'
|
||||||
|
name += f'{self.__parent.resolve_provider_name(self)}'
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
def assign_parent(self, parent):
|
||||||
|
"""Assign parent."""
|
||||||
|
self.__parent = parent
|
||||||
|
|
||||||
|
def _copy_parent(self, copied, memo):
|
||||||
|
_copy_parent(self, copied, memo)
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs):
|
cpdef object _provide(self, tuple args, dict kwargs):
|
||||||
"""Return single instance."""
|
"""Return single instance."""
|
||||||
return self.__container
|
return self.__container
|
||||||
|
@ -4033,6 +4160,9 @@ cpdef tuple parse_named_injections(dict kwargs):
|
||||||
return tuple(injections)
|
return tuple(injections)
|
||||||
|
|
||||||
|
|
||||||
|
CHILD_PROVIDERS = (Dependency, DependenciesContainer, Container)
|
||||||
|
|
||||||
|
|
||||||
cpdef bint is_provider(object instance):
|
cpdef bint is_provider(object instance):
|
||||||
"""Check if instance is provider instance.
|
"""Check if instance is provider instance.
|
||||||
|
|
||||||
|
@ -4093,6 +4223,30 @@ cpdef str represent_provider(object provider, object provides):
|
||||||
address=hex(id(provider)))
|
address=hex(id(provider)))
|
||||||
|
|
||||||
|
|
||||||
|
cpdef bint is_container_instance(object instance):
|
||||||
|
"""Check if instance is container instance.
|
||||||
|
|
||||||
|
:param instance: Instance to be checked.
|
||||||
|
:type instance: object
|
||||||
|
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return (not isinstance(instance, CLASS_TYPES) and
|
||||||
|
getattr(instance, '__IS_CONTAINER__', False) is True)
|
||||||
|
|
||||||
|
|
||||||
|
cpdef bint is_container_class(object instance):
|
||||||
|
"""Check if instance is container class.
|
||||||
|
|
||||||
|
:param instance: Instance to be checked.
|
||||||
|
:type instance: object
|
||||||
|
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return (isinstance(instance, CLASS_TYPES) and
|
||||||
|
getattr(instance, '__IS_CONTAINER__', False) is True)
|
||||||
|
|
||||||
|
|
||||||
cpdef object deepcopy(object instance, dict memo=None):
|
cpdef object deepcopy(object instance, dict memo=None):
|
||||||
"""Return full copy of provider or container with providers."""
|
"""Return full copy of provider or container with providers."""
|
||||||
if memo is None:
|
if memo is None:
|
||||||
|
@ -4102,6 +4256,7 @@ cpdef object deepcopy(object instance, dict memo=None):
|
||||||
|
|
||||||
return copy.deepcopy(instance, memo)
|
return copy.deepcopy(instance, memo)
|
||||||
|
|
||||||
|
|
||||||
def __add_sys_streams(memo):
|
def __add_sys_streams(memo):
|
||||||
"""Add system streams to memo dictionary.
|
"""Add system streams to memo dictionary.
|
||||||
|
|
||||||
|
@ -4188,3 +4343,13 @@ def isasyncgenfunction(obj):
|
||||||
return inspect.isasyncgenfunction(obj)
|
return inspect.isasyncgenfunction(obj)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
cpdef _copy_parent(object from_, object to, dict memo):
|
||||||
|
"""Copy and assign provider parent."""
|
||||||
|
copied_parent = (
|
||||||
|
deepcopy(from_.parent, memo)
|
||||||
|
if is_provider(from_.parent) or is_container_instance(from_.parent)
|
||||||
|
else from_.parent
|
||||||
|
)
|
||||||
|
to.assign_parent(copied_parent)
|
||||||
|
|
|
@ -224,7 +224,7 @@ class DeclarativeContainerTests(unittest.TestCase):
|
||||||
(_OverridingContainer1.p11,
|
(_OverridingContainer1.p11,
|
||||||
_OverridingContainer2.p11))
|
_OverridingContainer2.p11))
|
||||||
|
|
||||||
def test_reset_last_overridding(self):
|
def test_reset_last_overriding(self):
|
||||||
class _Container(containers.DeclarativeContainer):
|
class _Container(containers.DeclarativeContainer):
|
||||||
p11 = providers.Provider()
|
p11 = providers.Provider()
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ class DeclarativeContainerTests(unittest.TestCase):
|
||||||
self.assertEqual(_Container.p11.overridden,
|
self.assertEqual(_Container.p11.overridden,
|
||||||
(_OverridingContainer1.p11,))
|
(_OverridingContainer1.p11,))
|
||||||
|
|
||||||
def test_reset_last_overridding_when_not_overridden(self):
|
def test_reset_last_overriding_when_not_overridden(self):
|
||||||
with self.assertRaises(errors.Error):
|
with self.assertRaises(errors.Error):
|
||||||
ContainerA.reset_last_overriding()
|
ContainerA.reset_last_overriding()
|
||||||
|
|
||||||
|
@ -431,3 +431,68 @@ class DeclarativeContainerTests(unittest.TestCase):
|
||||||
self.assertIsInstance(container.p31, providers.Provider)
|
self.assertIsInstance(container.p31, providers.Provider)
|
||||||
self.assertIsInstance(container.p32, providers.Provider)
|
self.assertIsInstance(container.p32, providers.Provider)
|
||||||
self.assertIs(container.p11.last_overriding, provider)
|
self.assertIs(container.p11.last_overriding, provider)
|
||||||
|
|
||||||
|
def test_parent_set_in__new__(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
dependency = providers.Dependency()
|
||||||
|
dependencies_container = providers.DependenciesContainer()
|
||||||
|
container = providers.Container(ContainerA)
|
||||||
|
|
||||||
|
self.assertIs(Container.dependency.parent, Container)
|
||||||
|
self.assertIs(Container.dependencies_container.parent, Container)
|
||||||
|
self.assertIs(Container.container.parent, Container)
|
||||||
|
|
||||||
|
def test_parent_set_in__setattr__(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
pass
|
||||||
|
|
||||||
|
Container.dependency = providers.Dependency()
|
||||||
|
Container.dependencies_container = providers.DependenciesContainer()
|
||||||
|
Container.container = providers.Container(ContainerA)
|
||||||
|
|
||||||
|
self.assertIs(Container.dependency.parent, Container)
|
||||||
|
self.assertIs(Container.dependencies_container.parent, Container)
|
||||||
|
self.assertIs(Container.container.parent, Container)
|
||||||
|
|
||||||
|
def test_resolve_provider_name(self):
|
||||||
|
self.assertEqual(ContainerA.resolve_provider_name(ContainerA.p11), 'p11')
|
||||||
|
|
||||||
|
def test_resolve_provider_name_no_provider(self):
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
ContainerA.resolve_provider_name(providers.Provider())
|
||||||
|
|
||||||
|
def test_child_dependency_parent_name(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
dependency = providers.Dependency()
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
Container.dependency()
|
||||||
|
self.assertEqual(
|
||||||
|
str(context.exception),
|
||||||
|
'Dependency "Container.dependency" is not defined',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_child_dependencies_container_parent_name(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
dependencies_container = providers.DependenciesContainer()
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
Container.dependencies_container.dependency()
|
||||||
|
self.assertEqual(
|
||||||
|
str(context.exception),
|
||||||
|
'Dependency "Container.dependencies_container.dependency" is not defined',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_child_container_parent_name(self):
|
||||||
|
class ChildContainer(containers.DeclarativeContainer):
|
||||||
|
dependency = providers.Dependency()
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
child_container = providers.Container(ChildContainer)
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
Container.child_container.dependency()
|
||||||
|
self.assertEqual(
|
||||||
|
str(context.exception),
|
||||||
|
'Dependency "Container.child_container.dependency" is not defined',
|
||||||
|
)
|
||||||
|
|
|
@ -336,6 +336,62 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
|
||||||
self.assertIs(obj32, obj42)
|
self.assertIs(obj32, obj42)
|
||||||
self.assertIs(obj33, obj43)
|
self.assertIs(obj33, obj43)
|
||||||
|
|
||||||
|
def test_assign_parent(self):
|
||||||
|
parent = providers.DependenciesContainer()
|
||||||
|
container = ContainerA()
|
||||||
|
|
||||||
|
container.assign_parent(parent)
|
||||||
|
|
||||||
|
self.assertIs(container.parent, parent)
|
||||||
|
|
||||||
|
def test_parent_name_declarative_parent(self):
|
||||||
|
container = ContainerA()
|
||||||
|
self.assertEqual(container.parent_name, 'ContainerA')
|
||||||
|
|
||||||
|
def test_parent_name(self):
|
||||||
|
container = ContainerA()
|
||||||
|
self.assertEqual(container.parent_name, 'ContainerA')
|
||||||
|
|
||||||
|
def test_parent_name_with_deep_parenting(self):
|
||||||
|
class Container2(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
name = providers.Container(ContainerA)
|
||||||
|
|
||||||
|
class Container1(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
container = providers.Container(Container2)
|
||||||
|
|
||||||
|
container = Container1()
|
||||||
|
self.assertEqual(container.container().name.parent_name, 'Container1.container.name')
|
||||||
|
|
||||||
|
def test_parent_name_is_none(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
self.assertIsNone(container.parent_name)
|
||||||
|
|
||||||
|
def test_parent_deepcopy(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
container = providers.Container(ContainerA)
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
copied = providers.deepcopy(container)
|
||||||
|
|
||||||
|
self.assertIs(container.container.parent, container)
|
||||||
|
self.assertIs(copied.container.parent, copied)
|
||||||
|
|
||||||
|
self.assertIsNot(container, copied)
|
||||||
|
self.assertIsNot(container.container, copied.container)
|
||||||
|
self.assertIsNot(container.container.parent, copied.container.parent)
|
||||||
|
|
||||||
|
def test_resolve_provider_name(self):
|
||||||
|
container = ContainerA()
|
||||||
|
self.assertEqual(container.resolve_provider_name(container.p11), 'p11')
|
||||||
|
|
||||||
|
def test_resolve_provider_name_no_provider(self):
|
||||||
|
container = ContainerA()
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
container.resolve_provider_name(providers.Provider())
|
||||||
|
|
||||||
|
|
||||||
class SelfTests(unittest.TestCase):
|
class SelfTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -360,8 +360,128 @@ class DependencyTests(unittest.TestCase):
|
||||||
self.provider.provided_by(providers.Factory(dict))
|
self.provider.provided_by(providers.Factory(dict))
|
||||||
self.assertRaises(errors.Error, self.provider)
|
self.assertRaises(errors.Error, self.provider)
|
||||||
|
|
||||||
def test_call_not_overridden(self):
|
def test_call_undefined(self):
|
||||||
self.assertRaises(errors.Error, self.provider)
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
self.provider()
|
||||||
|
self.assertEqual(str(context.exception), 'Dependency is not defined')
|
||||||
|
|
||||||
|
def test_call_undefined_error_message_with_container_instance_parent(self):
|
||||||
|
class UserService:
|
||||||
|
def __init__(self, database):
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
database = providers.Dependency()
|
||||||
|
|
||||||
|
user_service = providers.Factory(
|
||||||
|
UserService,
|
||||||
|
database=database, # <---- missing dependency
|
||||||
|
)
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
container.user_service()
|
||||||
|
|
||||||
|
self.assertEqual(str(context.exception), 'Dependency "Container.database" is not defined')
|
||||||
|
|
||||||
|
def test_call_undefined_error_message_with_container_provider_parent_deep(self):
|
||||||
|
class Database:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UserService:
|
||||||
|
def __init__(self, db):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
class Gateways(containers.DeclarativeContainer):
|
||||||
|
database_client = providers.Singleton(Database)
|
||||||
|
|
||||||
|
class Services(containers.DeclarativeContainer):
|
||||||
|
gateways = providers.DependenciesContainer()
|
||||||
|
|
||||||
|
user = providers.Factory(
|
||||||
|
UserService,
|
||||||
|
db=gateways.database_client,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
gateways = providers.Container(Gateways)
|
||||||
|
|
||||||
|
services = providers.Container(
|
||||||
|
Services,
|
||||||
|
# gateways=gateways, # <---- missing dependency
|
||||||
|
)
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
container.services().user()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(context.exception),
|
||||||
|
'Dependency "Container.services.gateways.database_client" is not defined',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_call_undefined_error_message_with_dependenciescontainer_provider_parent(self):
|
||||||
|
class UserService:
|
||||||
|
def __init__(self, db):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
class Services(containers.DeclarativeContainer):
|
||||||
|
gateways = providers.DependenciesContainer()
|
||||||
|
|
||||||
|
user = providers.Factory(
|
||||||
|
UserService,
|
||||||
|
db=gateways.database_client, # <---- missing dependency
|
||||||
|
)
|
||||||
|
|
||||||
|
services = Services()
|
||||||
|
|
||||||
|
with self.assertRaises(errors.Error) as context:
|
||||||
|
services.user()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(context.exception),
|
||||||
|
'Dependency "Services.gateways.database_client" is not defined',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_assign_parent(self):
|
||||||
|
parent = providers.DependenciesContainer()
|
||||||
|
provider = providers.Dependency()
|
||||||
|
|
||||||
|
provider.assign_parent(parent)
|
||||||
|
|
||||||
|
self.assertIs(provider.parent, parent)
|
||||||
|
|
||||||
|
def test_parent_name(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
provider = providers.Dependency()
|
||||||
|
container.name = provider
|
||||||
|
self.assertEqual(provider.parent_name, 'name')
|
||||||
|
|
||||||
|
def test_parent_name_with_deep_parenting(self):
|
||||||
|
provider = providers.Dependency()
|
||||||
|
container = providers.DependenciesContainer(name=provider)
|
||||||
|
_ = providers.DependenciesContainer(container=container)
|
||||||
|
self.assertEqual(provider.parent_name, 'container.name')
|
||||||
|
|
||||||
|
def test_parent_name_is_none(self):
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
self.assertIsNone(provider.parent_name)
|
||||||
|
|
||||||
|
def test_parent_deepcopy(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
provider = providers.Dependency()
|
||||||
|
container.name = provider
|
||||||
|
|
||||||
|
copied = providers.deepcopy(container)
|
||||||
|
|
||||||
|
self.assertIs(container.name.parent, container)
|
||||||
|
self.assertIs(copied.name.parent, copied)
|
||||||
|
|
||||||
|
self.assertIsNot(container, copied)
|
||||||
|
self.assertIsNot(container.name, copied.name)
|
||||||
|
self.assertIsNot(container.name.parent, copied.name.parent)
|
||||||
|
|
||||||
def test_deepcopy(self):
|
def test_deepcopy(self):
|
||||||
provider = providers.Dependency(int)
|
provider = providers.Dependency(int)
|
||||||
|
@ -523,3 +643,61 @@ class DependenciesContainerTests(unittest.TestCase):
|
||||||
|
|
||||||
self.assertFalse(dependency.overridden)
|
self.assertFalse(dependency.overridden)
|
||||||
self.assertFalse(dependency.overridden)
|
self.assertFalse(dependency.overridden)
|
||||||
|
|
||||||
|
def test_assign_parent(self):
|
||||||
|
parent = providers.DependenciesContainer()
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
|
||||||
|
provider.assign_parent(parent)
|
||||||
|
|
||||||
|
self.assertIs(provider.parent, parent)
|
||||||
|
|
||||||
|
def test_parent_name(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
container.name = provider
|
||||||
|
self.assertEqual(provider.parent_name, 'name')
|
||||||
|
|
||||||
|
def test_parent_name_with_deep_parenting(self):
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
container = providers.DependenciesContainer(name=provider)
|
||||||
|
_ = providers.DependenciesContainer(container=container)
|
||||||
|
self.assertEqual(provider.parent_name, 'container.name')
|
||||||
|
|
||||||
|
def test_parent_name_is_none(self):
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
self.assertIsNone(provider.parent_name)
|
||||||
|
|
||||||
|
def test_parent_deepcopy(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
container.name = provider
|
||||||
|
|
||||||
|
copied = providers.deepcopy(container)
|
||||||
|
|
||||||
|
self.assertIs(container.name.parent, container)
|
||||||
|
self.assertIs(copied.name.parent, copied)
|
||||||
|
|
||||||
|
self.assertIsNot(container, copied)
|
||||||
|
self.assertIsNot(container.name, copied.name)
|
||||||
|
self.assertIsNot(container.name.parent, copied.name.parent)
|
||||||
|
|
||||||
|
def test_parent_set_on__getattr__(self):
|
||||||
|
provider = providers.DependenciesContainer()
|
||||||
|
self.assertIsInstance(provider.name, providers.Dependency)
|
||||||
|
self.assertIs(provider.name.parent, provider)
|
||||||
|
|
||||||
|
def test_parent_set_on__init__(self):
|
||||||
|
provider = providers.Dependency()
|
||||||
|
container = providers.DependenciesContainer(name=provider)
|
||||||
|
self.assertIs(container.name, provider)
|
||||||
|
self.assertIs(container.name.parent, container)
|
||||||
|
|
||||||
|
def test_resolve_provider_name(self):
|
||||||
|
container = providers.DependenciesContainer()
|
||||||
|
self.assertEqual(container.resolve_provider_name(container.name), 'name')
|
||||||
|
|
||||||
|
def test_resolve_provider_name_no_provider(self):
|
||||||
|
container = providers.DependenciesContainer()
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
container.resolve_provider_name(providers.Provider())
|
||||||
|
|
|
@ -175,3 +175,50 @@ class ContainerTests(unittest.TestCase):
|
||||||
b = B(d=D())
|
b = B(d=D())
|
||||||
result = b.a().c().bar()
|
result = b.a().c().bar()
|
||||||
self.assertEqual(result, 'foo++')
|
self.assertEqual(result, 'foo++')
|
||||||
|
|
||||||
|
def test_assign_parent(self):
|
||||||
|
parent = providers.DependenciesContainer()
|
||||||
|
provider = providers.Container(TestCore)
|
||||||
|
|
||||||
|
provider.assign_parent(parent)
|
||||||
|
|
||||||
|
self.assertIs(provider.parent, parent)
|
||||||
|
|
||||||
|
def test_parent_name(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
provider = providers.Container(TestCore)
|
||||||
|
container.name = provider
|
||||||
|
self.assertEqual(provider.parent_name, 'name')
|
||||||
|
|
||||||
|
def test_parent_name_with_deep_parenting(self):
|
||||||
|
provider = providers.Container(TestCore)
|
||||||
|
container = providers.DependenciesContainer(name=provider)
|
||||||
|
_ = providers.DependenciesContainer(container=container)
|
||||||
|
self.assertEqual(provider.parent_name, 'container.name')
|
||||||
|
|
||||||
|
def test_parent_name_is_none(self):
|
||||||
|
provider = providers.Container(TestCore)
|
||||||
|
self.assertIsNone(provider.parent_name)
|
||||||
|
|
||||||
|
def test_parent_deepcopy(self):
|
||||||
|
container = containers.DynamicContainer()
|
||||||
|
provider = providers.Container(TestCore)
|
||||||
|
container.name = provider
|
||||||
|
|
||||||
|
copied = providers.deepcopy(container)
|
||||||
|
|
||||||
|
self.assertIs(container.name.parent, container)
|
||||||
|
self.assertIs(copied.name.parent, copied)
|
||||||
|
|
||||||
|
self.assertIsNot(container, copied)
|
||||||
|
self.assertIsNot(container.name, copied.name)
|
||||||
|
self.assertIsNot(container.name.parent, copied.name.parent)
|
||||||
|
|
||||||
|
def test_resolve_provider_name(self):
|
||||||
|
container = providers.Container(TestCore)
|
||||||
|
self.assertEqual(container.resolve_provider_name(container.value_getter), 'value_getter')
|
||||||
|
|
||||||
|
def test_resolve_provider_name_no_provider(self):
|
||||||
|
container = providers.Container(TestCore)
|
||||||
|
with self.assertRaises(errors.Error):
|
||||||
|
container.resolve_provider_name(providers.Provider())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user