Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/6772.improvement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved assertion failure output for unequal ``range`` objects by avoiding unhelpful full diffs while retaining sequence difference details.
3 changes: 3 additions & 0 deletions src/_pytest/assertion/_compare_any.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def _compare_eq_any(
)

if isiterable(left) and isiterable(right):
if isinstance(left, range) and isinstance(right, range):
# Sequence output already covers ranges; skip the noisy repr diff.
return
yield from _compare_eq_iterable(
left, right, highlighter, verbose, truncation_budget
)
Expand Down
6 changes: 5 additions & 1 deletion src/_pytest/assertion/_compare_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ def _compare_eq_sequence(
comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes)
len_left = len(left)
len_right = len(right)
for i in range(min(len_left, len_right)):
common_length = min(len_left, len_right)
if isinstance(left, range) and isinstance(right, range):
# First two items fix start and step, so the prefix check is O(1).
common_length = min(common_length, 2)
for i in range(common_length):
if left[i] != right[i]:
if comparing_bytes:
# when comparing bytes, we want to see their ascii representation
Expand Down
43 changes: 43 additions & 0 deletions testing/test_assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,49 @@ def test_list_different_lengths(self) -> None:
assert expl is not None
assert len(expl) > 1

def test_range_different_lengths(self) -> None:
assert callequal(range(5), range(7)) == [
"range(0, 5) == range(0, 7)",
"",
"Right contains 2 more items, first extra item: 5",
]
assert callequal(range(7), range(5)) == [
"range(0, 7) == range(0, 5)",
"",
"Left contains 2 more items, first extra item: 5",
]
# Verbose adds no full diff for ranges.
assert callequal(range(5), range(7), verbose=1) == callequal(range(5), range(7))

def test_range_different_items(self) -> None:
assert callequal(range(5), range(1, 6)) == [
"range(0, 5) == range(1, 6)",
"",
"At index 0 diff: 0 != 1",
]
assert callequal(range(0, 10, 2), range(0, 13, 3)) == [
"range(0, 10, 2) == range(0, 13, 3)",
"",
"At index 1 diff: 2 != 3",
]
assert callequal(range(5), range(1, 6), verbose=1) == callequal(
range(5), range(1, 6)
)

def test_range_huge_comparison_is_fast(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
def test_huge_range():
assert range(10**12) == range(10**12 + 2)
"""
)
result = pytester.runpytest_subprocess("-v", timeout=10)
assert result.ret == 1
result.stdout.fnmatch_lines(
["E*Right contains 2 more items, first extra item: 1000000000000*"]
)
result.stdout.no_fnmatch_line("E*Full diff*")

def test_list_wrap_for_multiple_lines(self) -> None:
long_d = "d" * 80
l1 = ["a", "b", "c"]
Expand Down
Loading