diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 5f3226296..992a4d735 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -734,11 +734,11 @@ class FormattedExcinfo: ) -> 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()) diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 11cf3e60e..9cd862ae4 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -1397,6 +1397,29 @@ def test_cwd_deleted(pytester: Pytester) -> None: result.stderr.no_fnmatch_line("*INTERNALERROR*") +def test_regression_nagative_line_index(pytester: Pytester) -> None: + """ + 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(): """