]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-137576: Fix for Basic REPL showing incorrect code in tracebacks with `PYTHONSTARTU...
authoradam j hartz <hz@mit.edu>
Thu, 14 Aug 2025 17:58:11 +0000 (13:58 -0400)
committerGitHub <noreply@github.com>
Thu, 14 Aug 2025 17:58:11 +0000 (20:58 +0300)
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
Lib/test/test_repl.py
Lib/traceback.py
Misc/NEWS.d/next/Core_and_Builtins/2025-08-10-21-34-12.gh-issue-137576.0ZicS-.rst [new file with mode: 0644]
Python/pythonrun.c

index f4a4634fc62f8ab581d59e648cea4858291f8829..54e69277282c3016895ee6f2f9b3bbe73b9645a0 100644 (file)
@@ -188,6 +188,68 @@ class TestInteractiveInterpreter(unittest.TestCase):
         ]
         self.assertEqual(traceback_lines, expected_lines)
 
+    def test_pythonstartup_error_reporting(self):
+        # errors based on https://github.com/python/cpython/issues/137576
+
+        def make_repl(env):
+            return subprocess.Popen(
+                [os.path.join(os.path.dirname(sys.executable), '<stdin>'), "-i"],
+                executable=sys.executable,
+                text=True,
+                stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.STDOUT,
+                env=env,
+            )
+
+        # case 1: error in user input, but PYTHONSTARTUP is fine
+        with os_helper.temp_dir() as tmpdir:
+            script = os.path.join(tmpdir, "pythonstartup.py")
+            with open(script, "w") as f:
+                f.write("print('from pythonstartup')" + os.linesep)
+
+            env = os.environ.copy()
+            env['PYTHONSTARTUP'] = script
+            env["PYTHON_HISTORY"] = os.path.join(tmpdir, ".pythonhist")
+            p = make_repl(env)
+            p.stdin.write("1/0")
+            output = kill_python(p)
+        expected = dedent("""
+            Traceback (most recent call last):
+              File "<stdin>", line 1, in <module>
+                1/0
+                ~^~
+            ZeroDivisionError: division by zero
+        """)
+        self.assertIn("from pythonstartup", output)
+        self.assertIn(expected, output)
+
+        # case 2: error in PYTHONSTARTUP triggered by user input
+        with os_helper.temp_dir() as tmpdir:
+            script = os.path.join(tmpdir, "pythonstartup.py")
+            with open(script, "w") as f:
+                f.write("def foo():\n    1/0\n")
+
+            env = os.environ.copy()
+            env['PYTHONSTARTUP'] = script
+            env["PYTHON_HISTORY"] = os.path.join(tmpdir, ".pythonhist")
+            p = make_repl(env)
+            p.stdin.write('foo()')
+            output = kill_python(p)
+        expected = dedent("""
+            Traceback (most recent call last):
+              File "<stdin>", line 1, in <module>
+                foo()
+                ~~~^^
+              File "%s", line 2, in foo
+                1/0
+                ~^~
+            ZeroDivisionError: division by zero
+        """) % script
+        self.assertIn(expected, output)
+
+
+
     def test_runsource_show_syntax_error_location(self):
         user_input = dedent("""def f(x, x): ...
                             """)
index 318ec13cf91121cd9b7e4a1b4661fb9307e3cc8d..1fe295add3a6dd9601db970fb3365cc0760f384e 100644 (file)
@@ -541,7 +541,7 @@ class StackSummary(list):
         colorize = kwargs.get("colorize", False)
         row = []
         filename = frame_summary.filename
-        if frame_summary.filename.startswith("<stdin>-"):
+        if frame_summary.filename.startswith("<stdin-") and frame_summary.filename.endswith('>'):
             filename = "<stdin>"
         if colorize:
             theme = _colorize.get_theme(force_color=True).traceback
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-10-21-34-12.gh-issue-137576.0ZicS-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-10-21-34-12.gh-issue-137576.0ZicS-.rst
new file mode 100644 (file)
index 0000000..19e0f3b
--- /dev/null
@@ -0,0 +1,2 @@
+Fix for incorrect source code being shown in tracebacks from the Basic REPL
+when :envvar:`PYTHONSTARTUP` is given. Patch by Adam Hartz.
index 8f1c78bf831863d5c36cab21d55007f7faefbc2d..45211e1b075042a3d19bc82ad545399ec790730f 100644 (file)
@@ -1365,6 +1365,29 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py
     return PyEval_EvalCode((PyObject*)co, globals, locals);
 }
 
+static PyObject *
+get_interactive_filename(PyObject *filename, Py_ssize_t count)
+{
+    PyObject *result;
+    Py_ssize_t len = PyUnicode_GET_LENGTH(filename);
+
+    if (len >= 2
+            && PyUnicode_ReadChar(filename, 0) == '<'
+            && PyUnicode_ReadChar(filename, len - 1) == '>') {
+        PyObject *middle = PyUnicode_Substring(filename, 1, len-1);
+        if (middle == NULL) {
+            return NULL;
+        }
+        result = PyUnicode_FromFormat("<%U-%d>", middle, count);
+        Py_DECREF(middle);
+    } else {
+        result = PyUnicode_FromFormat(
+            "%U-%d", filename, count);
+    }
+    return result;
+
+}
+
 static PyObject *
 run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
             PyCompilerFlags *flags, PyArena *arena, PyObject* interactive_src,
@@ -1375,8 +1398,8 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
     if (interactive_src) {
         PyInterpreterState *interp = tstate->interp;
         if (generate_new_source) {
-            interactive_filename = PyUnicode_FromFormat(
-                "%U-%d", filename, interp->_interactive_src_count++);
+            interactive_filename = get_interactive_filename(
+                filename, interp->_interactive_src_count++);
         } else {
             Py_INCREF(interactive_filename);
         }