Implement concept with WiringConfiguration object

This commit is contained in:
Roman Mogylatov 2021-10-02 22:14:08 -04:00
parent a485228fa2
commit 2a57162d2e
4 changed files with 3836 additions and 3091 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ from typing import (
Generic, Generic,
Type, Type,
Dict, Dict,
List,
Tuple, Tuple,
Optional, Optional,
Any, Any,
@ -26,12 +27,20 @@ T = TypeVar('T')
TT = TypeVar('TT') TT = TypeVar('TT')
class WiringConfiguration:
modules: List[Any]
packages: List[Any]
from_package: Optional[str]
auto_wire: bool
def __init__(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None, auto_wire: bool = True) -> None: ...
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] dependencies: Dict[str, Provider]
overridden: Tuple[Provider] overridden: Tuple[Provider]
wiring_config: Dict[str, Any] wiring_config: WiringConfiguration
__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: ...

View File

@ -33,6 +33,19 @@ else:
raise NotImplementedError('Wiring requires Python 3.6 or above') raise NotImplementedError('Wiring requires Python 3.6 or above')
class WiringConfiguration:
"""Container wiring configuration."""
def __init__(self, modules=None, packages=None, from_package=None, auto_wire=True):
self.modules = [*modules] if modules else []
self.packages = [*packages] if packages else []
self.from_package = from_package
self.auto_wire = auto_wire
def __deepcopy__(self, memo=None):
return self.__class__(self.modules, self.packages, self.from_package, self.auto_wire)
class Container(object): class Container(object):
"""Abstract container.""" """Abstract container."""
@ -78,7 +91,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.wiring_config = WiringConfiguration()
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)
@ -255,29 +268,28 @@ class DynamicContainer(Container):
provider.reset_override() provider.reset_override()
def is_auto_wiring_enabled(self): def is_auto_wiring_enabled(self):
"""Check if auto wiring is enabled.""" """Check if auto wiring is needed."""
return self.wiring_config.get("auto_wire") is True return self.wiring_config.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: if modules is None and self.wiring_config.modules:
modules = self.wiring_config["modules"] modules = self.wiring_config.modules
if packages is None and "packages" in self.wiring_config: if packages is None and self.wiring_config.packages:
packages = self.wiring_config["packages"] 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: if self.wiring_config.from_package is not None:
from_package = self.wiring_config["from_package"] from_package = self.wiring_config.from_package
elif self.declarative_parent is not None \ elif self.declarative_parent is not None \
and ("modules" in self.wiring_config and (self.wiring_config.modules or self.wiring_config.packages):
or "packages" in self.wiring_config):
with contextlib.suppress(Exception): with contextlib.suppress(Exception):
from_package = _resolve_package_name_from_cls(self.declarative_parent) from_package = _resolve_package_name_from_cls(self.declarative_parent)
else: else:
@ -287,6 +299,9 @@ class DynamicContainer(Container):
modules = _resolve_string_imports(modules, from_package) modules = _resolve_string_imports(modules, from_package)
packages = _resolve_string_imports(packages, from_package) packages = _resolve_string_imports(packages, from_package)
if not modules and not packages:
return
wire( wire(
container=self, container=self,
modules=modules, modules=modules,
@ -483,11 +498,20 @@ class DeclarativeContainerMetaClass(type):
all_providers.update(inherited_providers) all_providers.update(inherited_providers)
all_providers.update(cls_providers) all_providers.update(cls_providers)
wiring_config = attributes.get("wiring_config")
if wiring_config is None:
wiring_config = WiringConfiguration()
if wiring_config is not None and not isinstance(wiring_config, WiringConfiguration):
raise errors.Error(
"Wiring configuration should be an instance of WiringConfiguration, "
"instead got {0}".format(wiring_config)
)
attributes['containers'] = containers attributes['containers'] = containers
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', {}) attributes['wiring_config'] = wiring_config
cls = <type>type.__new__(mcs, class_name, bases, attributes) cls = <type>type.__new__(mcs, class_name, bases, attributes)
@ -638,10 +662,10 @@ class DeclarativeContainer(Container):
:type: dict[str, :py:class:`dependency_injector.providers.Provider`] :type: dict[str, :py:class:`dependency_injector.providers.Provider`]
""" """
wiring_config = dict() wiring_config = WiringConfiguration()
"""Dictionary of wiring configuration. """Wiring configuration.
:type: dict[str, Any] :type: WiringConfiguration
""" """
cls_providers = dict() cls_providers = dict()

View File

@ -11,7 +11,7 @@ from dependency_injector.wiring import (
register_loader_containers, register_loader_containers,
unregister_loader_containers, unregister_loader_containers,
) )
from dependency_injector import errors from dependency_injector import containers, errors
# Runtime import to avoid syntax errors in samples on Python < 3.5 # Runtime import to avoid syntax errors in samples on Python < 3.5
import os import os
@ -30,7 +30,6 @@ _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
@ -365,19 +364,18 @@ class WiringWithStringModuleAndPackageNamesTest(unittest.TestCase):
class WiringWithWiringConfigInTheContainerTest(unittest.TestCase): class WiringWithWiringConfigInTheContainerTest(unittest.TestCase):
container: Container container: Container
original_wiring_config = copy.deepcopy(Container.wiring_config) original_wiring_config = Container.wiring_config
def tearDown(self) -> None: def tearDown(self) -> None:
Container.wiring_config = copy.deepcopy(self.original_wiring_config) Container.wiring_config = self.original_wiring_config
self.container.unwire() self.container.unwire()
def test_absolute_names(self): def test_absolute_names(self):
Container.wiring_config = { Container.wiring_config = containers.WiringConfiguration(
"modules": ["wiringsamples.module"], modules=["wiringsamples.module"],
"packages": ["wiringsamples.package"], packages=["wiringsamples.package"],
} )
self.container = Container() self.container = Container()
self.container.wire()
service = module.test_function() service = module.test_function()
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
@ -387,13 +385,12 @@ class WiringWithWiringConfigInTheContainerTest(unittest.TestCase):
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
def test_relative_names_with_explicit_package(self): def test_relative_names_with_explicit_package(self):
Container.wiring_config = { Container.wiring_config = containers.WiringConfiguration(
"modules": [".module"], modules=[".module"],
"packages": [".package"], packages=[".package"],
"from_package": "wiringsamples", from_package="wiringsamples",
} )
self.container = Container() self.container = Container()
self.container.wire()
service = module.test_function() service = module.test_function()
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
@ -403,12 +400,11 @@ class WiringWithWiringConfigInTheContainerTest(unittest.TestCase):
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
def test_relative_names_with_auto_package(self): def test_relative_names_with_auto_package(self):
Container.wiring_config = { Container.wiring_config = containers.WiringConfiguration(
"modules": [".module"], modules=[".module"],
"packages": [".package"], packages=[".package"],
} )
self.container = Container() self.container = Container()
self.container.wire()
service = module.test_function() service = module.test_function()
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
@ -417,17 +413,19 @@ class WiringWithWiringConfigInTheContainerTest(unittest.TestCase):
service = test_function() service = test_function()
self.assertIsInstance(service, Service) self.assertIsInstance(service, Service)
def test_auto_wire(self): def test_auto_wire_disabled(self):
Container.wiring_config = { Container.wiring_config = containers.WiringConfiguration(
"modules": [".module"], modules=[".module"],
"auto_wire": True, auto_wire=False,
} )
self.container = Container() self.container = Container()
service = module.test_function() service = module.test_function()
self.assertIsInstance(service, Service) self.assertIsInstance(service, Provide)
self.assertTrue(self.container.is_auto_wiring_enabled()) self.container.wire()
service = module.test_function()
self.assertIsInstance(service, Service)
class ModuleAsPackageTest(unittest.TestCase): class ModuleAsPackageTest(unittest.TestCase):