| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -188,6 +188,68 @@ def foo(x): | |||
| 188 | 188 | ] | |
| 189 | 189 | self.assertEqual(traceback_lines, expected_lines) | |
| 190 | 190 | ||
| 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 | + | ||
| 191 | 253 | def test_runsource_show_syntax_error_location(self): | |
| 192 | 254 | user_input = dedent("""def f(x, x): ... | |
| 193 | 255 | """) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -541,7 +541,7 @@ def format_frame_summary(self, frame_summary, **kwargs): | |||
| 541 | 541 | colorize = kwargs.get("colorize", False) | |
| 542 | 542 | row = [] | |
| 543 | 543 | filename = frame_summary.filename | |
| 544 | - if frame_summary.filename.startswith("<stdin>-"): | ||
| 544 | + if frame_summary.filename.startswith("<stdin-") and frame_summary.filename.endswith('>'): | ||
| 545 | 545 | filename = "<stdin>" | |
| 546 | 546 | if colorize: | |
| 547 | 547 | theme = _colorize.get_theme(force_color=True).traceback | |
| Original file line number | Diff line number | Diff 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. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1365,6 +1365,29 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py | |||
| 1365 | 1365 | return PyEval_EvalCode((PyObject*)co, globals, locals); | |
| 1366 | 1366 | } | |
| 1367 | 1367 | ||
| 1368 | + static PyObject * | ||
| 1369 | + get_interactive_filename(PyObject *filename, Py_ssize_t count) | ||
| 1370 | + { | ||
| 1371 | + PyObject *result; | ||
| 1372 | + Py_ssize_t len = PyUnicode_GET_LENGTH(filename); | ||
| 1373 | + | ||
| 1374 | + if (len >= 2 | ||
| 1375 | + && PyUnicode_ReadChar(filename, 0) == '<' | ||
| 1376 | + && PyUnicode_ReadChar(filename, len - 1) == '>') { | ||
| 1377 | + PyObject *middle = PyUnicode_Substring(filename, 1, len-1); | ||
| 1378 | + if (middle == NULL) { | ||
| 1379 | + return NULL; | ||
| 1380 | + } | ||
| 1381 | + result = PyUnicode_FromFormat("<%U-%d>", middle, count); | ||
| 1382 | + Py_DECREF(middle); | ||
| 1383 | + } else { | ||
| 1384 | + result = PyUnicode_FromFormat( | ||
| 1385 | + "%U-%d", filename, count); | ||
| 1386 | + } | ||
| 1387 | + return result; | ||
| 1388 | + | ||
| 1389 | + } | ||
| 1390 | + | ||
| 1368 | 1391 | static PyObject * | |
| 1369 | 1392 | run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, | |
| 1370 | 1393 | PyCompilerFlags *flags, PyArena *arena, PyObject* interactive_src, | |
@@ -1375,8 +1398,8 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, | |||
| 1375 | 1398 | if (interactive_src) { | |
| 1376 | 1399 | PyInterpreterState *interp = tstate->interp; | |
| 1377 | 1400 | if (generate_new_source) { | |
| 1378 | - interactive_filename = PyUnicode_FromFormat( | ||
| 1379 | - "%U-%d", filename, interp->_interactive_src_count++); | ||
| 1401 | + interactive_filename = get_interactive_filename( | ||
| 1402 | + filename, interp->_interactive_src_count++); | ||
| 1380 | 1403 | } else { | |
| 1381 | 1404 | Py_INCREF(interactive_filename); | |
| 1382 | 1405 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments