mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-10-09 21:36:41 +03:00
Merge branch 'release/4.48.2'
This commit is contained in:
commit
5a1aef9203
7
Makefile
7
Makefile
|
@ -1,6 +1,10 @@
|
|||
VERSION := $(shell python setup.py --version)
|
||||
|
||||
export COVERAGE_RCFILE := pyproject.toml
|
||||
export CIBW_ENVIRONMENT_PASS_LINUX := CFLAGS PIP_CONFIG_SETTINGS DEPENDENCY_INJECTOR_LIMITED_API
|
||||
export PIP_CONFIG_SETTINGS ?= build_ext=-j4
|
||||
export DEPENDENCY_INJECTOR_LIMITED_API ?= 1
|
||||
export CFLAGS ?= -g0
|
||||
|
||||
clean:
|
||||
# Clean sources
|
||||
|
@ -63,3 +67,6 @@ publish:
|
|||
# Create and upload tag
|
||||
git tag -a $(VERSION) -m 'version $(VERSION)'
|
||||
git push --tags
|
||||
|
||||
wheels:
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
|
|
|
@ -7,6 +7,13 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
4.48.2
|
||||
------
|
||||
|
||||
- Add ``warn_unresolved=True`` to ``WiringConfiguration`` and ``container.wire()``
|
||||
to produce warnings on unresolved string identifiers.
|
||||
- ABI3 wheels are now built only for CPython version >=3.10 (see issue `#919 <https://github.com/ets-labs/python-dependency-injector/issues/919>`_).
|
||||
|
||||
4.48.1
|
||||
------
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ factories:
|
|||
- :ref:`factory-specialize-provided-type`
|
||||
- :ref:`abstract-factory`
|
||||
|
||||
``Singleton`` provider scope is tied to the container. Two different containers will provider
|
||||
``Singleton`` provider scope is tied to the container. Two different containers will provide
|
||||
two different singleton objects:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/singleton_multiple_containers.py
|
||||
|
|
|
@ -251,6 +251,32 @@ To inject a container use special identifier ``<container>``:
|
|||
def foo(container: Container = Provide["<container>"]) -> None:
|
||||
...
|
||||
|
||||
Caveats
|
||||
~~~~~~~
|
||||
|
||||
While using string identifiers you may not notice a typo in the identifier until the code is executed.
|
||||
In order to aid with catching such errors early, you may pass `warn_unresolved=True` to the ``wire`` method and/or :class:`WiringConfiguration`:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 4
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
wiring_config = containers.WiringConfiguration(
|
||||
modules=["yourapp.module"],
|
||||
warn_unresolved=True,
|
||||
)
|
||||
|
||||
Or:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 4
|
||||
|
||||
container = Container()
|
||||
container.wire(
|
||||
modules=["yourapp.module"],
|
||||
warn_unresolved=True,
|
||||
)
|
||||
|
||||
|
||||
Making injections into modules and class attributes
|
||||
---------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "Cython>=3.1.1"]
|
||||
requires = ["setuptools", "Cython>=3.1.4"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
|
@ -54,7 +54,7 @@ classifiers = [
|
|||
dynamic = ["version"]
|
||||
dependencies = [
|
||||
# typing.Annotated since v3.9
|
||||
# typing.Self since v3.11
|
||||
# typing.Self and typing.assert_never since v3.11
|
||||
"typing-extensions; python_version<'3.11'",
|
||||
]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
cython==3.1.1
|
||||
cython==3.1.4
|
||||
setuptools
|
||||
pytest
|
||||
pytest-asyncio
|
||||
|
|
7
setup.py
7
setup.py
|
@ -2,6 +2,7 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import sysconfig
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Compiler import Options
|
||||
|
@ -11,6 +12,8 @@ debug = os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1"
|
|||
limited_api = (
|
||||
os.environ.get("DEPENDENCY_INJECTOR_LIMITED_API") == "1"
|
||||
and sys.implementation.name == "cpython"
|
||||
and sys.version_info >= (3, 10)
|
||||
and not sysconfig.get_config_var("Py_GIL_DISABLED")
|
||||
)
|
||||
defined_macros = []
|
||||
options = {}
|
||||
|
@ -34,8 +37,8 @@ if debug:
|
|||
|
||||
if limited_api:
|
||||
options.setdefault("bdist_wheel", {})
|
||||
options["bdist_wheel"]["py_limited_api"] = "cp38"
|
||||
defined_macros.append(("Py_LIMITED_API", "0x03080000"))
|
||||
options["bdist_wheel"]["py_limited_api"] = "cp310"
|
||||
defined_macros.append(("Py_LIMITED_API", "0x030A0000"))
|
||||
|
||||
setup(
|
||||
options=options,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Top-level package."""
|
||||
|
||||
__version__ = "4.48.1"
|
||||
__version__ = "4.48.2"
|
||||
"""Version number.
|
||||
|
||||
:type: str
|
||||
|
|
|
@ -72,6 +72,7 @@ class Container:
|
|||
modules: Optional[Iterable[Any]] = None,
|
||||
packages: Optional[Iterable[Any]] = None,
|
||||
from_package: Optional[str] = None,
|
||||
warn_unresolved: bool = False,
|
||||
) -> None: ...
|
||||
def unwire(self) -> None: ...
|
||||
def init_resources(self, resource_type: Type[Resource[Any]] = Resource) -> Optional[Awaitable[None]]: ...
|
||||
|
|
|
@ -20,15 +20,31 @@ from .wiring import wire, unwire
|
|||
class WiringConfiguration:
|
||||
"""Container wiring configuration."""
|
||||
|
||||
def __init__(self, modules=None, packages=None, from_package=None, auto_wire=True, keep_cache=False):
|
||||
def __init__(
|
||||
self,
|
||||
modules=None,
|
||||
packages=None,
|
||||
from_package=None,
|
||||
auto_wire=True,
|
||||
keep_cache=False,
|
||||
warn_unresolved=False,
|
||||
):
|
||||
self.modules = [*modules] if modules else []
|
||||
self.packages = [*packages] if packages else []
|
||||
self.from_package = from_package
|
||||
self.auto_wire = auto_wire
|
||||
self.keep_cache = keep_cache
|
||||
self.warn_unresolved = warn_unresolved
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
return self.__class__(self.modules, self.packages, self.from_package, self.auto_wire, self.keep_cache)
|
||||
return self.__class__(
|
||||
self.modules,
|
||||
self.packages,
|
||||
self.from_package,
|
||||
self.auto_wire,
|
||||
self.keep_cache,
|
||||
self.warn_unresolved,
|
||||
)
|
||||
|
||||
|
||||
class Container:
|
||||
|
@ -259,7 +275,14 @@ class DynamicContainer(Container):
|
|||
"""Check if auto wiring is needed."""
|
||||
return self.wiring_config.auto_wire is True
|
||||
|
||||
def wire(self, modules=None, packages=None, from_package=None, keep_cache=None):
|
||||
def wire(
|
||||
self,
|
||||
modules=None,
|
||||
packages=None,
|
||||
from_package=None,
|
||||
keep_cache=None,
|
||||
warn_unresolved=False,
|
||||
):
|
||||
"""Wire container providers with provided packages and modules.
|
||||
|
||||
:rtype: None
|
||||
|
@ -298,6 +321,7 @@ class DynamicContainer(Container):
|
|||
modules=modules,
|
||||
packages=packages,
|
||||
keep_cache=keep_cache,
|
||||
warn_unresolved=warn_unresolved,
|
||||
)
|
||||
|
||||
if modules:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,9 +30,9 @@ from typing import (
|
|||
from warnings import warn
|
||||
|
||||
try:
|
||||
from typing import Self
|
||||
from typing import Self, assert_never
|
||||
except ImportError:
|
||||
from typing_extensions import Self
|
||||
from typing_extensions import Self, assert_never
|
||||
|
||||
try:
|
||||
from functools import cache
|
||||
|
@ -139,6 +139,10 @@ class DIWiringWarning(RuntimeWarning):
|
|||
"""Base class for all warnings raised by the wiring module."""
|
||||
|
||||
|
||||
class UnresolvedMarkerWarning(DIWiringWarning):
|
||||
"""Warning raised when a marker with string identifier cannot be resolved against container."""
|
||||
|
||||
|
||||
class PatchedRegistry:
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
@ -433,6 +437,7 @@ def wire( # noqa: C901
|
|||
modules: Optional[Iterable[ModuleType]] = None,
|
||||
packages: Optional[Iterable[ModuleType]] = None,
|
||||
keep_cache: bool = False,
|
||||
warn_unresolved: bool = False,
|
||||
) -> None:
|
||||
"""Wire container providers with provided packages and modules."""
|
||||
modules = [*modules] if modules else []
|
||||
|
@ -449,9 +454,23 @@ def wire( # noqa: C901
|
|||
continue
|
||||
|
||||
if _is_marker(member):
|
||||
_patch_attribute(module, member_name, member, providers_map)
|
||||
_patch_attribute(
|
||||
module,
|
||||
member_name,
|
||||
member,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=1,
|
||||
)
|
||||
elif inspect.isfunction(member):
|
||||
_patch_fn(module, member_name, member, providers_map)
|
||||
_patch_fn(
|
||||
module,
|
||||
member_name,
|
||||
member,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=1,
|
||||
)
|
||||
elif inspect.isclass(member):
|
||||
cls = member
|
||||
try:
|
||||
|
@ -463,15 +482,30 @@ def wire( # noqa: C901
|
|||
for cls_member_name, cls_member in cls_members:
|
||||
if _is_marker(cls_member):
|
||||
_patch_attribute(
|
||||
cls, cls_member_name, cls_member, providers_map
|
||||
cls,
|
||||
cls_member_name,
|
||||
cls_member,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=1,
|
||||
)
|
||||
elif _is_method(cls_member):
|
||||
_patch_method(
|
||||
cls, cls_member_name, cls_member, providers_map
|
||||
cls,
|
||||
cls_member_name,
|
||||
cls_member,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=1,
|
||||
)
|
||||
|
||||
for patched in _patched_registry.get_callables_from_module(module):
|
||||
_bind_injections(patched, providers_map)
|
||||
_bind_injections(
|
||||
patched,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=1,
|
||||
)
|
||||
|
||||
if not keep_cache:
|
||||
clear_cache()
|
||||
|
@ -524,6 +558,8 @@ def _patch_fn(
|
|||
name: str,
|
||||
fn: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
warn_unresolved: bool = False,
|
||||
warn_unresolved_stacklevel: int = 0,
|
||||
) -> None:
|
||||
if not _is_patched(fn):
|
||||
reference_injections, reference_closing = _fetch_reference_injections(fn)
|
||||
|
@ -531,7 +567,12 @@ def _patch_fn(
|
|||
return
|
||||
fn = _get_patched(fn, reference_injections, reference_closing)
|
||||
|
||||
_bind_injections(fn, providers_map)
|
||||
_bind_injections(
|
||||
fn,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=warn_unresolved_stacklevel + 1,
|
||||
)
|
||||
|
||||
setattr(module, name, fn)
|
||||
|
||||
|
@ -541,6 +582,8 @@ def _patch_method(
|
|||
name: str,
|
||||
method: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
warn_unresolved: bool = False,
|
||||
warn_unresolved_stacklevel: int = 0,
|
||||
) -> None:
|
||||
if (
|
||||
hasattr(cls, "__dict__")
|
||||
|
@ -558,7 +601,12 @@ def _patch_method(
|
|||
return
|
||||
fn = _get_patched(fn, reference_injections, reference_closing)
|
||||
|
||||
_bind_injections(fn, providers_map)
|
||||
_bind_injections(
|
||||
fn,
|
||||
providers_map,
|
||||
warn_unresolved=warn_unresolved,
|
||||
warn_unresolved_stacklevel=warn_unresolved_stacklevel + 1,
|
||||
)
|
||||
|
||||
if fn is method:
|
||||
# Hotfix, see: https://github.com/ets-labs/python-dependency-injector/issues/884
|
||||
|
@ -594,9 +642,17 @@ def _patch_attribute(
|
|||
name: str,
|
||||
marker: "_Marker",
|
||||
providers_map: ProvidersMap,
|
||||
warn_unresolved: bool = False,
|
||||
warn_unresolved_stacklevel: int = 0,
|
||||
) -> None:
|
||||
provider = providers_map.resolve_provider(marker.provider, marker.modifier)
|
||||
if provider is None:
|
||||
if warn_unresolved:
|
||||
warn(
|
||||
f"Unresolved marker {name} in {member!r}",
|
||||
UnresolvedMarkerWarning,
|
||||
stacklevel=warn_unresolved_stacklevel + 2,
|
||||
)
|
||||
return
|
||||
|
||||
_patched_registry.register_attribute(PatchedAttribute(member, name, marker))
|
||||
|
@ -673,7 +729,12 @@ def _fetch_reference_injections( # noqa: C901
|
|||
return injections, closing
|
||||
|
||||
|
||||
def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> None:
|
||||
def _bind_injections(
|
||||
fn: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
warn_unresolved: bool = False,
|
||||
warn_unresolved_stacklevel: int = 0,
|
||||
) -> None:
|
||||
patched_callable = _patched_registry.get_callable(fn)
|
||||
if patched_callable is None:
|
||||
return
|
||||
|
@ -682,6 +743,12 @@ def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> Non
|
|||
provider = providers_map.resolve_provider(marker.provider, marker.modifier)
|
||||
|
||||
if provider is None:
|
||||
if warn_unresolved:
|
||||
warn(
|
||||
f"Unresolved marker {injection} in {fn.__qualname__}",
|
||||
UnresolvedMarkerWarning,
|
||||
stacklevel=warn_unresolved_stacklevel + 2,
|
||||
)
|
||||
continue
|
||||
|
||||
if isinstance(marker, Provide):
|
||||
|
@ -791,6 +858,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 +879,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 +904,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 +928,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 +971,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 +1008,7 @@ MarkerItem = Union[
|
|||
]
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
if TYPE_CHECKING: # noqa
|
||||
|
||||
class _Marker(Protocol):
|
||||
__IS_MARKER__: bool
|
||||
|
@ -918,6 +1016,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 +1045,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): ...
|
||||
|
|
15
tests/unit/samples/wiringstringids/missing.py
Normal file
15
tests/unit/samples/wiringstringids/missing.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from dependency_injector.wiring import Provide, inject
|
||||
|
||||
missing_obj: object = Provide["missing"]
|
||||
|
||||
|
||||
class TestMissingClass:
|
||||
obj: object = Provide["missing"]
|
||||
|
||||
def method(self, obj: object = Provide["missing"]) -> object:
|
||||
return obj
|
||||
|
||||
|
||||
@inject
|
||||
def test_missing_function(obj: object = Provide["missing"]):
|
||||
return obj
|
|
@ -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])
|
||||
|
||||
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
"""Main wiring tests."""
|
||||
|
||||
import re
|
||||
from decimal import Decimal
|
||||
|
||||
from pytest import fixture, mark, raises
|
||||
from pytest import fixture, mark, raises, warns
|
||||
from samples.wiringstringids import module, package, resourceclosing
|
||||
from samples.wiringstringids.container import Container, SubContainer
|
||||
from samples.wiringstringids.service import Service
|
||||
|
||||
from dependency_injector import errors
|
||||
from dependency_injector.wiring import Closing, Provide, Provider, wire
|
||||
from dependency_injector.wiring import (
|
||||
Closing,
|
||||
Provide,
|
||||
Provider,
|
||||
UnresolvedMarkerWarning,
|
||||
wire,
|
||||
)
|
||||
|
||||
|
||||
@fixture(autouse=True)
|
||||
|
@ -68,10 +75,20 @@ 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])
|
||||
|
||||
|
||||
def test_warn_unresolved_marker(container: Container):
|
||||
from samples.wiringstringids import missing
|
||||
|
||||
with warns(
|
||||
UnresolvedMarkerWarning,
|
||||
match=r"^Unresolved marker .+ in .+$",
|
||||
):
|
||||
container.wire(modules=[missing], warn_unresolved=True)
|
||||
|
||||
|
||||
def test_class_wiring():
|
||||
test_class_object = module.TestClass()
|
||||
assert isinstance(test_class_object.service, Service)
|
||||
|
|
42
tests/unit/wiring/test_reprs.py
Normal file
42
tests/unit/wiring/test_reprs.py
Normal file
|
@ -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()]"
|
Loading…
Reference in New Issue
Block a user