mirror of
https://github.com/python/cpython.git
synced 2025-11-24 12:20:42 +00:00
[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:
parent
5caa6cde58
commit
6d30edbae2
4 changed files with 90 additions and 3 deletions
|
|
@ -188,6 +188,68 @@ class TestInteractiveInterpreter(unittest.TestCase):
|
||||||
]
|
]
|
||||||
self.assertEqual(traceback_lines, expected_lines)
|
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):
|
def test_runsource_show_syntax_error_location(self):
|
||||||
user_input = dedent("""def f(x, x): ...
|
user_input = dedent("""def f(x, x): ...
|
||||||
""")
|
""")
|
||||||
|
|
|
||||||
|
|
@ -534,7 +534,7 @@ class StackSummary(list):
|
||||||
colorize = kwargs.get("colorize", False)
|
colorize = kwargs.get("colorize", False)
|
||||||
row = []
|
row = []
|
||||||
filename = frame_summary.filename
|
filename = frame_summary.filename
|
||||||
if frame_summary.filename.startswith("<stdin>-"):
|
if frame_summary.filename.startswith("<stdin-") and frame_summary.filename.endswith('>'):
|
||||||
filename = "<stdin>"
|
filename = "<stdin>"
|
||||||
if colorize:
|
if colorize:
|
||||||
theme = _colorize.get_theme(force_color=True).traceback
|
theme = _colorize.get_theme(force_color=True).traceback
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -1365,6 +1365,29 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py
|
||||||
return PyEval_EvalCode((PyObject*)co, globals, locals);
|
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 *
|
static PyObject *
|
||||||
run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
|
run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
|
||||||
PyCompilerFlags *flags, PyArena *arena, PyObject* interactive_src,
|
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) {
|
if (interactive_src) {
|
||||||
PyInterpreterState *interp = tstate->interp;
|
PyInterpreterState *interp = tstate->interp;
|
||||||
if (generate_new_source) {
|
if (generate_new_source) {
|
||||||
interactive_filename = PyUnicode_FromFormat(
|
interactive_filename = get_interactive_filename(
|
||||||
"%U-%d", filename, interp->_interactive_src_count++);
|
filename, interp->_interactive_src_count++);
|
||||||
} else {
|
} else {
|
||||||
Py_INCREF(interactive_filename);
|
Py_INCREF(interactive_filename);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue