[3.14] gh-137576: Fix for Basic REPL showing incorrect code in tracebacks with PYTHONSTARTUP (GH-137625) (#137771)

Co-authored-by: adam j hartz <hz@mit.edu>
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
This commit is contained in:
Miss Islington (bot) 2025-08-27 17:28:20 +02:00 committed by GitHub
parent 5caa6cde58
commit 6d30edbae2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 90 additions and 3 deletions

View 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): ...
""")

View file

@ -534,7 +534,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

View file

@ -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.

View 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);
}