From 78229ed62070154d0a72cecbb61079066daa4876 Mon Sep 17 00:00:00 2001 From: solaluset <60041069+solaluset@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:54:08 +0200 Subject: [PATCH 1/7] Fix internal error when source is modified --- src/_pytest/_code/source.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index 99c242dd98e..d0a5df4457f 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -216,6 +216,7 @@ def getstatementrange_ast( pass # The end might still point to a comment or empty line, correct it. + end = min(end, len(source.lines)) while end: line = source.lines[end - 1].lstrip() if line.startswith("#") or not line: From 6ac721c70ddbc30f6dc39f0182aa6cdca935f48a Mon Sep 17 00:00:00 2001 From: solaluset <60041069+solaluset@users.noreply.github.com> Date: Sat, 8 Nov 2025 18:45:44 +0200 Subject: [PATCH 2/7] Fix IndexError when retrieving start lineno --- src/_pytest/_code/source.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index d0a5df4457f..cbadf667907 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -168,6 +168,8 @@ def get_statement_startend2(lineno: int, node: ast.AST) -> tuple[int, int | None values.append(val[0].lineno - 1 - 1) values.sort() insert_index = bisect_right(values, lineno) + if insert_index == 0: + return 0, None start = values[insert_index - 1] if insert_index >= len(values): end = None From c4848a445eb075ebee95f7dd8071fe65f41714bd Mon Sep 17 00:00:00 2001 From: solaluset <60041069+solaluset@users.noreply.github.com> Date: Sat, 8 Nov 2025 18:47:31 +0200 Subject: [PATCH 3/7] Add test_patched_compile pytest should not crash when source is dynamically modified --- testing/code/test_source.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/testing/code/test_source.py b/testing/code/test_source.py index e413af3766e..3704687ad75 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -7,6 +7,7 @@ import sys import textwrap from typing import Any +from unittest.mock import patch from _pytest._code import Code from _pytest._code import Frame @@ -647,3 +648,26 @@ def __init__(self, *args): # fmt: on values = [i for i in x.source.lines if i.strip()] assert len(values) == 4 + + +def test_patched_compile() -> None: + # ensure Source doesn't break + # when compile() modifies code dynamically + from builtins import compile + + def patched_compile1(_, *args, **kwargs): + return compile("", *args, **kwargs) + + with patch("builtins.compile", new=patched_compile1): + Source(patched_compile1).getstatement(1) + + # fmt: off + def patched_compile2(_, *args, **kwargs): +# first line of this function must not start with spaces +# LINES must be equal to number of lines of this function + LINES = 4 + return compile("\ndef a():\n" + "\n" * LINES + " pass", *args, **kwargs) + # fmt: on + + with patch("builtins.compile", new=patched_compile2): + Source(patched_compile2).getstatement(1) From 60d4d82dd29062dd0a72814bb468774d9187fb43 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 19:03:12 +0000 Subject: [PATCH 4/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/code/test_source.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/code/test_source.py b/testing/code/test_source.py index 3704687ad75..1afcd906b61 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -663,8 +663,8 @@ def patched_compile1(_, *args, **kwargs): # fmt: off def patched_compile2(_, *args, **kwargs): -# first line of this function must not start with spaces -# LINES must be equal to number of lines of this function + # first line of this function must not start with spaces + # LINES must be equal to number of lines of this function LINES = 4 return compile("\ndef a():\n" + "\n" * LINES + " pass", *args, **kwargs) # fmt: on From 24dd541821363c1f6169b4919fd5a6a5ed4ccede Mon Sep 17 00:00:00 2001 From: solaluset <60041069+solaluset@users.noreply.github.com> Date: Tue, 18 Nov 2025 05:29:41 +0200 Subject: [PATCH 5/7] Fix source IndexError test --- testing/code/test_source.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testing/code/test_source.py b/testing/code/test_source.py index 1afcd906b61..3512a86f9a8 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -663,9 +663,10 @@ def patched_compile1(_, *args, **kwargs): # fmt: off def patched_compile2(_, *args, **kwargs): - # first line of this function must not start with spaces - # LINES must be equal to number of lines of this function - LINES = 4 + + # first line of this function (the one above this one) must be empty + # LINES must be equal or higher than number of lines of this function + LINES = 99 return compile("\ndef a():\n" + "\n" * LINES + " pass", *args, **kwargs) # fmt: on From e422b605c5299c5d8a8f384dcb72ed3b52d76d2f Mon Sep 17 00:00:00 2001 From: solaluset <60041069+solaluset@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:00:42 +0200 Subject: [PATCH 6/7] Add changelog entry for #13884 --- changelog/13884.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/13884.bugfix.rst diff --git a/changelog/13884.bugfix.rst b/changelog/13884.bugfix.rst new file mode 100644 index 00000000000..3f7fb465603 --- /dev/null +++ b/changelog/13884.bugfix.rst @@ -0,0 +1 @@ +Fixed rare internal IndexError caused by `builtins.compile` being overriden in client code. From 59021758e6e4f4894528ca696365ba03f39b2af7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 21:05:54 +0000 Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- changelog/13884.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/13884.bugfix.rst b/changelog/13884.bugfix.rst index 3f7fb465603..af0f08eb00c 100644 --- a/changelog/13884.bugfix.rst +++ b/changelog/13884.bugfix.rst @@ -1 +1 @@ -Fixed rare internal IndexError caused by `builtins.compile` being overriden in client code. +Fixed rare internal IndexError caused by `builtins.compile` being overridden in client code.