diff --git a/changelog/13530.bugfix.rst b/changelog/13530.bugfix.rst new file mode 100644 index 00000000000..1a5ab365f12 --- /dev/null +++ b/changelog/13530.bugfix.rst @@ -0,0 +1 @@ +Fixed a crash when using :func:`pytest.approx` and :class:`decimal.Decimal` instances with the :class:`decimal.FloatOperation` trap set. diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index 07794abea95..1db667fcbe5 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -530,6 +530,26 @@ class ApproxDecimal(ApproxScalar): DEFAULT_ABSOLUTE_TOLERANCE = Decimal("1e-12") DEFAULT_RELATIVE_TOLERANCE = Decimal("1e-6") + def __repr__(self) -> str: + if isinstance(self.rel, float): + rel = Decimal.from_float(self.rel) + else: + rel = self.rel + + if isinstance(self.abs, float): + abs_ = Decimal.from_float(self.abs) + else: + abs_ = self.abs + + if rel is not None and Decimal("1e-3") <= rel <= Decimal("1e3"): + tol_str = f"{rel:.1e}" + elif abs_ is not None: + tol_str = f"{abs_:.1e}" + else: + tol_str = "???" + + return f"{self.expected} ± {tol_str}" + def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: """Assert that two numbers (or two ordered sequences of numbers) are equal to each other diff --git a/testing/python/approx.py b/testing/python/approx.py index 75b57b6965c..6b46db3df65 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -1015,6 +1015,11 @@ def __len__(self): expected_repr = "approx([1 ± 1.0e-06, 2 ± 2.0e-06, 3 ± 3.0e-06, 4 ± 4.0e-06])" assert repr(approx(expected)) == expected_repr + def test_decimal_approx_repr(self, monkeypatch) -> None: + monkeypatch.setitem(decimal.getcontext().traps, decimal.FloatOperation, True) + approx_obj = pytest.approx(decimal.Decimal("2.60")) + assert decimal.Decimal("2.600001") == approx_obj + def test_allow_ordered_sequences_only(self) -> None: """pytest.approx() should raise an error on unordered sequences (#9692).""" with pytest.raises(TypeError, match="only supports ordered sequences"):