-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy path_compare_sequence.py
More file actions
104 lines (92 loc) · 3.83 KB
/
Copy path_compare_sequence.py
File metadata and controls
104 lines (92 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from __future__ import annotations
from collections.abc import Iterable
from collections.abc import Iterator
from collections.abc import Sequence
from _pytest._io.pprint import PrettyPrinter
from _pytest._io.saferepr import saferepr
from _pytest.assertion._typing import _HighlightFunc
from _pytest.assertion._typing import NO_TRUNCATION_BUDGET
from _pytest.assertion._typing import TruncationBudget
from _pytest.compat import running_on_ci
def _compare_eq_iterable(
left: Iterable[object],
right: Iterable[object],
highlighter: _HighlightFunc,
verbose: int = 0,
truncation_budget: TruncationBudget = NO_TRUNCATION_BUDGET,
) -> Iterator[str]:
if verbose <= 0 and not running_on_ci():
yield "Use -v to get more diff"
return
# dynamic import to speedup pytest
import difflib
# ``truncation_budget`` is ``(max_lines, max_chars)``, computed by the
# dispatcher from the truncator's ``truncation_limit_lines`` /
# ``truncation_limit_chars``: when truncation is going to drop
# everything past those budgets anyway, we don't bother formatting
# more. ``(None, None)`` means no cap (``-vv`` or CI: the user wants
# the full diff).
pp = PrettyPrinter()
max_lines, max_chars = truncation_budget
left_formatting = pp.pformat_lines(left, max_lines=max_lines, max_chars=max_chars)
right_formatting = pp.pformat_lines(right, max_lines=max_lines, max_chars=max_chars)
yield ""
yield "Full diff:"
# "right" is the expected base against which we compare "left",
# see https://github.com/pytest-dev/pytest/issues/3333
#
# Yield each ndiff line through the highlighter individually so the
# streaming truncator can stop pulling from ``difflib.ndiff`` as
# soon as its budget is full. The diff lexer is line-oriented, so
# per-line highlighting is equivalent — it just adds a redundant
# ``\x1b[0m`` reset at the start of each line (invisible to the
# terminal).
for line in difflib.ndiff(right_formatting, left_formatting):
yield highlighter(line.rstrip(), lexer="diff")
def _compare_eq_sequence(
left: Sequence[object],
right: Sequence[object],
highlighter: _HighlightFunc,
verbose: int = 0,
) -> Iterator[str]:
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)):
if left[i] != right[i]:
if comparing_bytes:
# when comparing bytes, we want to see their ascii representation
# instead of their numeric values (#5260)
# using a slice gives us the ascii representation:
# >>> s = b'foo'
# >>> s[0]
# 102
# >>> s[0:1]
# b'f'
left_value: object = left[i : i + 1]
right_value: object = right[i : i + 1]
else:
left_value = left[i]
right_value = right[i]
yield (
f"At index {i} diff:"
f" {highlighter(repr(left_value))} != {highlighter(repr(right_value))}"
)
break
if comparing_bytes:
# when comparing bytes, it doesn't help to show the "sides contain one or more
# items" longer explanation, so skip it
return
len_diff = len_left - len_right
if len_diff:
if len_diff > 0:
dir_with_more = "Left"
extra = saferepr(left[len_right])
else:
len_diff = 0 - len_diff
dir_with_more = "Right"
extra = saferepr(right[len_left])
if len_diff == 1:
yield f"{dir_with_more} contains one more item: {highlighter(extra)}"
else:
yield f"{dir_with_more} contains {len_diff} more items, first extra item: {highlighter(extra)}"