Restructure truncation of assertion messages#1995
Restructure truncation of assertion messages#1995nicoddemus merged 3 commits intopytest-dev:featuresfrom
Conversation
This addresses ref pytest-dev#1954. The current truncation for assertion explanations does not deal with long lines properly: - Previously if lines were too long it would display a "-n more lines" message. - 999e7c6 introduced a bug where long lines can cause index errors if there are < 10 lines. Extract the truncation logic into its own file and ensure it can deal with long lines properly.
| return verbose < 2 and not _running_on_ci() | ||
|
|
||
|
|
||
| def _running_on_ci(): |
There was a problem hiding this comment.
@flub previously noted this:
Not sure it's right to use this _running_on_ci() condition. It's a very hidden configuration option. Either it needs to be configured separetely and then it probably needs a new command line option or config file option or it's fine being linked to -vN.
I haven't looked into this yet, but I agree that this shouldn't be so hidden.
What's the reason for truncating output on CI?
There was a problem hiding this comment.
Actually, reverse question... CI is displaying full output. What's the reason that we can't solve this by running on CI using -vv?
There was a problem hiding this comment.
This is addressed in the original commit message, it attempts to provide some utility for the user:
Always show full comparison output if on CI.
When you don't get enough information with a test running on a CI, it's quite
frustrating, for various reasons:
- It's more likely to be a flaky test, so you might not be able to reproduce
the failure.
- Passing -vv is quite bothersome (creating a temporary commit and reverting
it)
For those reasons, if something goes wrong on CI, it's good to have as much
information as possible.
Hey @The-Compiler, what makes passing -vv bothersome? Is it because it makes the output (other than your failing test) too verbose? I'm not sure I understand why you need a temporary commit. Thanks!
There was a problem hiding this comment.
That's one reason, the other is that it's just a sane default IMHO (because you can't easily debug failures on CI, and I'd imagine most people don't use -vv on CI by default)
There was a problem hiding this comment.
@The-Compiler cool, thanks.
it's just a sane default IMHO (because you can't easily debug failures on CI
This is a good point, but I also agree with @flub that it's quite hidden / implicit behaviour. Do you think it's worth adding --help documentation for this? Or moving it up to config.py and linking it to -vv?
Either way I think this is a separate feature that should be changed (or not) on another branch.
There was a problem hiding this comment.
I don't understand what you mean with "Or moving it up to config.py and linking it to -vv?".
I'm not sure where an explanation would fit. To be honest, I don't think it needs more documentation, just like the truncation in the first place (or that you can use -vv to turn it off) isn't explicitly documented.
|
|
||
| def _truncate_by_char_count(input_lines, max_chars): | ||
| # Check if truncation required | ||
| if len("".join(input_lines)) <= max_chars: |
There was a problem hiding this comment.
This check is not really required because you already did the same check in line 56.
I'm pointing this out because this might be expensive if the output is quite big, although in general I'm sure it won't matter.
An option would be to pass the full text to this function.
There was a problem hiding this comment.
Hey @nicoddemus, the check in 56 is not the same as the check here, because line 61 truncates input_lines to 8 lines, so the total length might have changed.
Do you think this should be restructured? Or is it worth renaming the variables to make it clear that the input_lines arg that gets passed to _truncate_by_char_count() might not be the same as the input_lines that gets passed to _truncate_explanation()?
| ]) | ||
|
|
||
| result = testdir.runpytest('-vv') | ||
| result.stdout.fnmatch_lines([ |
There was a problem hiding this comment.
The output from this runpytest call is:
def test_many_lines():
a = list([str(i)[0] * 100 for i in range(7)])
b = a[::2]
a = '\n'.join(map(str, a))
b = '\n'.join(map(str, b))
> assert a == b
E assert '000000000000...6666666666666' == '0000000000000...6666666666666'
E 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
E - 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
E 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
E - 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
E 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
E - 5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
E 6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
test_full_output_truncated.py:6: AssertionError
========================== 1 failed in 0.01 seconds ===========================
Because "*- 5* will match even when truncating the output as the match above this one show, I think this fnmatch_lines call and the next should match against the 6* line to demonstrate the the output is not being truncated, something like:
result.stdout.fnmatch_lines([
"* 6*",
])There was a problem hiding this comment.
Good shout - have fixed this.
Fix issue with truncation tests for -vv and CI, where the test for non-truncated output would return a positive match even on truncated output.
|
@nicoddemus thanks for the feedback. I've fixed the test issue and replied on the other point. Let me know if you want to make any other changes. |
|
@mattduck thanks for following up. Anybody else wants to review this? |
|
Thanks again @mattduck! |
This addresses ref #1954.
The current truncation logic for assertion explanations does not deal with long lines
properly:
message.
cause index errors if there are < 10 lines.
Extract the truncation logic into its own file and ensure it can deal with
long lines properly.