mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-07-06 21:33:31 +03:00
Add unwire functionality
This commit is contained in:
parent
cae99da84f
commit
f3619d696f
File diff suppressed because it is too large
Load Diff
|
@ -12,11 +12,14 @@ from .providers cimport (
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[:2] >= (3, 6):
|
if sys.version_info[:2] >= (3, 6):
|
||||||
from .wiring import wire
|
from .wiring import wire, unwire
|
||||||
else:
|
else:
|
||||||
def wire(*args, **kwargs):
|
def wire(*args, **kwargs):
|
||||||
raise NotADirectoryError('Wiring requires Python 3.6 or above')
|
raise NotADirectoryError('Wiring requires Python 3.6 or above')
|
||||||
|
|
||||||
|
def unwire(*args, **kwargs):
|
||||||
|
raise NotADirectoryError('Wiring requires Python 3.6 or above')
|
||||||
|
|
||||||
|
|
||||||
class DynamicContainer(object):
|
class DynamicContainer(object):
|
||||||
"""Dynamic inversion of control container.
|
"""Dynamic inversion of control container.
|
||||||
|
@ -55,9 +58,11 @@ class DynamicContainer(object):
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
self.provider_type = Provider
|
self.provider_type = Provider
|
||||||
self.providers = dict()
|
self.providers = {}
|
||||||
self.overridden = tuple()
|
self.overridden = tuple()
|
||||||
self.declarative_parent = None
|
self.declarative_parent = None
|
||||||
|
self.wired_to_modules = []
|
||||||
|
self.wired_to_packages = []
|
||||||
super(DynamicContainer, self).__init__()
|
super(DynamicContainer, self).__init__()
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
|
@ -196,7 +201,7 @@ class DynamicContainer(object):
|
||||||
|
|
||||||
|
|
||||||
def wire(self, modules=None, packages=None):
|
def wire(self, modules=None, packages=None):
|
||||||
"""Wire container providers with provided packages and modules by name.
|
"""Wire container providers with provided packages and modules.
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
|
@ -206,6 +211,23 @@ class DynamicContainer(object):
|
||||||
packages=packages,
|
packages=packages,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if modules:
|
||||||
|
self.wired_to_modules.extend(modules)
|
||||||
|
|
||||||
|
if packages:
|
||||||
|
self.wired_to_packages.extend(packages)
|
||||||
|
|
||||||
|
def unwire(self):
|
||||||
|
"""Unwire container providers from previously wired packages and modules."""
|
||||||
|
unwire(
|
||||||
|
modules=self.wired_to_modules,
|
||||||
|
packages=self.wired_to_packages,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.wired_to_modules.clear()
|
||||||
|
self.wired_to_packages.clear()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DeclarativeContainerMetaClass(type):
|
class DeclarativeContainerMetaClass(type):
|
||||||
"""Declarative inversion of control container meta class."""
|
"""Declarative inversion of control container meta class."""
|
||||||
|
|
|
@ -27,7 +27,7 @@ def wire(
|
||||||
modules: Optional[Iterable[ModuleType]] = None,
|
modules: Optional[Iterable[ModuleType]] = None,
|
||||||
packages: Optional[Iterable[ModuleType]] = None,
|
packages: Optional[Iterable[ModuleType]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Wire container providers with provided packages and modules by name."""
|
"""Wire container providers with provided packages and modules."""
|
||||||
if not modules:
|
if not modules:
|
||||||
modules = []
|
modules = []
|
||||||
|
|
||||||
|
@ -43,6 +43,27 @@ def wire(
|
||||||
_patch_cls(member, container)
|
_patch_cls(member, container)
|
||||||
|
|
||||||
|
|
||||||
|
def unwire(
|
||||||
|
*,
|
||||||
|
modules: Optional[Iterable[ModuleType]] = None,
|
||||||
|
packages: Optional[Iterable[ModuleType]] = None,
|
||||||
|
) -> None:
|
||||||
|
"""Wire provided packages and modules with previous wired providers."""
|
||||||
|
if not modules:
|
||||||
|
modules = []
|
||||||
|
|
||||||
|
if packages:
|
||||||
|
for package in packages:
|
||||||
|
modules.extend(_fetch_modules(package))
|
||||||
|
|
||||||
|
for module in modules:
|
||||||
|
for name, member in inspect.getmembers(module):
|
||||||
|
if inspect.isfunction(member):
|
||||||
|
_unpatch_fn(module, name, member)
|
||||||
|
elif inspect.isclass(member):
|
||||||
|
_unpatch_cls(member,)
|
||||||
|
|
||||||
|
|
||||||
def _patch_cls(
|
def _patch_cls(
|
||||||
cls: Type[Any],
|
cls: Type[Any],
|
||||||
container: AnyContainer,
|
container: AnyContainer,
|
||||||
|
@ -50,14 +71,21 @@ def _patch_cls(
|
||||||
if not hasattr(cls, '__init__'):
|
if not hasattr(cls, '__init__'):
|
||||||
return
|
return
|
||||||
init_method = getattr(cls, '__init__')
|
init_method = getattr(cls, '__init__')
|
||||||
|
|
||||||
injections = _resolve_injections(init_method, container)
|
injections = _resolve_injections(init_method, container)
|
||||||
if not injections:
|
if not injections:
|
||||||
return
|
return
|
||||||
|
|
||||||
setattr(cls, '__init__', _patch_with_injections(init_method, injections))
|
setattr(cls, '__init__', _patch_with_injections(init_method, injections))
|
||||||
|
|
||||||
|
|
||||||
|
def _unpatch_cls(cls: Type[Any]) -> None:
|
||||||
|
if not hasattr(cls, '__init__'):
|
||||||
|
return
|
||||||
|
init_method = getattr(cls, '__init__')
|
||||||
|
if not _is_patched(init_method):
|
||||||
|
return
|
||||||
|
setattr(cls, '__init__', _get_original_from_patched(init_method))
|
||||||
|
|
||||||
|
|
||||||
def _patch_fn(
|
def _patch_fn(
|
||||||
module: ModuleType,
|
module: ModuleType,
|
||||||
name: str,
|
name: str,
|
||||||
|
@ -67,10 +95,19 @@ def _patch_fn(
|
||||||
injections = _resolve_injections(fn, container)
|
injections = _resolve_injections(fn, container)
|
||||||
if not injections:
|
if not injections:
|
||||||
return
|
return
|
||||||
|
|
||||||
setattr(module, name, _patch_with_injections(fn, injections))
|
setattr(module, name, _patch_with_injections(fn, injections))
|
||||||
|
|
||||||
|
|
||||||
|
def _unpatch_fn(
|
||||||
|
module: ModuleType,
|
||||||
|
name: str,
|
||||||
|
fn: Callable[..., Any],
|
||||||
|
) -> None:
|
||||||
|
if not _is_patched(fn):
|
||||||
|
return
|
||||||
|
setattr(module, name, _get_original_from_patched(fn))
|
||||||
|
|
||||||
|
|
||||||
def _resolve_injections(fn: Callable[..., Any], container: AnyContainer) -> Dict[str, Any]:
|
def _resolve_injections(fn: Callable[..., Any], container: AnyContainer) -> Dict[str, Any]:
|
||||||
config = _resolve_container_config(container)
|
config = _resolve_container_config(container)
|
||||||
|
|
||||||
|
@ -148,9 +185,22 @@ def _patch_with_injections(fn, injections):
|
||||||
to_inject.update(kwargs)
|
to_inject.update(kwargs)
|
||||||
|
|
||||||
return fn(*args, **to_inject)
|
return fn(*args, **to_inject)
|
||||||
|
|
||||||
|
_patched.__wired__ = True
|
||||||
|
_patched.__original__ = fn
|
||||||
|
_patched.__injections__ = injections
|
||||||
|
|
||||||
return _patched
|
return _patched
|
||||||
|
|
||||||
|
|
||||||
|
def _is_patched(fn):
|
||||||
|
return getattr(fn, '__wired__', False) is True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_original_from_patched(fn):
|
||||||
|
return getattr(fn, '__original__')
|
||||||
|
|
||||||
|
|
||||||
class ClassGetItemMeta(GenericMeta):
|
class ClassGetItemMeta(GenericMeta):
|
||||||
def __getitem__(cls, item):
|
def __getitem__(cls, item):
|
||||||
# Spike for Python 3.6
|
# Spike for Python 3.6
|
||||||
|
|
|
@ -10,13 +10,13 @@ class WiringTest(unittest.TestCase):
|
||||||
|
|
||||||
container: Container
|
container: Container
|
||||||
|
|
||||||
@classmethod
|
def setUp(self) -> None:
|
||||||
def setUpClass(cls) -> None:
|
self.container = Container(config={'a': {'b': {'c': 10}}})
|
||||||
cls.container = Container(config={'a': {'b': {'c': 10}}})
|
self.container.wire(
|
||||||
cls.container.wire(
|
|
||||||
modules=[module],
|
modules=[module],
|
||||||
packages=[package],
|
packages=[package],
|
||||||
)
|
)
|
||||||
|
self.addCleanup(self.container.unwire)
|
||||||
|
|
||||||
def test_package_lookup(self):
|
def test_package_lookup(self):
|
||||||
from .package.subpackage.submodule import test_function
|
from .package.subpackage.submodule import test_function
|
||||||
|
|
Loading…
Reference in New Issue
Block a user