Add implementation

This commit is contained in:
Roman Mogylatov 2021-02-06 19:45:00 -05:00
parent ce6d3df72c
commit 41f8009811
7 changed files with 12705 additions and 9168 deletions

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,7 @@ class Container:
def __setattr__(self, name: str, value: Union[Provider, Any]) -> None: ...
def __delattr__(self, name: str) -> None: ...
def set_providers(self, **providers: Provider): ...
def set_provider(self, name: str, provider: Provider) -> None: ...
def override(self, overriding: C_Base) -> None: ...
def override_providers(self, **overriding_providers: Provider) -> None: ...
def reset_last_overriding(self) -> None: ...

View File

@ -69,7 +69,7 @@ class DynamicContainer(Container):
self.declarative_parent = None
self.wired_to_modules = []
self.wired_to_packages = []
self.__self__ = providers.Object(self)
self.__self__ = providers.Self(self)
super(DynamicContainer, self).__init__()
def __deepcopy__(self, memo):
@ -102,7 +102,7 @@ class DynamicContainer(Container):
:rtype: None
"""
if isinstance(value, providers.Provider) and name != '__self__':
if isinstance(value, providers.Provider) and not isinstance(value, providers.Self):
_check_provider_type(self, value)
self.providers[name] = value
super(DynamicContainer, self).__setattr__(name, value)
@ -154,6 +154,19 @@ class DynamicContainer(Container):
for name, provider in six.iteritems(providers):
setattr(self, name, provider)
def set_provider(self, name, provider):
"""Set container provider.
:param name: Provider name
:type name: str
:param provider: Provider
:type provider: :py:class:`dependency_injector.providers.Provider`
:rtype: None
"""
setattr(self, name, provider)
def override(self, object overriding):
"""Override current container by overriding container.
@ -282,6 +295,10 @@ class DeclarativeContainerMetaClass(type):
def __new__(type mcs, str class_name, tuple bases, dict attributes):
"""Declarative container class factory."""
self = mcs.__fetch_self(attributes)
if self is None:
self = providers.Self()
containers = {
name: container
for name, container in six.iteritems(attributes)
@ -291,7 +308,7 @@ class DeclarativeContainerMetaClass(type):
cls_providers = {
name: provider
for name, provider in six.iteritems(attributes)
if isinstance(provider, providers.Provider)
if isinstance(provider, providers.Provider) and not isinstance(provider, providers.Self)
}
inherited_providers = {
@ -312,7 +329,8 @@ class DeclarativeContainerMetaClass(type):
cls = <type>type.__new__(mcs, class_name, bases, attributes)
cls.__self__ = providers.Object(cls)
self.set_container(cls)
cls.__self__ = self
for provider in six.itervalues(cls.providers):
_check_provider_type(cls, provider)
@ -375,6 +393,28 @@ class DeclarativeContainerMetaClass(type):
"""Return providers traversal generator."""
yield from providers.traverse(*cls.providers.values(), types=types)
@staticmethod
def __fetch_self(attributes):
self = None
alt_names = []
for name, value in attributes.items():
if not isinstance(value, providers.Self):
continue
if self is not None and value is not self:
raise errors.Error('Container can have only one "Self" provider')
if name != '__self__':
alt_names.append(name)
self = value
if self:
self.set_alt_names(alt_names)
return self
@six.add_metaclass(DeclarativeContainerMetaClass)
class DeclarativeContainer(Container):
@ -448,9 +488,21 @@ class DeclarativeContainer(Container):
container = cls.instance_type()
container.provider_type = cls.provider_type
container.declarative_parent = cls
container.set_providers(**providers.deepcopy(cls.providers))
copied_providers = providers.deepcopy({ **cls.providers, **{'@@self@@': cls.__self__}})
copied_self = copied_providers.pop('@@self@@')
copied_self.set_container(container)
container.__self__ = copied_self
for name in copied_self.alt_names:
container.set_provider(name, copied_self)
for name, provider in copied_providers.items():
container.set_provider(name, provider)
container.override_providers(**overriding_providers)
container.apply_container_providers_overridings()
return container
@classmethod

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,11 @@ cdef class Object(Provider):
cpdef object _provide(self, tuple args, dict kwargs)
cdef class Self(Provider):
cdef object __container
cdef tuple __alt_names
cdef class Delegate(Provider):
cdef object __provides

View File

@ -85,6 +85,14 @@ class Object(Provider[T]):
def __init__(self, provides: T) -> None: ...
class Self(Provider[T]):
def __init__(self, container: Optional[T] = None) -> None: ...
def set_container(self, container: T) -> None: ...
def set_alt_names(self, alt_names: _Iterable[Any]) -> None: ...
@property
def alt_names(self) -> Tuple[Any]: ...
class Delegate(Provider[Provider]):
def __init__(self, provides: Provider) -> None: ...
@property

View File

@ -458,6 +458,62 @@ cdef class Object(Provider):
return self.__provides
cdef class Self(Provider):
"""Self provider returns own container."""
def __init__(self, container=None):
"""Initialize provider."""
self.__container = container
self.__alt_names = tuple()
super().__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__()
copied.set_container(deepcopy(self.__container, memo))
copied.set_alt_names(self.__alt_names)
self._copy_overridings(copied, memo)
return copied
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return represent_provider(provider=self, provides=self.__container)
def __repr__(self):
"""Return string representation of provider.
:rtype: str
"""
return self.__str__()
def set_container(self, container):
self.__container = container
def set_alt_names(self, alt_names):
self.__alt_names = tuple(set(alt_names))
@property
def alt_names(self):
return self.__alt_names
@property
def related(self):
"""Return related providers generator."""
yield from super().related
cpdef object _provide(self, tuple args, dict kwargs):
return self.__container
cdef class Delegate(Provider):
"""Delegate provider returns provider "as is".