Implement sub containers wiring + add tests

This commit is contained in:
Roman Mogylatov 2020-09-27 22:53:42 -04:00
parent a02f9c6981
commit deae475874
9 changed files with 1192 additions and 1103 deletions

View File

@ -1312,14 +1312,14 @@ struct __pyx_obj_19dependency_injector_9providers_List {
* *
* *
* cdef class Container(Provider): # <<<<<<<<<<<<<< * cdef class Container(Provider): # <<<<<<<<<<<<<<
* cdef object container_cls * cdef object __container_cls
* cdef dict overriding_providers * cdef dict __overriding_providers
*/ */
struct __pyx_obj_19dependency_injector_9providers_Container { struct __pyx_obj_19dependency_injector_9providers_Container {
struct __pyx_obj_19dependency_injector_9providers_Provider __pyx_base; struct __pyx_obj_19dependency_injector_9providers_Provider __pyx_base;
PyObject *container_cls; PyObject *__pyx___container_cls;
PyObject *overriding_providers; PyObject *__pyx___overriding_providers;
PyObject *container; PyObject *__pyx___container;
}; };
@ -1989,8 +1989,8 @@ static struct __pyx_vtabstruct_19dependency_injector_9providers_List *__pyx_vtab
* *
* *
* cdef class Container(Provider): # <<<<<<<<<<<<<< * cdef class Container(Provider): # <<<<<<<<<<<<<<
* cdef object container_cls * cdef object __container_cls
* cdef dict overriding_providers * cdef dict __overriding_providers
*/ */
struct __pyx_vtabstruct_19dependency_injector_9providers_Container { struct __pyx_vtabstruct_19dependency_injector_9providers_Container {

File diff suppressed because it is too large Load Diff

View File

@ -185,9 +185,9 @@ cdef class List(Provider):
cdef class Container(Provider): cdef class Container(Provider):
cdef object container_cls cdef object __container_cls
cdef dict overriding_providers cdef dict __overriding_providers
cdef object container cdef object __container
cpdef object _provide(self, tuple args, dict kwargs) cpdef object _provide(self, tuple args, dict kwargs)

View File

@ -278,6 +278,8 @@ class Container(Provider):
def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Provider) -> None: ... def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Provider) -> None: ...
def __call__(self, *args: Injection, **kwargs: Injection) -> T: ... def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
def __getattr__(self, name: str) -> Provider: ... def __getattr__(self, name: str) -> Provider: ...
@property
def container(self) -> T: ...
class Selector(Provider): class Selector(Provider):

View File

@ -2477,13 +2477,13 @@ cdef class Container(Provider):
def __init__(self, container_cls, container=None, **overriding_providers): def __init__(self, container_cls, container=None, **overriding_providers):
"""Initialize provider.""" """Initialize provider."""
self.container_cls = container_cls self.__container_cls = container_cls
self.overriding_providers = overriding_providers self.__overriding_providers = overriding_providers
if container is None: if container is None:
container = container_cls() container = container_cls()
container.override_providers(**overriding_providers) container.override_providers(**overriding_providers)
self.container = container self.__container = container
super(Container, self).__init__() super(Container, self).__init__()
@ -2494,9 +2494,9 @@ cdef class Container(Provider):
return copied return copied
copied = self.__class__( copied = self.__class__(
self.container_cls, self.__container_cls,
deepcopy(self.container, memo), deepcopy(self.__container, memo),
**deepcopy(self.overriding_providers, memo), **deepcopy(self.__overriding_providers, memo),
) )
return copied return copied
@ -2508,7 +2508,11 @@ cdef class Container(Provider):
'\'{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) return getattr(self.__container, name)
@property
def container(self):
return self.__container
def override(self, provider): def override(self, provider):
"""Override provider with another provider.""" """Override provider with another provider."""
@ -2516,7 +2520,7 @@ cdef class Container(Provider):
cpdef object _provide(self, tuple args, dict kwargs): cpdef object _provide(self, tuple args, dict kwargs):
"""Return single instance.""" """Return single instance."""
return self.container return self.__container
cdef class Selector(Provider): cdef class Selector(Provider):

View File

@ -25,7 +25,10 @@ class ProvidersMap:
def __init__(self, container): def __init__(self, container):
self._container = container self._container = container
self._map = self._create_providers_map(container) self._map = self._create_providers_map(
current_providers=container.providers,
original_providers=container.declarative_parent.providers,
)
def resolve_provider(self, provider: providers.Provider) -> providers.Provider: def resolve_provider(self, provider: providers.Provider) -> providers.Provider:
if isinstance(provider, providers.Delegate): if isinstance(provider, providers.Delegate):
@ -105,18 +108,20 @@ class ProvidersMap:
@classmethod @classmethod
def _create_providers_map( def _create_providers_map(
cls, cls,
container: AnyContainer, current_providers: Dict[str, providers.Provider],
original_providers: Dict[str, providers.Provider],
) -> Dict[providers.Provider, providers.Provider]: ) -> Dict[providers.Provider, providers.Provider]:
current_providers = container.providers
original_providers = container.declarative_parent.providers
providers_map = {} providers_map = {}
for provider_name, current_provider in current_providers.items(): for provider_name, current_provider in current_providers.items():
original_provider = original_providers[provider_name] original_provider = original_providers[provider_name]
providers_map[original_provider] = current_provider providers_map[original_provider] = current_provider
if isinstance(current_provider, providers.Container): if isinstance(current_provider, providers.Container) \
subcontainer_map = cls._create_providers_map(current_provider.container) and isinstance(original_provider, providers.Container):
subcontainer_map = cls._create_providers_map(
current_providers=current_provider.container.providers,
original_providers=original_provider.container.providers,
)
providers_map.update(subcontainer_map) providers_map.update(subcontainer_map)
return providers_map return providers_map

View File

@ -3,8 +3,15 @@ from dependency_injector import containers, providers
from .service import Service from .service import Service
class SubContainer(containers.DeclarativeContainer):
int_object = providers.Object(1)
class Container(containers.DeclarativeContainer): class Container(containers.DeclarativeContainer):
config = providers.Configuration() config = providers.Configuration()
service = providers.Factory(Service) service = providers.Factory(Service)
sub = providers.Container(SubContainer)

View File

@ -39,3 +39,7 @@ def test_provide_provider(service_provider: Callable[..., Service] = Provider[Co
def test_provided_instance(some_value: int = Provide[Container.service.provided.foo['bar'].call()]): def test_provided_instance(some_value: int = Provide[Container.service.provided.foo['bar'].call()]):
return some_value return some_value
def test_subcontainer_provider(some_value: int = Provide[Container.sub.int_object]):
return some_value

View File

@ -72,3 +72,7 @@ class WiringTest(unittest.TestCase):
with self.container.service.override(TestService()): with self.container.service.override(TestService()):
some_value = module.test_provided_instance() some_value = module.test_provided_instance()
self.assertEqual(some_value, 10) self.assertEqual(some_value, 10)
def test_subcontainer(self):
some_value = module.test_subcontainer_provider()
self.assertEqual(some_value, 1)