Skip to content

Commit fb525fd

Browse files
Merge pull request #14105 Fix edge case when we truncate due to max_chars
Previously the added test case would output: "...Full output truncated (0 lines hidden), use '-vv' to show" Also removed some useless complexity and some performance improvements.
2 parents fe7e4d5 + c454d2f commit fb525fd

File tree

2 files changed

+33
-31
lines changed

2 files changed

+33
-31
lines changed

src/_pytest/assertion/truncate.py

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,13 @@ def _truncate_explanation(
5959
Truncates to either max_lines, or max_chars - whichever the input reaches
6060
first, taking the truncation explanation into account. The remaining lines
6161
will be replaced by a usage message.
62+
63+
If max_chars=0, no truncation by character count is performed.
64+
If max_lines=0, no truncation by line count is performed.
65+
66+
When this function is launched we know max_lines > 0 or max_chars > 0
67+
because _get_truncation_parameters was called first.
6268
"""
63-
# Check if truncation required
64-
input_char_count = len("".join(input_lines))
6569
# The length of the truncation explanation depends on the number of lines
6670
# removed but is at least 68 characters:
6771
# The real value is
@@ -77,40 +81,27 @@ def _truncate_explanation(
7781
max_chars + 70 # 64 + 1 (for plural) + 2 (for '99') + 3 for '...'
7882
)
7983
# The truncation explanation add two lines to the output
80-
tolerable_max_lines = max_lines + 2
81-
if (
82-
len(input_lines) <= tolerable_max_lines
83-
and input_char_count <= tolerable_max_chars
84-
):
85-
return input_lines
86-
# Truncate first to max_lines, and then truncate to max_chars if necessary
87-
if max_lines > 0:
88-
truncated_explanation = input_lines[:max_lines]
89-
else:
84+
if max_lines == 0 or len(input_lines) <= max_lines + 2:
85+
if max_chars == 0 or sum(len(s) for s in input_lines) <= tolerable_max_chars:
86+
return input_lines
9087
truncated_explanation = input_lines
91-
truncated_char = True
88+
else:
89+
# Truncate first to max_lines, and then truncate to max_chars if necessary
90+
truncated_explanation = input_lines[:max_lines]
9291
# We reevaluate the need to truncate chars following removal of some lines
93-
if len("".join(truncated_explanation)) > tolerable_max_chars and max_chars > 0:
92+
need_to_truncate_char = (
93+
max_chars > 0
94+
and sum(len(e) for e in truncated_explanation) > tolerable_max_chars
95+
)
96+
if need_to_truncate_char:
9497
truncated_explanation = _truncate_by_char_count(
9598
truncated_explanation, max_chars
9699
)
97-
else:
98-
truncated_char = False
99-
100-
if truncated_explanation == input_lines:
101-
# No truncation happened, so we do not need to add any explanations
102-
return truncated_explanation
103-
104-
truncated_line_count = len(input_lines) - len(truncated_explanation)
105-
if truncated_explanation[-1]:
106-
# Add ellipsis and take into account part-truncated final line
107-
truncated_explanation[-1] = truncated_explanation[-1] + "..."
108-
if truncated_char:
109-
# It's possible that we did not remove any char from this line
110-
truncated_line_count += 1
111-
else:
112-
# Add proper ellipsis when we were able to fit a full line exactly
113-
truncated_explanation[-1] = "..."
100+
# Something was truncated, adding '...' at the end to show that
101+
truncated_explanation[-1] += "..."
102+
truncated_line_count = (
103+
len(input_lines) - len(truncated_explanation) + int(need_to_truncate_char)
104+
)
114105
return [
115106
*truncated_explanation,
116107
"",

testing/test_assertion.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,17 @@ def test_truncates_at_8_lines_when_there_is_one_line_to_remove(self) -> None:
13941394
assert result == expl
13951395
assert "truncated" not in result[-1]
13961396

1397+
def test_truncates_full_line_because_of_max_chars(self) -> None:
1398+
"""A line is fully truncated because of the max_chars value."""
1399+
expl = ["a" * 10, "b" * 71]
1400+
result = truncate._truncate_explanation(expl, max_lines=10, max_chars=10)
1401+
assert result == [
1402+
"a" * 10,
1403+
"...",
1404+
"",
1405+
"...Full output truncated (1 line hidden), use '-vv' to show",
1406+
]
1407+
13971408
def test_truncates_edgecase_when_truncation_message_makes_the_result_longer_for_chars(
13981409
self,
13991410
) -> None:

0 commit comments

Comments
 (0)