mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-24 10:34:01 +03:00
Wiring: attribute injections (#414)
* Add implementation * Add tests for module and class * Add tests for module and class for string ids * Update tests with typing * Add tests for invalid type of marker * Add docs and the example * Update changelog * Fix Python 3.6 tests and flake8
This commit is contained in:
parent
c787ac2f63
commit
da13341453
|
@ -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 wiring injections into modules and class attributes.
|
||||||
|
See issue: `#411 <https://github.com/ets-labs/python-dependency-injector/issues/411>`_.
|
||||||
|
Many thanks to `@brunopereira27 <https://github.com/brunopereira27>`_ for submitting
|
||||||
|
the use case.
|
||||||
|
|
||||||
4.27.0
|
4.27.0
|
||||||
------
|
------
|
||||||
- Introduce wiring inspect filter to filter out ``flask.request`` and other local proxy objects
|
- Introduce wiring inspect filter to filter out ``flask.request`` and other local proxy objects
|
||||||
|
|
|
@ -164,6 +164,29 @@ To inject a container use special identifier ``<container>``:
|
||||||
def foo(container: Container = Provide['<container>']) -> None:
|
def foo(container: Container = Provide['<container>']) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
Making injections into modules and class attributes
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
You can use wiring to make injections into modules and class attributes.
|
||||||
|
|
||||||
|
.. literalinclude:: ../examples/wiring/example_attribute.py
|
||||||
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
:emphasize-lines: 16,21
|
||||||
|
|
||||||
|
You could also use string identifiers to avoid a dependency on a container:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:emphasize-lines: 1,6
|
||||||
|
|
||||||
|
service: Service = Provide['service']
|
||||||
|
|
||||||
|
|
||||||
|
class Main:
|
||||||
|
|
||||||
|
service: Service = Provide['service']
|
||||||
|
|
||||||
Wiring with modules and packages
|
Wiring with modules and packages
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|
31
examples/wiring/example_attribute.py
Normal file
31
examples/wiring/example_attribute.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
"""Wiring attribute example."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
from dependency_injector.wiring import Provide
|
||||||
|
|
||||||
|
|
||||||
|
class Service:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
service = providers.Factory(Service)
|
||||||
|
|
||||||
|
|
||||||
|
service: Service = Provide[Container.service]
|
||||||
|
|
||||||
|
|
||||||
|
class Main:
|
||||||
|
|
||||||
|
service: Service = Provide[Container.service]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container()
|
||||||
|
container.wire(modules=[sys.modules[__name__]])
|
||||||
|
|
||||||
|
assert isinstance(service, Service)
|
||||||
|
assert isinstance(Main.service, Service)
|
|
@ -20,6 +20,7 @@ from typing import (
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Type,
|
Type,
|
||||||
Union,
|
Union,
|
||||||
|
Set,
|
||||||
cast,
|
cast,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -82,22 +83,53 @@ F = TypeVar('F', bound=Callable[..., Any])
|
||||||
Container = Any
|
Container = Any
|
||||||
|
|
||||||
|
|
||||||
class Registry:
|
class PatchedRegistry:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._storage = set()
|
self._callables: Set[Callable[..., Any]] = set()
|
||||||
|
self._attributes: Set[PatchedAttribute] = set()
|
||||||
|
|
||||||
def add(self, patched: Callable[..., Any]) -> None:
|
def add_callable(self, patched: Callable[..., Any]) -> None:
|
||||||
self._storage.add(patched)
|
self._callables.add(patched)
|
||||||
|
|
||||||
def get_from_module(self, module: ModuleType) -> Iterator[Callable[..., Any]]:
|
def get_callables_from_module(self, module: ModuleType) -> Iterator[Callable[..., Any]]:
|
||||||
for patched in self._storage:
|
for patched in self._callables:
|
||||||
if patched.__module__ != module.__name__:
|
if patched.__module__ != module.__name__:
|
||||||
continue
|
continue
|
||||||
yield patched
|
yield patched
|
||||||
|
|
||||||
|
def add_attribute(self, patched: 'PatchedAttribute'):
|
||||||
|
self._attributes.add(patched)
|
||||||
|
|
||||||
_patched_registry = Registry()
|
def get_attributes_from_module(self, module: ModuleType) -> Iterator['PatchedAttribute']:
|
||||||
|
for attribute in self._attributes:
|
||||||
|
if not attribute.is_in_module(module):
|
||||||
|
continue
|
||||||
|
yield attribute
|
||||||
|
|
||||||
|
def clear_module_attributes(self, module: ModuleType):
|
||||||
|
for attribute in self._attributes.copy():
|
||||||
|
if not attribute.is_in_module(module):
|
||||||
|
continue
|
||||||
|
self._attributes.remove(attribute)
|
||||||
|
|
||||||
|
|
||||||
|
class PatchedAttribute:
|
||||||
|
|
||||||
|
def __init__(self, member: Any, name: str, marker: '_Marker'):
|
||||||
|
self.member = member
|
||||||
|
self.name = name
|
||||||
|
self.marker = marker
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module_name(self) -> str:
|
||||||
|
if isinstance(self.member, ModuleType):
|
||||||
|
return self.member.__name__
|
||||||
|
else:
|
||||||
|
return self.member.__module__
|
||||||
|
|
||||||
|
def is_in_module(self, module: ModuleType) -> bool:
|
||||||
|
return self.module_name == module.__name__
|
||||||
|
|
||||||
|
|
||||||
class ProvidersMap:
|
class ProvidersMap:
|
||||||
|
@ -278,9 +310,6 @@ class InspectFilter:
|
||||||
and issubclass(instance, starlette.requests.Request)
|
and issubclass(instance, starlette.requests.Request)
|
||||||
|
|
||||||
|
|
||||||
inspect_filter = InspectFilter()
|
|
||||||
|
|
||||||
|
|
||||||
def wire( # noqa: C901
|
def wire( # noqa: C901
|
||||||
container: Container,
|
container: Container,
|
||||||
*,
|
*,
|
||||||
|
@ -301,20 +330,27 @@ def wire( # noqa: C901
|
||||||
providers_map = ProvidersMap(container)
|
providers_map = ProvidersMap(container)
|
||||||
|
|
||||||
for module in modules:
|
for module in modules:
|
||||||
for name, member in inspect.getmembers(module):
|
for member_name, member in inspect.getmembers(module):
|
||||||
if inspect_filter.is_excluded(member):
|
if _inspect_filter.is_excluded(member):
|
||||||
continue
|
continue
|
||||||
if inspect.isfunction(member):
|
|
||||||
_patch_fn(module, name, member, providers_map)
|
|
||||||
elif inspect.isclass(member):
|
|
||||||
for method_name, method in inspect.getmembers(member, _is_method):
|
|
||||||
_patch_method(member, method_name, method, providers_map)
|
|
||||||
|
|
||||||
for patched in _patched_registry.get_from_module(module):
|
if _is_marker(member):
|
||||||
|
_patch_attribute(module, member_name, member, providers_map)
|
||||||
|
elif inspect.isfunction(member):
|
||||||
|
_patch_fn(module, member_name, member, providers_map)
|
||||||
|
elif inspect.isclass(member):
|
||||||
|
cls = member
|
||||||
|
for cls_member_name, cls_member in inspect.getmembers(cls):
|
||||||
|
if _is_marker(cls_member):
|
||||||
|
_patch_attribute(cls, cls_member_name, cls_member, providers_map)
|
||||||
|
elif _is_method(cls_member):
|
||||||
|
_patch_method(cls, cls_member_name, cls_member, providers_map)
|
||||||
|
|
||||||
|
for patched in _patched_registry.get_callables_from_module(module):
|
||||||
_bind_injections(patched, providers_map)
|
_bind_injections(patched, providers_map)
|
||||||
|
|
||||||
|
|
||||||
def unwire(
|
def unwire( # noqa: C901
|
||||||
*,
|
*,
|
||||||
modules: Optional[Iterable[ModuleType]] = None,
|
modules: Optional[Iterable[ModuleType]] = None,
|
||||||
packages: Optional[Iterable[ModuleType]] = None,
|
packages: Optional[Iterable[ModuleType]] = None,
|
||||||
|
@ -335,15 +371,19 @@ def unwire(
|
||||||
for method_name, method in inspect.getmembers(member, inspect.isfunction):
|
for method_name, method in inspect.getmembers(member, inspect.isfunction):
|
||||||
_unpatch(member, method_name, method)
|
_unpatch(member, method_name, method)
|
||||||
|
|
||||||
for patched in _patched_registry.get_from_module(module):
|
for patched in _patched_registry.get_callables_from_module(module):
|
||||||
_unbind_injections(patched)
|
_unbind_injections(patched)
|
||||||
|
|
||||||
|
for patched_attribute in _patched_registry.get_attributes_from_module(module):
|
||||||
|
_unpatch_attribute(patched_attribute)
|
||||||
|
_patched_registry.clear_module_attributes(module)
|
||||||
|
|
||||||
|
|
||||||
def inject(fn: F) -> F:
|
def inject(fn: F) -> F:
|
||||||
"""Decorate callable with injecting decorator."""
|
"""Decorate callable with injecting decorator."""
|
||||||
reference_injections, reference_closing = _fetch_reference_injections(fn)
|
reference_injections, reference_closing = _fetch_reference_injections(fn)
|
||||||
patched = _get_patched(fn, reference_injections, reference_closing)
|
patched = _get_patched(fn, reference_injections, reference_closing)
|
||||||
_patched_registry.add(patched)
|
_patched_registry.add_callable(patched)
|
||||||
return cast(F, patched)
|
return cast(F, patched)
|
||||||
|
|
||||||
|
|
||||||
|
@ -358,7 +398,7 @@ def _patch_fn(
|
||||||
if not reference_injections:
|
if not reference_injections:
|
||||||
return
|
return
|
||||||
fn = _get_patched(fn, reference_injections, reference_closing)
|
fn = _get_patched(fn, reference_injections, reference_closing)
|
||||||
_patched_registry.add(fn)
|
_patched_registry.add_callable(fn)
|
||||||
|
|
||||||
_bind_injections(fn, providers_map)
|
_bind_injections(fn, providers_map)
|
||||||
|
|
||||||
|
@ -384,7 +424,7 @@ def _patch_method(
|
||||||
if not reference_injections:
|
if not reference_injections:
|
||||||
return
|
return
|
||||||
fn = _get_patched(fn, reference_injections, reference_closing)
|
fn = _get_patched(fn, reference_injections, reference_closing)
|
||||||
_patched_registry.add(fn)
|
_patched_registry.add_callable(fn)
|
||||||
|
|
||||||
_bind_injections(fn, providers_map)
|
_bind_injections(fn, providers_map)
|
||||||
|
|
||||||
|
@ -411,6 +451,31 @@ def _unpatch(
|
||||||
_unbind_injections(fn)
|
_unbind_injections(fn)
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_attribute(
|
||||||
|
member: Any,
|
||||||
|
name: str,
|
||||||
|
marker: '_Marker',
|
||||||
|
providers_map: ProvidersMap,
|
||||||
|
) -> None:
|
||||||
|
provider = providers_map.resolve_provider(marker.provider, marker.modifier)
|
||||||
|
if provider is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
_patched_registry.add_attribute(PatchedAttribute(member, name, marker))
|
||||||
|
|
||||||
|
if isinstance(marker, Provide):
|
||||||
|
instance = provider()
|
||||||
|
setattr(member, name, instance)
|
||||||
|
elif isinstance(marker, Provider):
|
||||||
|
setattr(member, name, provider)
|
||||||
|
else:
|
||||||
|
raise Exception(f'Unknown type of marker {marker}')
|
||||||
|
|
||||||
|
|
||||||
|
def _unpatch_attribute(patched: PatchedAttribute) -> None:
|
||||||
|
setattr(patched.member, patched.name, patched.marker)
|
||||||
|
|
||||||
|
|
||||||
def _fetch_reference_injections(
|
def _fetch_reference_injections(
|
||||||
fn: Callable[..., Any],
|
fn: Callable[..., Any],
|
||||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||||
|
@ -484,6 +549,10 @@ def _is_method(member):
|
||||||
return inspect.ismethod(member) or inspect.isfunction(member)
|
return inspect.ismethod(member) or inspect.isfunction(member)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_marker(member):
|
||||||
|
return isinstance(member, _Marker)
|
||||||
|
|
||||||
|
|
||||||
def _get_patched(fn, reference_injections, reference_closing):
|
def _get_patched(fn, reference_injections, reference_closing):
|
||||||
if inspect.iscoroutinefunction(fn):
|
if inspect.iscoroutinefunction(fn):
|
||||||
patched = _get_async_patched(fn)
|
patched = _get_async_patched(fn)
|
||||||
|
@ -825,9 +894,6 @@ class AutoLoader:
|
||||||
importlib.invalidate_caches()
|
importlib.invalidate_caches()
|
||||||
|
|
||||||
|
|
||||||
_loader = AutoLoader()
|
|
||||||
|
|
||||||
|
|
||||||
def register_loader_containers(*containers: Container) -> None:
|
def register_loader_containers(*containers: Container) -> None:
|
||||||
"""Register containers in auto-wiring module loader."""
|
"""Register containers in auto-wiring module loader."""
|
||||||
_loader.register_containers(*containers)
|
_loader.register_containers(*containers)
|
||||||
|
@ -851,3 +917,8 @@ def uninstall_loader() -> None:
|
||||||
def is_loader_installed() -> bool:
|
def is_loader_installed() -> bool:
|
||||||
"""Check if auto-wiring module loader hook is installed."""
|
"""Check if auto-wiring module loader hook is installed."""
|
||||||
return _loader.installed
|
return _loader.installed
|
||||||
|
|
||||||
|
|
||||||
|
_patched_registry = PatchedRegistry()
|
||||||
|
_inspect_filter = InspectFilter()
|
||||||
|
_loader = AutoLoader()
|
||||||
|
|
|
@ -3,14 +3,24 @@
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
|
from dependency_injector import providers
|
||||||
from dependency_injector.wiring import inject, Provide, Provider
|
from dependency_injector.wiring import inject, Provide, Provider
|
||||||
|
|
||||||
from .container import Container, SubContainer
|
from .container import Container, SubContainer
|
||||||
from .service import Service
|
from .service import Service
|
||||||
|
|
||||||
|
|
||||||
|
service: Service = Provide[Container.service]
|
||||||
|
service_provider: Callable[..., Service] = Provider[Container.service]
|
||||||
|
undefined: Callable = Provide[providers.Provider()]
|
||||||
|
|
||||||
|
|
||||||
class TestClass:
|
class TestClass:
|
||||||
|
|
||||||
|
service: Service = Provide[Container.service]
|
||||||
|
service_provider: Callable[..., Service] = Provider[Container.service]
|
||||||
|
undefined: Callable = Provide[providers.Provider()]
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
def __init__(self, service: Service = Provide[Container.service]):
|
def __init__(self, service: Service = Provide[Container.service]):
|
||||||
self.service = service
|
self.service = service
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
"""Test module for wiring with invalid type of marker for attribute injection."""
|
||||||
|
|
||||||
|
from dependency_injector.wiring import Closing
|
||||||
|
|
||||||
|
from .container import Container
|
||||||
|
|
||||||
|
|
||||||
|
service = Closing[Container.service]
|
|
@ -19,8 +19,17 @@ from .container import Container
|
||||||
from .service import Service
|
from .service import Service
|
||||||
|
|
||||||
|
|
||||||
|
service: Service = Provide['service']
|
||||||
|
service_provider: Callable[..., Service] = Provider['service']
|
||||||
|
undefined: Callable = Provide['undefined']
|
||||||
|
|
||||||
|
|
||||||
class TestClass:
|
class TestClass:
|
||||||
|
|
||||||
|
service: Service = Provide['service']
|
||||||
|
service_provider: Callable[..., Service] = Provider['service']
|
||||||
|
undefined: Callable = Provide['undefined']
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
def __init__(self, service: Service = Provide['service']):
|
def __init__(self, service: Service = Provide['service']):
|
||||||
self.service = service
|
self.service = service
|
||||||
|
|
|
@ -6,6 +6,7 @@ import unittest
|
||||||
from dependency_injector.wiring import (
|
from dependency_injector.wiring import (
|
||||||
wire,
|
wire,
|
||||||
Provide,
|
Provide,
|
||||||
|
Provider,
|
||||||
Closing,
|
Closing,
|
||||||
register_loader_containers,
|
register_loader_containers,
|
||||||
unregister_loader_containers,
|
unregister_loader_containers,
|
||||||
|
@ -64,6 +65,20 @@ class WiringTest(unittest.TestCase):
|
||||||
service = test_function()
|
service = test_function()
|
||||||
self.assertIsInstance(service, Service)
|
self.assertIsInstance(service, Service)
|
||||||
|
|
||||||
|
def test_module_attributes_wiring(self):
|
||||||
|
self.assertIsInstance(module.service, Service)
|
||||||
|
self.assertIsInstance(module.service_provider(), Service)
|
||||||
|
self.assertIsInstance(module.undefined, Provide)
|
||||||
|
|
||||||
|
def test_module_attribute_wiring_with_invalid_marker(self):
|
||||||
|
from wiringsamples import module_invalid_attr_injection
|
||||||
|
with self.assertRaises(Exception) as context:
|
||||||
|
self.container.wire(modules=[module_invalid_attr_injection])
|
||||||
|
self.assertEqual(
|
||||||
|
str(context.exception),
|
||||||
|
'Unknown type of marker {0}'.format(module_invalid_attr_injection.service),
|
||||||
|
)
|
||||||
|
|
||||||
def test_class_wiring(self):
|
def test_class_wiring(self):
|
||||||
test_class_object = module.TestClass()
|
test_class_object = module.TestClass()
|
||||||
self.assertIsInstance(test_class_object.service, Service)
|
self.assertIsInstance(test_class_object.service, Service)
|
||||||
|
@ -97,6 +112,11 @@ class WiringTest(unittest.TestCase):
|
||||||
service = instance.static_method()
|
service = instance.static_method()
|
||||||
self.assertIsInstance(service, Service)
|
self.assertIsInstance(service, Service)
|
||||||
|
|
||||||
|
def test_class_attribute_wiring(self):
|
||||||
|
self.assertIsInstance(module.TestClass.service, Service)
|
||||||
|
self.assertIsInstance(module.TestClass.service_provider(), Service)
|
||||||
|
self.assertIsInstance(module.TestClass.undefined, Provide)
|
||||||
|
|
||||||
def test_function_wiring(self):
|
def test_function_wiring(self):
|
||||||
service = module.test_function()
|
service = module.test_function()
|
||||||
self.assertIsInstance(service, Service)
|
self.assertIsInstance(service, Service)
|
||||||
|
@ -215,6 +235,18 @@ class WiringTest(unittest.TestCase):
|
||||||
self.container.unwire()
|
self.container.unwire()
|
||||||
self.assertIsInstance(submodule.test_function(), Provide)
|
self.assertIsInstance(submodule.test_function(), Provide)
|
||||||
|
|
||||||
|
def test_unwire_module_attributes(self):
|
||||||
|
self.container.unwire()
|
||||||
|
self.assertIsInstance(module.service, Provide)
|
||||||
|
self.assertIsInstance(module.service_provider, Provider)
|
||||||
|
self.assertIsInstance(module.undefined, Provide)
|
||||||
|
|
||||||
|
def test_unwire_class_attributes(self):
|
||||||
|
self.container.unwire()
|
||||||
|
self.assertIsInstance(module.TestClass.service, Provide)
|
||||||
|
self.assertIsInstance(module.TestClass.service_provider, Provider)
|
||||||
|
self.assertIsInstance(module.TestClass.undefined, Provide)
|
||||||
|
|
||||||
def test_wire_multiple_containers(self):
|
def test_wire_multiple_containers(self):
|
||||||
sub_container = SubContainer()
|
sub_container = SubContainer()
|
||||||
sub_container.wire(
|
sub_container.wire(
|
||||||
|
|
|
@ -4,7 +4,9 @@ import unittest
|
||||||
from dependency_injector.wiring import (
|
from dependency_injector.wiring import (
|
||||||
wire,
|
wire,
|
||||||
Provide,
|
Provide,
|
||||||
Closing)
|
Provider,
|
||||||
|
Closing,
|
||||||
|
)
|
||||||
from dependency_injector import errors
|
from dependency_injector import 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
|
||||||
|
@ -59,6 +61,11 @@ class WiringTest(unittest.TestCase):
|
||||||
service = test_function()
|
service = test_function()
|
||||||
self.assertIsInstance(service, Service)
|
self.assertIsInstance(service, Service)
|
||||||
|
|
||||||
|
def test_module_attributes_wiring(self):
|
||||||
|
self.assertIsInstance(module.service, Service)
|
||||||
|
self.assertIsInstance(module.service_provider(), Service)
|
||||||
|
self.assertIsInstance(module.undefined, Provide)
|
||||||
|
|
||||||
def test_class_wiring(self):
|
def test_class_wiring(self):
|
||||||
test_class_object = module.TestClass()
|
test_class_object = module.TestClass()
|
||||||
self.assertIsInstance(test_class_object.service, Service)
|
self.assertIsInstance(test_class_object.service, Service)
|
||||||
|
@ -92,6 +99,11 @@ class WiringTest(unittest.TestCase):
|
||||||
service = instance.static_method()
|
service = instance.static_method()
|
||||||
self.assertIsInstance(service, Service)
|
self.assertIsInstance(service, Service)
|
||||||
|
|
||||||
|
def test_class_attribute_wiring(self):
|
||||||
|
self.assertIsInstance(module.TestClass.service, Service)
|
||||||
|
self.assertIsInstance(module.TestClass.service_provider(), Service)
|
||||||
|
self.assertIsInstance(module.TestClass.undefined, Provide)
|
||||||
|
|
||||||
def test_function_wiring(self):
|
def test_function_wiring(self):
|
||||||
service = module.test_function()
|
service = module.test_function()
|
||||||
self.assertIsInstance(service, Service)
|
self.assertIsInstance(service, Service)
|
||||||
|
@ -210,6 +222,18 @@ class WiringTest(unittest.TestCase):
|
||||||
self.container.unwire()
|
self.container.unwire()
|
||||||
self.assertIsInstance(submodule.test_function(), Provide)
|
self.assertIsInstance(submodule.test_function(), Provide)
|
||||||
|
|
||||||
|
def test_unwire_module_attributes(self):
|
||||||
|
self.container.unwire()
|
||||||
|
self.assertIsInstance(module.service, Provide)
|
||||||
|
self.assertIsInstance(module.service_provider, Provider)
|
||||||
|
self.assertIsInstance(module.undefined, Provide)
|
||||||
|
|
||||||
|
def test_unwire_class_attributes(self):
|
||||||
|
self.container.unwire()
|
||||||
|
self.assertIsInstance(module.TestClass.service, Provide)
|
||||||
|
self.assertIsInstance(module.TestClass.service_provider, Provider)
|
||||||
|
self.assertIsInstance(module.TestClass.undefined, Provide)
|
||||||
|
|
||||||
def test_wire_multiple_containers(self):
|
def test_wire_multiple_containers(self):
|
||||||
sub_container = SubContainer()
|
sub_container = SubContainer()
|
||||||
sub_container.wire(
|
sub_container.wire(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user