mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-29 04:53:59 +03:00
Feature/declarative container initialization (#176)
* Add overriding functionality on declarative container initialization * Update changelog * Update bundles example
This commit is contained in:
parent
1115e783e0
commit
1c6160e827
|
@ -12,6 +12,13 @@ Development version
|
||||||
- Rename ``ExternalDependency`` provider to ``Dependency``.
|
- Rename ``ExternalDependency`` provider to ``Dependency``.
|
||||||
- Add default value for ``instance_of`` argument of ``Dependency`` provider -
|
- Add default value for ``instance_of`` argument of ``Dependency`` provider -
|
||||||
``Dependency(instance_of=object)``.
|
``Dependency(instance_of=object)``.
|
||||||
|
- Change initialization of declarative container, so it accepts overriding
|
||||||
|
providers as keyword arguments -
|
||||||
|
``DeclarativeContainer(**overriding_providers)``.
|
||||||
|
- Add method to dynamic catalog for setting groups of providers -
|
||||||
|
``DynamicContainer.set_providers(**providers)``.
|
||||||
|
- Add method to dynamic catalog for overriding groups of providers -
|
||||||
|
``DynamicContainer.set_providers(**overriding_providers)``.
|
||||||
|
|
||||||
|
|
||||||
3.8.2
|
3.8.2
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Photos bundle."""
|
"""Photos bundle."""
|
||||||
|
|
||||||
from core import containers
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
from . import entities
|
from . import entities
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Users bundle."""
|
"""Users bundle."""
|
||||||
|
|
||||||
from core import containers
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
from . import entities
|
from . import entities
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
"""Containers module."""
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from dependency_injector import containers, providers
|
|
||||||
|
|
||||||
|
|
||||||
class DeclarativeContainer(containers.DeclarativeContainer):
|
|
||||||
"""Declarative container."""
|
|
||||||
|
|
||||||
def __new__(cls, **dependencies):
|
|
||||||
"""Constructor.
|
|
||||||
|
|
||||||
:return: Dynamic container with copy of all providers.
|
|
||||||
:rtype: :py:class:`DynamicContainer`
|
|
||||||
"""
|
|
||||||
# Make copy of declarative container providers for container instance
|
|
||||||
container_providers = providers.deepcopy(cls.providers)
|
|
||||||
|
|
||||||
# Fetch container dependencies
|
|
||||||
container_dependencies = dict()
|
|
||||||
for name, provider in six.iteritems(container_providers):
|
|
||||||
if isinstance(provider, providers.Dependency):
|
|
||||||
container_dependencies[name] = provider
|
|
||||||
|
|
||||||
# Satisfy container dependencies
|
|
||||||
for name, dependency in six.iteritems(container_dependencies):
|
|
||||||
try:
|
|
||||||
dependency_provider = dependencies[name]
|
|
||||||
except KeyError:
|
|
||||||
raise Exception('Dependency {name} of container {container} '
|
|
||||||
'is not satisfied'.format(
|
|
||||||
name=name, container=cls))
|
|
||||||
else:
|
|
||||||
dependency.provided_by(dependency_provider)
|
|
||||||
|
|
||||||
# Create dynamic container
|
|
||||||
container = cls.instance_type()
|
|
||||||
container.provider_type = cls.provider_type
|
|
||||||
for name, provider in six.iteritems(container_providers):
|
|
||||||
setattr(container, name, provider)
|
|
||||||
|
|
||||||
return container
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Example application - Bundles."""
|
"""Example application - Bundles."""
|
||||||
|
|
||||||
from core import containers
|
from dependency_injector import containers
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
|
|
||||||
from bundles.users import Users
|
from bundles.users import Users
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -88,6 +88,18 @@ class DynamicContainer(object):
|
||||||
del self.providers[name]
|
del self.providers[name]
|
||||||
super(DynamicContainer, self).__delattr__(name)
|
super(DynamicContainer, self).__delattr__(name)
|
||||||
|
|
||||||
|
def set_providers(self, **providers):
|
||||||
|
"""Set container providers.
|
||||||
|
|
||||||
|
:param providers: Dictionary of providers
|
||||||
|
:type providers:
|
||||||
|
dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
for name, provider in six.iteritems(providers):
|
||||||
|
setattr(self, name, provider)
|
||||||
|
|
||||||
def override(self, object overriding):
|
def override(self, object overriding):
|
||||||
"""Override current container by overriding container.
|
"""Override current container by overriding container.
|
||||||
|
|
||||||
|
@ -111,6 +123,19 @@ class DynamicContainer(object):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def override_providers(self, **overriding_providers):
|
||||||
|
"""Override container providers.
|
||||||
|
|
||||||
|
:param overriding_providers: Dictionary of providers
|
||||||
|
:type overriding_providers:
|
||||||
|
dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
for name, overriding_provider in six.iteritems(overriding_providers):
|
||||||
|
container_provider = getattr(self, name)
|
||||||
|
container_provider.override(overriding_provider)
|
||||||
|
|
||||||
def reset_last_overriding(self):
|
def reset_last_overriding(self):
|
||||||
"""Reset last overriding provider for each container providers.
|
"""Reset last overriding provider for each container providers.
|
||||||
|
|
||||||
|
@ -265,18 +290,16 @@ class DeclarativeContainer(object):
|
||||||
:type: tuple[:py:class:`DeclarativeContainer`]
|
:type: tuple[:py:class:`DeclarativeContainer`]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, **overriding_providers):
|
||||||
"""Constructor.
|
"""Constructor.
|
||||||
|
|
||||||
:return: Dynamic container with copy of all providers.
|
:return: Dynamic container with copy of all providers.
|
||||||
:rtype: :py:class:`DynamicContainer`
|
:rtype: :py:class:`DynamicContainer`
|
||||||
"""
|
"""
|
||||||
container = cls.instance_type(*args, **kwargs)
|
container = cls.instance_type()
|
||||||
container.provider_type = cls.provider_type
|
container.provider_type = cls.provider_type
|
||||||
|
container.set_providers(**deepcopy(cls.providers))
|
||||||
for name, provider in six.iteritems(deepcopy(cls.providers)):
|
container.override_providers(**overriding_providers)
|
||||||
setattr(container, name, provider)
|
|
||||||
|
|
||||||
return container
|
return container
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -265,3 +265,12 @@ class DeclarativeContainerTests(unittest.TestCase):
|
||||||
dict(Container1=Container.Container1,
|
dict(Container1=Container.Container1,
|
||||||
Container2=Container.Container2,
|
Container2=Container.Container2,
|
||||||
Container3=Container.Container3))
|
Container3=Container.Container3))
|
||||||
|
|
||||||
|
def test_init_with_overriding_providers(self):
|
||||||
|
p1 = providers.Provider()
|
||||||
|
p2 = providers.Provider()
|
||||||
|
|
||||||
|
container = ContainerA(p11=p1, p12=p2)
|
||||||
|
|
||||||
|
self.assertIs(container.p11.last_overriding, p1)
|
||||||
|
self.assertIs(container.p12.last_overriding, p2)
|
||||||
|
|
|
@ -75,6 +75,16 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
|
||||||
self.assertIs(ContainerA.provider_type,
|
self.assertIs(ContainerA.provider_type,
|
||||||
containers.DeclarativeContainer.provider_type)
|
containers.DeclarativeContainer.provider_type)
|
||||||
|
|
||||||
|
def test_set_providers(self):
|
||||||
|
p13 = providers.Provider()
|
||||||
|
p14 = providers.Provider()
|
||||||
|
container_a = ContainerA()
|
||||||
|
|
||||||
|
container_a.set_providers(p13=p13, p14=p14)
|
||||||
|
|
||||||
|
self.assertIs(container_a.p13, p13)
|
||||||
|
self.assertIs(container_a.p14, p14)
|
||||||
|
|
||||||
def test_override(self):
|
def test_override(self):
|
||||||
class _Container(containers.DeclarativeContainer):
|
class _Container(containers.DeclarativeContainer):
|
||||||
p11 = providers.Provider()
|
p11 = providers.Provider()
|
||||||
|
@ -108,6 +118,22 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
|
||||||
with self.assertRaises(errors.Error):
|
with self.assertRaises(errors.Error):
|
||||||
container.override(container)
|
container.override(container)
|
||||||
|
|
||||||
|
def test_override_providers(self):
|
||||||
|
p1 = providers.Provider()
|
||||||
|
p2 = providers.Provider()
|
||||||
|
container_a = ContainerA()
|
||||||
|
|
||||||
|
container_a.override_providers(p11=p1, p12=p2)
|
||||||
|
|
||||||
|
self.assertIs(container_a.p11.last_overriding, p1)
|
||||||
|
self.assertIs(container_a.p12.last_overriding, p2)
|
||||||
|
|
||||||
|
def test_override_providers_with_unknown_provider(self):
|
||||||
|
container_a = ContainerA()
|
||||||
|
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
container_a.override_providers(unknown=providers.Provider())
|
||||||
|
|
||||||
def test_reset_last_overridding(self):
|
def test_reset_last_overridding(self):
|
||||||
class _Container(containers.DeclarativeContainer):
|
class _Container(containers.DeclarativeContainer):
|
||||||
p11 = providers.Provider()
|
p11 = providers.Provider()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user