diff --git a/changelog/8703.bugfix.rst b/changelog/8703.bugfix.rst new file mode 100644 index 00000000000..dd48e95aa83 --- /dev/null +++ b/changelog/8703.bugfix.rst @@ -0,0 +1 @@ +Fixed ``pytest.approx()`` silently falling back to exact equality when a dict value is itself a list or dict. Nested sequences and mappings are now compared with the same tolerance as top-level ones. diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index d7f4c2dcef8..6344b238da1 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -98,6 +98,10 @@ def _approx_scalar(self, x) -> ApproxBase: return ApproxDecimal(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) if isinstance(x, (datetime, timedelta)): return ApproxTimedelta(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) + if isinstance(x, Mapping): + return ApproxMapping(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) + if _is_sequence_like(x): + return ApproxSequenceLike(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) def _yield_comparisons(self, actual): diff --git a/testing/python/approx.py b/testing/python/approx.py index 88d46cbb755..2108fb9522f 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -679,6 +679,10 @@ def test_list_wrong_len(self): assert [1, 2] != approx([1]) assert [1, 2] != approx([1, 2, 3]) + def test_list_with_dict_elements(self): + assert [{"a": 1.0 + 1e-7}] == approx([{"a": 1.0}], abs=1e-5) + assert [{"a": 1.0 + 1e-4}] != approx([{"a": 1.0}], abs=1e-5) + def test_tuple(self): actual = (1 + 1e-7, 2 + 1e-8) expected = (1, 2) @@ -726,6 +730,10 @@ def test_dict_nonnumeric(self): assert {"a": 1.0, "b": 1} != pytest.approx({"a": 1.0, "b": None}) assert {"a": 1.0, "b": True} != pytest.approx({"a": 1.0, "b": False}, abs=2) + def test_dict_with_list_values(self): + assert {"a": [1.0, 2.0 + 1e-7]} == approx({"a": [1.0, 2.0]}, abs=1e-5) + assert {"a": [1.0, 2.0 + 1e-4]} != approx({"a": [1.0, 2.0]}, abs=1e-5) + def test_dict_vs_other(self): assert 1 != approx({"a": 0})