Skip to content
Merged
1 change: 1 addition & 0 deletions changelog/12444.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed :func:`pytest.approx` which now correctly takes account Mapping keys order to compare them.
7 changes: 3 additions & 4 deletions src/_pytest/python_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def _repr_compare(self, other_side: Mapping[object, float]) -> list[str]:
f"Lengths: {len(self.expected)} and {len(other_side)}",
]

if set(self.expected.keys()) != set(other_side.keys()):
if self.expected.keys() != other_side.keys():
return [
"comparison failed.",
f"Mappings has different keys: expected {self.expected.keys()} but got {other_side.keys()}",
Expand All @@ -256,9 +256,8 @@ def _repr_compare(self, other_side: Mapping[object, float]) -> list[str]:
max_abs_diff = -math.inf
max_rel_diff = -math.inf
different_ids = []
for (approx_key, approx_value), other_value in zip(
approx_side_as_map.items(), other_side.values(), strict=True
):
for approx_key, approx_value in approx_side_as_map.items():
other_value = other_side[approx_key]
if approx_value != other_value:
if approx_value.expected is not None and other_value is not None:
try:
Expand Down
40 changes: 40 additions & 0 deletions testing/python/approx.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,46 @@ def test_approx_dicts_with_mismatch_on_keys(self) -> None:
):
assert actual == approx(expected)

def test_approx_on_unordered_mapping_with_mismatch(
self, pytester: Pytester
) -> None:
"""https://github.com/pytest-dev/pytest/issues/12444"""
pytester.makepyfile(
"""
import pytest

def test_approx_on_unordered_mapping_with_mismatch():
expected = {"a": 1, "b": 2, "c": 3, "d": 4}
actual = {"d": 4, "c": 5, "a": 8, "b": 2}
assert actual == pytest.approx(expected)
"""
)
result = pytester.runpytest()
result.assert_outcomes(failed=1)
result.stdout.fnmatch_lines(
[
"*comparison failed.**Mismatched elements: 2 / 4:*",
"*Max absolute difference: 7*",
"*Index | Obtained | Expected *",
"* a * | 8 * | 1 *",
"* c * | 5 * | 3 *",
]
)

def test_approx_on_unordered_mapping_matching(self, pytester: Pytester) -> None:
"""https://github.com/pytest-dev/pytest/issues/12444"""
pytester.makepyfile(
"""
import pytest
def test_approx_on_unordered_mapping_matching():
expected = {"a": 1, "b": 2, "c": 3, "d": 4}
actual = {"d": 4, "c": 3, "a": 1, "b": 2}
assert actual == pytest.approx(expected)
"""
)
result = pytester.runpytest()
result.assert_outcomes(passed=1)


class MyVec3: # incomplete
"""sequence like"""
Expand Down