From 78fb97105f38dc286353bbc331a243b6e753fe3c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 6 Jan 2021 13:33:33 +0100 Subject: [PATCH 1/2] Make code.FormattedExcinfo.get_source more defensive When line_index was a large negative number, get_source failed on `source.lines[line_index]`. Use the same dummy Source as with a large positive line_index. --- src/_pytest/_code/code.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index b852175606..af3bdf0561 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -721,11 +721,11 @@ def get_source( ) -> List[str]: """Return formatted and marked up source lines.""" lines = [] - if source is None or line_index >= len(source.lines): + if source is not None and line_index < 0: + line_index += len(source.lines) + if source is None or line_index >= len(source.lines) or line_index < 0: source = Source("???") line_index = 0 - if line_index < 0: - line_index += len(source) space_prefix = " " if short: lines.append(space_prefix + source.lines[line_index].strip()) From 0a75c8e57b4b87ee533f3b08612590704b6743bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 22 Apr 2021 19:13:44 +0200 Subject: [PATCH 2/2] Add a regression test for a more defensive code.FormattedExcinfo.get_source --- testing/code/test_excinfo.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index e6a9cbaf73..287733dac7 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -1397,6 +1397,29 @@ def test(tmp_path): result.stderr.no_fnmatch_line("*INTERNALERROR*") +def test_regression_nagative_line_index(pytester): + """ + With Python 3.10 alphas, there was an INTERNALERROR reported in + https://github.com/pytest-dev/pytest/pull/8227 + This test ensures it does not regress. + """ + pytester.makepyfile( + """ + import ast + import pytest + + + def test_literal_eval(): + with pytest.raises(ValueError, match="^$"): + ast.literal_eval("pytest") + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines(["* 1 failed in *"]) + result.stdout.no_fnmatch_line("*INTERNALERROR*") + result.stderr.no_fnmatch_line("*INTERNALERROR*") + + @pytest.mark.usefixtures("limited_recursion_depth") def test_exception_repr_extraction_error_on_recursion(): """