mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 19:14:00 +03:00
Add prototype for flat resolving
This commit is contained in:
parent
81da4e0451
commit
1c433ed0ad
File diff suppressed because it is too large
Load Diff
|
@ -38,13 +38,13 @@ 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]: ...
|
||||||
def shutdown_resources(self) -> Optional[Awaitable]: ...
|
def shutdown_resources(self) -> Optional[Awaitable]: ...
|
||||||
def apply_container_providers_overridings(self) -> None: ...
|
def apply_container_providers_overridings(self) -> None: ...
|
||||||
def reset_singletons(self) -> None: ...
|
def reset_singletons(self) -> None: ...
|
||||||
|
def resolve_provider_name(self, provider: Provider) -> Optional[str]: ...
|
||||||
@overload
|
@overload
|
||||||
def traverse(self, types: Optional[Iterable[Type[TT]]] = None) -> _Iterator[TT]: ...
|
def traverse(self, types: Optional[Iterable[Type[TT]]] = None) -> _Iterator[TT]: ...
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -110,7 +110,12 @@ class DynamicContainer(Container):
|
||||||
"""
|
"""
|
||||||
if isinstance(value, providers.Provider) and not isinstance(value, providers.Self):
|
if isinstance(value, providers.Provider) and not isinstance(value, providers.Self):
|
||||||
_check_provider_type(self, value)
|
_check_provider_type(self, value)
|
||||||
|
|
||||||
self.providers[name] = value
|
self.providers[name] = value
|
||||||
|
|
||||||
|
if isinstance(value, providers.Dependency):
|
||||||
|
value.set_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 +300,15 @@ 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."""
|
||||||
|
# TODO: add tests
|
||||||
|
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}"')
|
||||||
|
|
||||||
|
|
||||||
class DeclarativeContainerMetaClass(type):
|
class DeclarativeContainerMetaClass(type):
|
||||||
"""Declarative inversion of control container meta class."""
|
"""Declarative inversion of control container meta class."""
|
||||||
|
@ -317,6 +331,8 @@ class DeclarativeContainerMetaClass(type):
|
||||||
if isinstance(provider, providers.Provider) and not isinstance(provider, providers.Self)
|
if isinstance(provider, providers.Provider) and not isinstance(provider, providers.Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO: set dependencies parent
|
||||||
|
|
||||||
inherited_providers = {
|
inherited_providers = {
|
||||||
name: provider
|
name: provider
|
||||||
for base in bases
|
for base in bases
|
||||||
|
@ -361,6 +377,7 @@ class DeclarativeContainerMetaClass(type):
|
||||||
_check_provider_type(cls, value)
|
_check_provider_type(cls, value)
|
||||||
cls.providers[name] = value
|
cls.providers[name] = value
|
||||||
cls.cls_providers[name] = value
|
cls.cls_providers[name] = value
|
||||||
|
# TODO: set dependencies parent
|
||||||
super(DeclarativeContainerMetaClass, cls).__setattr__(name, value)
|
super(DeclarativeContainerMetaClass, cls).__setattr__(name, value)
|
||||||
|
|
||||||
def __delattr__(cls, str name):
|
def __delattr__(cls, str name):
|
||||||
|
|
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):
|
||||||
|
@ -305,6 +306,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')
|
||||||
|
|
||||||
|
@ -105,6 +106,9 @@ class Dependency(Provider[T]):
|
||||||
def instance_of(self) -> Type[T]: ...
|
def instance_of(self) -> Type[T]: ...
|
||||||
@property
|
@property
|
||||||
def default(self) -> Provider[T]: ...
|
def default(self) -> Provider[T]: ...
|
||||||
|
@property
|
||||||
|
def parent(self) -> ProviderParent: ...
|
||||||
|
def set_parent(self, parent: ProviderParent) -> None: ...
|
||||||
def provided_by(self, provider: Provider) -> OverridingContext: ...
|
def provided_by(self, provider: Provider) -> OverridingContext: ...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -617,6 +617,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,8 +627,20 @@ 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 = (
|
||||||
|
deepcopy(self.__default, memo)
|
||||||
|
if self.__default is not UNDEFINED
|
||||||
|
else UNDEFINED
|
||||||
|
)
|
||||||
|
copied_parent = (
|
||||||
|
deepcopy(self.__parent, memo)
|
||||||
|
if is_provider(self.parent) or is_container_instance(self.parent)
|
||||||
|
else self.parent
|
||||||
|
)
|
||||||
|
|
||||||
copied = self.__class__(self.__instance_of, copied_default)
|
copied = self.__class__(self.__instance_of, copied_default)
|
||||||
|
# TODO: introduce .set_default() for consistency
|
||||||
|
copied.set_parent(copied_parent)
|
||||||
|
|
||||||
self._copy_overridings(copied, memo)
|
self._copy_overridings(copied, memo)
|
||||||
|
|
||||||
|
@ -644,7 +658,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,6 +711,15 @@ cdef class Dependency(Provider):
|
||||||
"""Return default provider."""
|
"""Return default provider."""
|
||||||
return self.__default
|
return self.__default
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent(self):
|
||||||
|
"""Return parent."""
|
||||||
|
return self.__parent
|
||||||
|
|
||||||
|
def set_parent(self, parent):
|
||||||
|
"""Set parent."""
|
||||||
|
self.__parent = parent
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def related(self):
|
def related(self):
|
||||||
"""Return related providers generator."""
|
"""Return related providers generator."""
|
||||||
|
@ -727,6 +750,14 @@ 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 is_container_instance(self.parent) and self.parent.declarative_parent is not None:
|
||||||
|
name_in_container = self.parent.resolve_provider_name(self)
|
||||||
|
name = f'{self.parent.declarative_parent.__name__}.{name_in_container}'
|
||||||
|
raise Error(f'Dependency "{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.
|
||||||
|
@ -4093,6 +4124,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 +4157,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.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user