Add dependencies attribute to declarative and dynamic containers (#359)

* Add .dependencies attribute to declarative and dynamic containers

* Update changelog

* Add typing tests
This commit is contained in:
Roman Mogylatov 2021-01-15 07:20:37 -05:00 committed by GitHub
parent 3e207a4f21
commit 907a4f1887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 2066 additions and 1362 deletions

View File

@ -7,6 +7,13 @@ 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`_
Development version
-------------------
- Add ``.dependencies`` attribute to the ``DeclarativeContainer`` and ``DynamicContainer``.
It returns dictionary of container ``Dependency`` and ``DependenciesContainer`` providers.
See issue `#357 <https://github.com/ets-labs/python-dependency-injector/issues/357>`_.
Many thanks to `Shaun Cutts <https://github.com/shaunc>`_ for suggesting the feature.
4.8.3 4.8.3
----- -----
- Fix a bug in the ``Configuration`` provider to correctly handle overriding by ``None``. - Fix a bug in the ``Configuration`` provider to correctly handle overriding by ``None``.

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@ C_Overriding = TypeVar('C_Overriding', bound='DeclarativeContainer')
class Container: class Container:
provider_type: Type[Provider] = Provider provider_type: Type[Provider] = Provider
providers: Dict[str, Provider] providers: Dict[str, Provider]
dependencies: Dict[str, Provider]
overridden: Tuple[Provider] overridden: Tuple[Provider]
__self__: Provider __self__: Provider
def __init__(self) -> None: ... def __init__(self) -> None: ...

View File

@ -15,6 +15,8 @@ from .providers cimport (
Provider, Provider,
Object, Object,
Resource, Resource,
Dependency,
DependenciesContainer,
Container as ContainerProvider, Container as ContainerProvider,
deepcopy, deepcopy,
) )
@ -125,6 +127,22 @@ class DynamicContainer(object):
del self.providers[name] del self.providers[name]
super(DynamicContainer, self).__delattr__(name) super(DynamicContainer, self).__delattr__(name)
@property
def dependencies(self):
"""Return dependency providers dictionary.
Dependency providers can be both of :py:class:`dependency_injector.providers.Dependency` and
:py:class:`dependency_injector.providers.DependenciesContainer`.
:rtype:
dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return {
name: provider
for name, provider in self.providers.items()
if isinstance(provider, (Dependency, DependenciesContainer))
}
def set_providers(self, **providers): def set_providers(self, **providers):
"""Set container providers. """Set container providers.
@ -340,6 +358,22 @@ class DeclarativeContainerMetaClass(type):
del cls.cls_providers[name] del cls.cls_providers[name]
super(DeclarativeContainerMetaClass, cls).__delattr__(name) super(DeclarativeContainerMetaClass, cls).__delattr__(name)
@property
def dependencies(cls):
"""Return dependency providers dictionary.
Dependency providers can be both of :py:class:`dependency_injector.providers.Dependency` and
:py:class:`dependency_injector.providers.DependenciesContainer`.
:rtype:
dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
return {
name: provider
for name, provider in cls.providers.items()
if isinstance(provider, (Dependency, DependenciesContainer))
}
@six.add_metaclass(DeclarativeContainerMetaClass) @six.add_metaclass(DeclarativeContainerMetaClass)
class DeclarativeContainer(object): class DeclarativeContainer(object):

View File

@ -1,3 +1,5 @@
from typing import Dict
from dependency_injector import containers, providers from dependency_injector import containers, providers
@ -38,3 +40,11 @@ class Container4(containers.DeclarativeContainer):
container4 = Container4() container4 = Container4()
container4.override(Container4()) container4.override(Container4())
# Test 5: to check .dependencies attribute
class Container5(containers.DeclarativeContainer):
provider = providers.Factory(int)
dependencies: Dict[str, providers.Provider] = Container5.dependencies

View File

@ -1,3 +1,5 @@
from typing import Dict
from dependency_injector import containers, providers from dependency_injector import containers, providers
@ -16,3 +18,7 @@ container3.override_providers(a=providers.Provider())
# Test 4: to check set_providers() # Test 4: to check set_providers()
container4 = containers.DynamicContainer() container4 = containers.DynamicContainer()
container4.set_providers(a=providers.Provider()) container4.set_providers(a=providers.Provider())
# Test 5: to check .dependencies attribute
container5 = containers.DynamicContainer()
dependencies: Dict[str, providers.Provider] = container5.dependencies

View File

@ -60,6 +60,32 @@ class DeclarativeContainerTests(unittest.TestCase):
p21=ContainerB.p21, p21=ContainerB.p21,
p22=ContainerB.p22)) p22=ContainerB.p22))
def test_dependencies_attribute(self):
class ContainerD(ContainerC):
p41 = providers.Dependency()
p42 = providers.DependenciesContainer()
class ContainerE(ContainerD):
p51 = providers.Dependency()
p52 = providers.DependenciesContainer()
self.assertEqual(
ContainerD.dependencies,
{
'p41': ContainerD.p41,
'p42': ContainerD.p42,
},
)
self.assertEqual(
ContainerE.dependencies,
{
'p41': ContainerD.p41,
'p42': ContainerD.p42,
'p51': ContainerE.p51,
'p52': ContainerE.p52,
},
)
def test_set_get_del_providers(self): def test_set_get_del_providers(self):
a_p13 = providers.Provider() a_p13 = providers.Provider()
b_p23 = providers.Provider() b_p23 = providers.Provider()

View File

@ -24,6 +24,12 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
self.assertIsNot(container_a1.p12, container_a2.p12) self.assertIsNot(container_a1.p12, container_a2.p12)
self.assertNotEqual(container_a1.providers, container_a2.providers) self.assertNotEqual(container_a1.providers, container_a2.providers)
def test_dependencies_attribute(self):
container = ContainerA()
container.a1 = providers.Dependency()
container.a2 = providers.DependenciesContainer()
self.assertEqual(container.dependencies, {'a1': container.a1, 'a2': container.a2})
def test_set_get_del_providers(self): def test_set_get_del_providers(self):
p13 = providers.Provider() p13 = providers.Provider()