Implement POC

This commit is contained in:
Roman Mogylatov 2021-10-01 21:33:13 -04:00
parent 08ea99759d
commit a485228fa2
4 changed files with 3940 additions and 2884 deletions

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@ class Container:
providers: Dict[str, Provider] providers: Dict[str, Provider]
dependencies: Dict[str, Provider] dependencies: Dict[str, Provider]
overridden: Tuple[Provider] overridden: Tuple[Provider]
wiring_config: Dict[str, Any]
__self__: Self __self__: Self
def __init__(self) -> None: ... def __init__(self) -> None: ...
def __deepcopy__(self, memo: Optional[Dict[str, Any]]) -> Provider: ... def __deepcopy__(self, memo: Optional[Dict[str, Any]]) -> Provider: ...
@ -43,6 +44,7 @@ class Container:
def override_providers(self, **overriding_providers: Union[Provider, Any]) -> None: ... def override_providers(self, **overriding_providers: Union[Provider, Any]) -> None: ...
def reset_last_overriding(self) -> None: ... def reset_last_overriding(self) -> None: ...
def reset_override(self) -> None: ... def reset_override(self) -> None: ...
def is_auto_wiring_enabled(self) -> bool: ...
def wire(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None) -> None: ... def wire(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None) -> None: ...
def unwire(self) -> None: ... def unwire(self) -> None: ...
def init_resources(self) -> Optional[Awaitable]: ... def init_resources(self) -> Optional[Awaitable]: ...

View File

@ -1,6 +1,7 @@
"""Containers module.""" """Containers module."""
import contextlib import contextlib
import copy as copy_module
import json import json
import sys import sys
import importlib import importlib
@ -77,6 +78,7 @@ class DynamicContainer(Container):
self.overridden = tuple() self.overridden = tuple()
self.parent = None self.parent = None
self.declarative_parent = None self.declarative_parent = None
self.wiring_config = {}
self.wired_to_modules = [] self.wired_to_modules = []
self.wired_to_packages = [] self.wired_to_packages = []
self.__self__ = providers.Self(self) self.__self__ = providers.Self(self)
@ -97,6 +99,7 @@ class DynamicContainer(Container):
copied.provider_type = providers.Provider copied.provider_type = providers.Provider
copied.overridden = providers.deepcopy(self.overridden, memo) copied.overridden = providers.deepcopy(self.overridden, memo)
copied.wiring_config = copy_module.deepcopy(self.wiring_config, memo)
copied.declarative_parent = self.declarative_parent copied.declarative_parent = self.declarative_parent
for name, provider in providers.deepcopy(self.providers, memo).items(): for name, provider in providers.deepcopy(self.providers, memo).items():
@ -251,16 +254,33 @@ class DynamicContainer(Container):
for provider in six.itervalues(self.providers): for provider in six.itervalues(self.providers):
provider.reset_override() provider.reset_override()
def is_auto_wiring_enabled(self):
"""Check if auto wiring is enabled."""
return self.wiring_config.get("auto_wire") is True
def wire(self, modules=None, packages=None, from_package=None): def wire(self, modules=None, packages=None, from_package=None):
"""Wire container providers with provided packages and modules. """Wire container providers with provided packages and modules.
:rtype: None :rtype: None
""" """
if modules is None and "modules" in self.wiring_config:
modules = self.wiring_config["modules"]
if packages is None and "packages" in self.wiring_config:
packages = self.wiring_config["packages"]
modules = [*modules] if modules else [] modules = [*modules] if modules else []
packages = [*packages] if packages else [] packages = [*packages] if packages else []
if _any_relative_string_imports_in(modules) or _any_relative_string_imports_in(packages): if _any_relative_string_imports_in(modules) or _any_relative_string_imports_in(packages):
if from_package is None: if from_package is None:
if "from_package" in self.wiring_config:
from_package = self.wiring_config["from_package"]
elif self.declarative_parent is not None \
and ("modules" in self.wiring_config
or "packages" in self.wiring_config):
with contextlib.suppress(Exception):
from_package = _resolve_package_name_from_cls(self.declarative_parent)
else:
with contextlib.suppress(Exception): with contextlib.suppress(Exception):
from_package = _resolve_calling_package_name() from_package = _resolve_calling_package_name()
@ -467,6 +487,7 @@ class DeclarativeContainerMetaClass(type):
attributes['inherited_providers'] = inherited_providers attributes['inherited_providers'] = inherited_providers
attributes['cls_providers'] = cls_providers attributes['cls_providers'] = cls_providers
attributes['providers'] = all_providers attributes['providers'] = all_providers
attributes['wiring_config'] = attributes.get('wiring_config', {})
cls = <type>type.__new__(mcs, class_name, bases, attributes) cls = <type>type.__new__(mcs, class_name, bases, attributes)
@ -617,6 +638,12 @@ class DeclarativeContainer(Container):
:type: dict[str, :py:class:`dependency_injector.providers.Provider`] :type: dict[str, :py:class:`dependency_injector.providers.Provider`]
""" """
wiring_config = dict()
"""Dictionary of wiring configuration.
:type: dict[str, Any]
"""
cls_providers = dict() cls_providers = dict()
"""Read-only dictionary of current container providers. """Read-only dictionary of current container providers.
@ -649,6 +676,7 @@ class DeclarativeContainer(Container):
""" """
container = cls.instance_type() container = cls.instance_type()
container.provider_type = cls.provider_type container.provider_type = cls.provider_type
container.wiring_config = copy_module.deepcopy(cls.wiring_config)
container.declarative_parent = cls container.declarative_parent = cls
copied_providers = providers.deepcopy({ **cls.providers, **{'@@self@@': cls.__self__}}) copied_providers = providers.deepcopy({ **cls.providers, **{'@@self@@': cls.__self__}})
@ -665,6 +693,9 @@ class DeclarativeContainer(Container):
container.override_providers(**overriding_providers) container.override_providers(**overriding_providers)
container.apply_container_providers_overridings() container.apply_container_providers_overridings()
if container.is_auto_wiring_enabled():
container.wire()
return container return container
@classmethod @classmethod
@ -826,3 +857,8 @@ cpdef object _resolve_calling_package_name():
pre_last_frame = stack[0] pre_last_frame = stack[0]
module = inspect.getmodule(pre_last_frame[0]) module = inspect.getmodule(pre_last_frame[0])
return module.__package__ return module.__package__
cpdef object _resolve_package_name_from_cls(cls):
module = importlib.import_module(cls.__module__)
return module.__package__

View File

@ -30,6 +30,7 @@ _SAMPLES_DIR = os.path.abspath(
import sys import sys
sys.path.append(_TOP_DIR) sys.path.append(_TOP_DIR)
sys.path.append(_SAMPLES_DIR) sys.path.append(_SAMPLES_DIR)
import copy
from asyncutils import AsyncTestCase from asyncutils import AsyncTestCase
@ -361,6 +362,74 @@ class WiringWithStringModuleAndPackageNamesTest(unittest.TestCase):
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
class WiringWithWiringConfigInTheContainerTest(unittest.TestCase):
container: Container
original_wiring_config = copy.deepcopy(Container.wiring_config)
def tearDown(self) -> None:
Container.wiring_config = copy.deepcopy(self.original_wiring_config)
self.container.unwire()
def test_absolute_names(self):
Container.wiring_config = {
"modules": ["wiringsamples.module"],
"packages": ["wiringsamples.package"],
}
self.container = Container()
self.container.wire()
service = module.test_function()
self.assertIsInstance(service, Service)
from wiringsamples.package.subpackage.submodule import test_function
service = test_function()
self.assertIsInstance(service, Service)
def test_relative_names_with_explicit_package(self):
Container.wiring_config = {
"modules": [".module"],
"packages": [".package"],
"from_package": "wiringsamples",
}
self.container = Container()
self.container.wire()
service = module.test_function()
self.assertIsInstance(service, Service)
from wiringsamples.package.subpackage.submodule import test_function
service = test_function()
self.assertIsInstance(service, Service)
def test_relative_names_with_auto_package(self):
Container.wiring_config = {
"modules": [".module"],
"packages": [".package"],
}
self.container = Container()
self.container.wire()
service = module.test_function()
self.assertIsInstance(service, Service)
from wiringsamples.package.subpackage.submodule import test_function
service = test_function()
self.assertIsInstance(service, Service)
def test_auto_wire(self):
Container.wiring_config = {
"modules": [".module"],
"auto_wire": True,
}
self.container = Container()
service = module.test_function()
self.assertIsInstance(service, Service)
self.assertTrue(self.container.is_auto_wiring_enabled())
class ModuleAsPackageTest(unittest.TestCase): class ModuleAsPackageTest(unittest.TestCase):
def setUp(self): def setUp(self):