Skip to content

Commit 5131b8f

Browse files
adqmEclips4
andauthored
[3.13] gh-137576: Fix for Basic REPL showing incorrect code in tracebacks with PYTHONSTARTUP (GH-137625) (#137778)
(cherry picked from commit 04f8ef6) Co-authored-by: Kirill Podoprigora <[email protected]>
1 parent 785b396 commit 5131b8f

File tree

4 files changed

+90
-3
lines changed

4 files changed

+90
-3
lines changed

Lib/test/test_repl.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,68 @@ def foo(x):
188188
]
189189
self.assertEqual(traceback_lines, expected_lines)
190190

191+
def test_pythonstartup_error_reporting(self):
192+
# errors based on https://github.com/python/cpython/issues/137576
193+
194+
def make_repl(env):
195+
return subprocess.Popen(
196+
[os.path.join(os.path.dirname(sys.executable), '<stdin>'), "-i"],
197+
executable=sys.executable,
198+
text=True,
199+
stdin=subprocess.PIPE,
200+
stdout=subprocess.PIPE,
201+
stderr=subprocess.STDOUT,
202+
env=env,
203+
)
204+
205+
# case 1: error in user input, but PYTHONSTARTUP is fine
206+
with os_helper.temp_dir() as tmpdir:
207+
script = os.path.join(tmpdir, "pythonstartup.py")
208+
with open(script, "w") as f:
209+
f.write("print('from pythonstartup')" + os.linesep)
210+
211+
env = os.environ.copy()
212+
env['PYTHONSTARTUP'] = script
213+
env["PYTHON_HISTORY"] = os.path.join(tmpdir, ".pythonhist")
214+
p = make_repl(env)
215+
p.stdin.write("1/0")
216+
output = kill_python(p)
217+
expected = dedent("""
218+
Traceback (most recent call last):
219+
File "<stdin>", line 1, in <module>
220+
1/0
221+
~^~
222+
ZeroDivisionError: division by zero
223+
""")
224+
self.assertIn("from pythonstartup", output)
225+
self.assertIn(expected, output)
226+
227+
# case 2: error in PYTHONSTARTUP triggered by user input
228+
with os_helper.temp_dir() as tmpdir:
229+
script = os.path.join(tmpdir, "pythonstartup.py")
230+
with open(script, "w") as f:
231+
f.write("def foo():\n 1/0\n")
232+
233+
env = os.environ.copy()
234+
env['PYTHONSTARTUP'] = script
235+
env["PYTHON_HISTORY"] = os.path.join(tmpdir, ".pythonhist")
236+
p = make_repl(env)
237+
p.stdin.write('foo()')
238+
output = kill_python(p)
239+
expected = dedent("""
240+
Traceback (most recent call last):
241+
File "<stdin>", line 1, in <module>
242+
foo()
243+
~~~^^
244+
File "%s", line 2, in foo
245+
1/0
246+
~^~
247+
ZeroDivisionError: division by zero
248+
""") % script
249+
self.assertIn(expected, output)
250+
251+
252+
191253
def test_runsource_show_syntax_error_location(self):
192254
user_input = dedent("""def f(x, x): ...
193255
""")

Lib/traceback.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ def format_frame_summary(self, frame_summary, **kwargs):
528528
colorize = kwargs.get("colorize", False)
529529
row = []
530530
filename = frame_summary.filename
531-
if frame_summary.filename.startswith("<stdin>-"):
531+
if frame_summary.filename.startswith("<stdin-") and frame_summary.filename.endswith('>'):
532532
filename = "<stdin>"
533533
if colorize:
534534
row.append(' File {}"{}"{}, line {}{}{}, in {}{}{}\n'.format(
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix for incorrect source code being shown in tracebacks from the Basic REPL
2+
when :envvar:`PYTHONSTARTUP` is given. Patch by Adam Hartz.

Python/pythonrun.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,29 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py
13851385
return v;
13861386
}
13871387

1388+
static PyObject *
1389+
get_interactive_filename(PyObject *filename, Py_ssize_t count)
1390+
{
1391+
PyObject *result;
1392+
Py_ssize_t len = PyUnicode_GET_LENGTH(filename);
1393+
1394+
if (len >= 2
1395+
&& PyUnicode_ReadChar(filename, 0) == '<'
1396+
&& PyUnicode_ReadChar(filename, len - 1) == '>') {
1397+
PyObject *middle = PyUnicode_Substring(filename, 1, len-1);
1398+
if (middle == NULL) {
1399+
return NULL;
1400+
}
1401+
result = PyUnicode_FromFormat("<%U-%d>", middle, count);
1402+
Py_DECREF(middle);
1403+
} else {
1404+
result = PyUnicode_FromFormat(
1405+
"%U-%d", filename, count);
1406+
}
1407+
return result;
1408+
1409+
}
1410+
13881411
static PyObject *
13891412
run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
13901413
PyCompilerFlags *flags, PyArena *arena, PyObject* interactive_src,
@@ -1395,8 +1418,8 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
13951418
if (interactive_src) {
13961419
PyInterpreterState *interp = tstate->interp;
13971420
if (generate_new_source) {
1398-
interactive_filename = PyUnicode_FromFormat(
1399-
"%U-%d", filename, interp->_interactive_src_count++);
1421+
interactive_filename = get_interactive_filename(
1422+
filename, interp->_interactive_src_count++);
14001423
} else {
14011424
Py_INCREF(interactive_filename);
14021425
}

0 commit comments

Comments
 (0)