diff --git a/src/dependency_injector/providers.pyx b/src/dependency_injector/providers.pyx index 43e49d7e..d8a8ab35 100644 --- a/src/dependency_injector/providers.pyx +++ b/src/dependency_injector/providers.pyx @@ -1599,7 +1599,7 @@ cdef class ConfigurationOption(Provider): return self._root def get_name(self): - return ".".join((self._root.get_name(), self._get_self_name())) + return f"{self._root.get_name()}.{self._get_self_name()}" def get_name_segments(self): return self._name diff --git a/src/dependency_injector/wiring.py b/src/dependency_injector/wiring.py index 6d5d1510..4b8dbf4d 100644 --- a/src/dependency_injector/wiring.py +++ b/src/dependency_injector/wiring.py @@ -25,6 +25,7 @@ from typing import ( Type, TypeVar, Union, + assert_never, cast, ) from warnings import warn @@ -791,6 +792,9 @@ class TypeModifier(Modifier): ) -> providers.Provider: return provider.as_(self.type_) + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.type_!r})" + def as_int() -> TypeModifier: """Return int type modifier.""" @@ -809,8 +813,8 @@ def as_(type_: Type) -> TypeModifier: class RequiredModifier(Modifier): - def __init__(self) -> None: - self.type_modifier = None + def __init__(self, type_modifier: Optional[TypeModifier] = None) -> None: + self.type_modifier = type_modifier def as_int(self) -> Self: self.type_modifier = TypeModifier(int) @@ -834,6 +838,11 @@ class RequiredModifier(Modifier): provider = provider.as_(self.type_modifier.type_) return provider + def __repr__(self) -> str: + if self.type_modifier: + return f"{self.__class__.__name__}({self.type_modifier!r})" + return f"{self.__class__.__name__}()" + def required() -> RequiredModifier: """Return required modifier.""" @@ -853,6 +862,9 @@ class InvariantModifier(Modifier): invariant_segment = providers_map.resolve_provider(self.id) return provider[invariant_segment] + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.id!r})" + def invariant(id: str) -> InvariantModifier: """Return invariant modifier.""" @@ -893,8 +905,28 @@ class ProvidedInstance(Modifier): provider = provider[value] elif type_ == ProvidedInstance.TYPE_CALL: provider = provider.call() + else: + assert_never(type_) return provider + def _format_segments(self) -> str: + segments = [] + for type_, value in self.segments: + if type_ == ProvidedInstance.TYPE_ATTRIBUTE: + segments.append(f".{value}") + elif type_ == ProvidedInstance.TYPE_ITEM: + segments.append(f"[{value!r}]") + elif type_ == ProvidedInstance.TYPE_CALL: + segments.append(".call()") + else: + assert_never(type_) + return "".join(segments) + + __str__ = _format_segments + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(){self._format_segments()}" + def provided() -> ProvidedInstance: """Return provided instance modifier.""" @@ -910,7 +942,7 @@ MarkerItem = Union[ ] -if TYPE_CHECKING: +if TYPE_CHECKING: # noqa class _Marker(Protocol): __IS_MARKER__: bool @@ -918,6 +950,7 @@ if TYPE_CHECKING: def __call__(self) -> Self: ... def __getattr__(self, item: str) -> Self: ... def __getitem__(self, item: Any) -> Any: ... + def __repr__(self) -> str: ... Provide: _Marker Provider: _Marker @@ -946,6 +979,12 @@ else: def __call__(self) -> Self: return self + def __repr__(self) -> str: + cls_name = self.__class__.__name__ + if self.modifier: + return f"{cls_name}[{self.provider!r}, {self.modifier!r}]" + return f"{cls_name}[{self.provider!r}]" + class Provide(_Marker): ... class Provider(_Marker): ... diff --git a/tests/unit/wiring/provider_ids/test_main_py36.py b/tests/unit/wiring/provider_ids/test_main_py36.py index 15ac31c0..a36e50e8 100644 --- a/tests/unit/wiring/provider_ids/test_main_py36.py +++ b/tests/unit/wiring/provider_ids/test_main_py36.py @@ -1,5 +1,6 @@ """Main wiring tests.""" +import re from decimal import Decimal from dependency_injector import errors @@ -67,7 +68,7 @@ def test_module_attributes_wiring(): def test_module_attribute_wiring_with_invalid_marker(container: Container): from samples.wiring import module_invalid_attr_injection - with raises(Exception, match="Unknown type of marker {0}".format(module_invalid_attr_injection.service)): + with raises(Exception, match=re.escape("Unknown type of marker {0}".format(module_invalid_attr_injection.service))): container.wire(modules=[module_invalid_attr_injection]) diff --git a/tests/unit/wiring/string_ids/test_main_py36.py b/tests/unit/wiring/string_ids/test_main_py36.py index 8125481a..904c4e3e 100644 --- a/tests/unit/wiring/string_ids/test_main_py36.py +++ b/tests/unit/wiring/string_ids/test_main_py36.py @@ -1,5 +1,6 @@ """Main wiring tests.""" +import re from decimal import Decimal from pytest import fixture, mark, raises @@ -68,7 +69,7 @@ def test_module_attributes_wiring(): def test_module_attribute_wiring_with_invalid_marker(container: Container): from samples.wiringstringids import module_invalid_attr_injection - with raises(Exception, match="Unknown type of marker {0}".format(module_invalid_attr_injection.service)): + with raises(Exception, match=re.escape("Unknown type of marker {0}".format(module_invalid_attr_injection.service))): container.wire(modules=[module_invalid_attr_injection]) diff --git a/tests/unit/wiring/test_reprs.py b/tests/unit/wiring/test_reprs.py new file mode 100644 index 00000000..24da7424 --- /dev/null +++ b/tests/unit/wiring/test_reprs.py @@ -0,0 +1,42 @@ +from dependency_injector.wiring import ( + Closing, + InvariantModifier, + Provide, + ProvidedInstance, + RequiredModifier, + TypeModifier, +) + + +def test_type_modifier_repr() -> None: + assert repr(TypeModifier(int)) == f"TypeModifier({int!r})" + + +def test_required_modifier_repr() -> None: + assert repr(RequiredModifier()) == "RequiredModifier()" + + +def test_required_modifier_with_type_repr() -> None: + type_modifier = TypeModifier(int) + required_modifier = RequiredModifier(type_modifier) + assert repr(required_modifier) == f"RequiredModifier({type_modifier!r})" + + +def test_invariant_modifier_repr() -> None: + assert repr(InvariantModifier("test")) == "InvariantModifier('test')" + + +def test_provided_instance_repr() -> None: + provided_instance = ProvidedInstance().test["attr"].call() + + assert repr(provided_instance) == "ProvidedInstance().test['attr'].call()" + + +def test_marker_repr() -> None: + assert repr(Closing[Provide["test"]]) == "Closing[Provide['test']]" + + +def test_marker_with_modifier_repr() -> None: + marker = Provide["test", RequiredModifier()] + + assert repr(marker) == "Provide['test', RequiredModifier()]"