@@ -38,45 +38,61 @@ def _truncate_explanation(
3838 """Truncate given list of strings that makes up the assertion explanation.
3939
4040 Truncates to either 8 lines, or 640 characters - whichever the input reaches
41- first. The remaining lines will be replaced by a usage message.
41+ first, taking the truncation explanation into account. The remaining lines
42+ will be replaced by a usage message.
4243 """
43-
4444 if max_lines is None :
4545 max_lines = DEFAULT_MAX_LINES
4646 if max_chars is None :
4747 max_chars = DEFAULT_MAX_CHARS
4848
4949 # Check if truncation required
5050 input_char_count = len ("" .join (input_lines ))
51- if len (input_lines ) <= max_lines and input_char_count <= max_chars :
51+ # The length of the truncation explanation depends on the number of line
52+ # removed but is at least 67 characters:
53+ # The real value is
54+ # 64 (for the base message:
55+ # '...\n...Full output truncated (1 line hidden), use '-vv' to show")'
56+ # )
57+ # + 1 (for plural)
58+ # + int(math.log10(len(input_lines) - max_lines)) (number of hidden line)
59+ # + 3 for the '...' added to the truncated line
60+ # But if there's more than 100 lines it's very likely that we're going to
61+ # truncate, so we don't need the exact value using log10.
62+ tolerable_max_chars = (
63+ max_chars + 70 # 64 + 1 (for plural) + 2 (for '99') + 3 for '...'
64+ )
65+ # The truncation explanation add two lines to the output
66+ tolerable_max_lines = max_lines + 2
67+ if (
68+ len (input_lines ) <= tolerable_max_lines
69+ and input_char_count <= tolerable_max_chars
70+ ):
5271 return input_lines
53-
54- # Truncate first to max_lines, and then truncate to max_chars if max_chars
55- # is exceeded.
72+ # Truncate first to max_lines, and then truncate to max_chars if necessary
5673 truncated_explanation = input_lines [:max_lines ]
57- truncated_explanation = _truncate_by_char_count (truncated_explanation , max_chars )
58-
59- # Add ellipsis to final line
60- truncated_explanation [- 1 ] = truncated_explanation [- 1 ] + "..."
74+ # We reevaluate the need to truncate following removal of some lines
75+ if len ("" .join (input_lines )) > tolerable_max_chars :
76+ truncated_explanation = _truncate_by_char_count (
77+ truncated_explanation , max_chars
78+ )
6179
62- # Append useful message to explanation
6380 truncated_line_count = len (input_lines ) - len (truncated_explanation )
64- truncated_line_count += 1 # Account for the part-truncated final line
65- truncated_explanation .extend (
66- [
67- "" , # Line break
68- f"...Full output truncated ({ truncated_line_count } line"
69- f"{ '' if truncated_line_count == 1 else 's' } hidden), { USAGE_MSG } " ,
70- ]
71- )
72- return truncated_explanation
81+ if truncated_explanation [- 1 ]:
82+ # Add ellipsis and take into account part-truncated final line
83+ truncated_explanation [- 1 ] = truncated_explanation [- 1 ] + "..."
84+ truncated_line_count += 1
85+ else :
86+ # Add proper ellipsis when we were able to fit a full line exactly
87+ truncated_explanation [- 1 ] = "..."
88+ return truncated_explanation + [
89+ "" ,
90+ f"...Full output truncated ({ truncated_line_count } line"
91+ f"{ '' if truncated_line_count == 1 else 's' } hidden), { USAGE_MSG } " ,
92+ ]
7393
7494
7595def _truncate_by_char_count (input_lines : List [str ], max_chars : int ) -> List [str ]:
76- # Check if truncation required
77- if len ("" .join (input_lines )) <= max_chars :
78- return input_lines
79-
8096 # Find point at which input length exceeds total allowed length
8197 iterated_char_count = 0
8298 for iterated_index , input_line in enumerate (input_lines ):
0 commit comments