diff --git a/AUTHORS b/AUTHORS index 05823646188..1aa5265e62e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -163,6 +163,7 @@ Ionuț Turturică Itxaso Aizpurua Iwan Briquemont Jaap Broekhuizen +Jake VanderPlas Jakob van Santen Jakub Mitoraj James Bourbeau diff --git a/changelog/10840.improvement.rst b/changelog/10840.improvement.rst new file mode 100644 index 00000000000..17be0d07b06 --- /dev/null +++ b/changelog/10840.improvement.rst @@ -0,0 +1 @@ +pytest should no longer crash on AST with pathological position attributes, for example testing AST produced by `Hylang __`. diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index e375fb70c44..032b83beb02 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -743,11 +743,13 @@ 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) + if source is None or line_index >= len(source.lines) or line_index < 0: + # `line_index` could still be outside `range(len(source.lines))` if + # we're processing AST with pathological position attributes. 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 3607501a84e..918c972762b 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -461,6 +461,24 @@ def f(x): assert lines[0] == "| def f(x):" assert lines[1] == " pass" + def test_repr_source_out_of_bounds(self): + pr = FormattedExcinfo() + source = _pytest._code.Source( + """\ + def f(x): + pass + """ + ).strip() + pr.flow_marker = "|" # type: ignore[misc] + + lines = pr.get_source(source, 100) + assert len(lines) == 1 + assert lines[0] == "| ???" + + lines = pr.get_source(source, -100) + assert len(lines) == 1 + assert lines[0] == "| ???" + def test_repr_source_excinfo(self) -> None: """Check if indentation is right.""" try: