Add experimental config fixes

This commit is contained in:
Roman Mogylatov 2020-06-22 21:20:54 -04:00
parent 40e3e4c8cc
commit 4554df8315
9 changed files with 4991 additions and 4392 deletions

37
config_fix.py Normal file
View File

@ -0,0 +1,37 @@
from dependency_injector import containers, providers
CONFIG = {'core': {'value': 123}}
CONFIG2 = {'core': {'value': 124}}
def fn(value):
return value
def fn_2(fn):
fn()
class Core(containers.DeclarativeContainer):
config = providers.Configuration('core')
fn = providers.Callable(fn, value=config.value)
class Application(containers.DeclarativeContainer):
"""Application container."""
config = providers.Configuration('config')
core = Core(config=config.core)
fd = providers.Callable(dict, fn=core.fn)
if __name__ == '__main__':
application = Application(config=CONFIG)
print(application.fd())
application.config.override(CONFIG2)
print(application.fd())

45
config_test.py Normal file
View File

@ -0,0 +1,45 @@
from dependency_injector import containers, providers
def get_value(value):
return value
class Core(containers.DeclarativeContainer):
config = providers.Configuration('core')
value_getter = providers.Callable(get_value, config.value)
class Services(containers.DeclarativeContainer):
config = providers.Configuration('services')
value_getter = providers.Callable(get_value, config.value)
root_config = providers.Configuration('main')
core = Core(config=root_config.core)
services = Services(config=root_config.services)
root_config.override(
{
'core': {
'value': 'core',
},
'services': {
'value': 'services',
},
},
)
print(core.value_getter())
print(services.value_getter())
print(core.config(), core.config.value())
print(services.config(), services.config.value())
print(root_config.children)
print(core.config.children)
print(services.config.children)

36
config_test2.py Normal file
View File

@ -0,0 +1,36 @@
from dependency_injector import containers, providers
def get_value(value):
return value
class Core(containers.DeclarativeContainer):
config = providers.Configuration('core')
value_getter = providers.Callable(get_value, config.value)
class Services(containers.DeclarativeContainer):
config = providers.Configuration('services')
value_getter = providers.Callable(get_value, config.value)
root_config = providers.Configuration('main')
sub_config = providers.Configuration('sub')
sub_config.override(root_config.core)
root_config.override(
{
'core': {
'value': 'core',
},
},
)
print(sub_config())
print(sub_config.value())

22
object_test.py Normal file
View File

@ -0,0 +1,22 @@
from dependency_injector import providers
object1 = providers.Object(1)
object2 = providers.Object(2)
object3 = providers.Object(3)
# 1
assert object1() == 1
# 2
object1.override(object2)
assert object1() == 2
# 3
object2.override(object3)
assert object1() == 3
print('Success')

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,19 @@ class DynamicContainer(object):
self.overridden = tuple() self.overridden = tuple()
super(DynamicContainer, self).__init__() super(DynamicContainer, 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__()
copied.provider_type = Provider
copied.providers = deepcopy(self.providers, memo)
copied.overridden = deepcopy(self.overridden, memo)
return copied
def __setattr__(self, str name, object value): def __setattr__(self, str name, object value):
"""Set instance attribute. """Set instance attribute.

File diff suppressed because it is too large Load Diff

View File

@ -92,6 +92,7 @@ cdef class CoroutineDelegate(Delegate):
cdef class Configuration(Object): cdef class Configuration(Object):
cdef str __name cdef str __name
cdef dict __children cdef dict __children
cdef list __linked
# Factory providers # Factory providers
@ -175,8 +176,10 @@ cdef class List(Provider):
cpdef object _provide(self, tuple args, dict kwargs) cpdef object _provide(self, tuple args, dict kwargs)
cdef class Container(Singleton): cdef class Container(Provider):
pass cdef object container_cls
cdef dict overriding_providers
cdef object container
# Injections # Injections

View File

@ -541,7 +541,7 @@ cdef class DependenciesContainer(Object):
provider = Dependency() provider = Dependency()
self.__providers[name] = provider self.__providers[name] = provider
container = self.__call__() container = self.__provides
if container: if container:
dependency_provider = container.providers.get(name) dependency_provider = container.providers.get(name)
if dependency_provider: if dependency_provider:
@ -598,6 +598,9 @@ cdef class DependenciesContainer(Object):
provider = self.__providers.get(name) provider = self.__providers.get(name)
if not provider: if not provider:
provider = Dependency()
provider.override(dependency_provider)
self.__providers[name] = provider
continue continue
if provider.last_overriding is dependency_provider: if provider.last_overriding is dependency_provider:
@ -1029,6 +1032,7 @@ cdef class Configuration(Object):
self.__name = name self.__name = name
self.__children = self._create_children(default) self.__children = self._create_children(default)
self.__linked = list()
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
"""Create and return full copy of provider.""" """Create and return full copy of provider."""
@ -1041,6 +1045,7 @@ cdef class Configuration(Object):
copied = self.__class__(self.__name) copied = self.__class__(self.__name)
copied.__provides = deepcopy(self.__provides, memo) copied.__provides = deepcopy(self.__provides, memo)
copied.__children = deepcopy(self.__children, memo) copied.__children = deepcopy(self.__children, memo)
copied.__linked = deepcopy(self.__linked, memo)
self._copy_overridings(copied, memo) self._copy_overridings(copied, memo)
@ -1076,6 +1081,21 @@ cdef class Configuration(Object):
return child_provider return child_provider
@property
def children(self):
"""Return children providers."""
return self.__children
@property
def linked(self):
"""Return linked providers."""
return self.__linked
def link_provider(self, Configuration provider):
"""Link providers."""
assert isinstance(provider, Configuration)
self.__linked.append(provider)
def get_name(self): def get_name(self):
"""Name of configuration unit.""" """Name of configuration unit."""
return self.__name return self.__name
@ -1093,6 +1113,12 @@ cdef class Configuration(Object):
""" """
overriding_context = super(Configuration, self).override(provider) overriding_context = super(Configuration, self).override(provider)
for linked in self.__linked:
linked.override(provider)
if isinstance(provider, Configuration):
provider.link_provider(self)
value = self.__call__() value = self.__call__()
if not isinstance(value, dict): if not isinstance(value, dict):
return return
@ -2077,30 +2103,30 @@ cdef class List(Provider):
return list(__provide_positional_args(args, self.__args, self.__args_len)) return list(__provide_positional_args(args, self.__args, self.__args_len))
cdef class Container(Singleton): cdef class Container(Provider):
def __init__(self, container_cls, container=None, **overriding_providers):
self.container_cls = container_cls
self.overriding_providers = overriding_providers
if container is None:
container = container_cls()
container.override_providers(**overriding_providers)
self.container = container
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
cls = self.cls copied = self.__class__(
if isinstance(cls, Provider): self.container_cls,
cls = deepcopy(cls, memo) self.container,
**deepcopy(self.overriding_providers, memo),
copied = self.__class__(cls, )
*deepcopy(self.args, memo),
**deepcopy(self.kwargs, memo))
copied.set_attributes(**deepcopy(self.attributes, memo))
self._copy_overridings(copied, memo) self._copy_overridings(copied, memo)
if copied.__storage:
copied.__storage = deepcopy(copied.__storage, memo)
return copied return copied
def __getattr__(self, name): def __getattr__(self, name):
@ -2110,57 +2136,11 @@ cdef class Container(Singleton):
'\'{cls}\' object has no attribute ' '\'{cls}\' object has no attribute '
'\'{attribute_name}\''.format(cls=self.__class__.__name__, '\'{attribute_name}\''.format(cls=self.__class__.__name__,
attribute_name=name)) attribute_name=name))
return getattr(self.container, name)
container = self.__call__() cpdef object _provide(self, tuple args, dict kwargs):
provider = container.providers.get(name) """Return single instance."""
return self.container
if not provider:
provider = Dependency()
setattr(container, name, provider)
return provider
@property
def providers(self):
"""Read-only dictionary of dependency providers."""
container = self.__call__()
return container.providers
def override(self, provider):
"""Override provider with another provider.
:param provider: Overriding provider.
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
:return: Overriding context.
:rtype: :py:class:`OverridingContext`
"""
container = self.__call__()
container.override(container)
return super(Container, self).override(provider)
def reset_last_overriding(self):
"""Reset last overriding provider.
:raise: :py:exc:`dependency_injector.errors.Error` if provider is not
overridden.
:rtype: None
"""
container = self.__call()
container.reset_last_overriding()
super(Container, self).reset_last_overriding()
def reset_override(self):
"""Reset all overriding providers.
:rtype: None
"""
container = self.__call()
container.reset_override()
super(Container, self).reset_override()
cdef class Injection(object): cdef class Injection(object):