8000 fixup! gh-67224: Show source lines in tracebacks when using the -c op… · python/cpython@88a92a1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 88a92a1

Browse files
committed
fixup! gh-67224: Show source lines in tracebacks when using the -c option when running Python
1 parent e0ebb00 commit 88a92a1

File tree

11 files changed

+89
-46
lines changed

11 files changed

+89
-46
lines changed

Include/internal/pycore_pylifecycle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ extern int _Py_LegacyLocaleDetected(int warn);
114114
// Export for 'readline' shared extension
115115
PyAPI_FUNC(char*) _Py_SetLocaleFromEnv(int category);
116116

117+
// Export for special main.c string compiling with source tracebacks
118+
int _PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags);
119+
117120
#ifdef __cplusplus
118121
}
119122
#endif

Lib/test/test_faulthandler.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
def expected_traceback(lineno1, lineno2, header, min_count=1):
2727
regex = header
28-
regex += ' File "<string>", line %s in func\n' % lineno1
29-
regex += ' File "<string>", line %s in <module>' % lineno2
28+
regex += ' File "<string>-0", line %s in func\n' % lineno1
29+
regex += ' File "<string>-0", line %s in <module>' % lineno2
3030
if 1 < min_count:
3131
return '^' + (regex + '\n') * (min_count - 1) + regex
3232
else:
@@ -114,7 +114,7 @@ def check_error(self, code, lineno, fatal_error, *,
114114
regex.append(fr'{header} \(most recent call first\):')
115115
if garbage_collecting:
116116
regex.append(' Garbage-collecting')
117-
regex.append(fr' File "<string>", line {lineno} in {function}')
117+
regex.append(fr' File "<string>-0", line {lineno} in {function}')
118118
regex = '\n'.join(regex)
119119

120120
if other_regex:
@@ -485,9 +485,9 @@ def funcA():
485485
lineno = 14
486486
expected = [
487487
'Stack (most recent call first):',
488-
' File "<string>", line %s in funcB' % lineno,
489-
' File "<string>", line 17 in funcA',
490-
' File "<string>", line 19 in <module>'
488+
' File "<string>-0", line %s in funcB' % lineno,
489+
' File "<string>-0", line 17 in funcA',
490+
' File "<string>-0", line 19 in <module>'
491491
]
492492
trace, exitcode = self.get_output(code, filename, fd)
493493
self.assertEqual(trace, expected)
@@ -523,8 +523,8 @@ def {func_name}():
523523
)
524524
expected = [
525525
'Stack (most recent call first):',
526-
' File "<string>", line 4 in %s' % truncated,
527-
' File "<string>", line 6 in <module>'
526+
' File "<string>-0", line 4 in %s' % truncated,
527+
' File "<string>-0", line 6 in <module>'
528528
]
529529
trace, exitcode = self.get_output(code)
530530
self.assertEqual(trace, expected)
@@ -577,13 +577,13 @@ def run(self):
577577
regex = r"""
578578
^Thread 0x[0-9a-f]+ \(most recent call first\):
579579
(?: File ".*threading.py", line [0-9]+ in [_a-z]+
580-
){{1,3}} File "<string>", line 23 in run
580+
){{1,3}} File "<string>-0", line 23 in run
581581
File ".*threading.py", line [0-9]+ in _bootstrap_inner
582582
File ".*threading.py", line [0-9]+ in _bootstrap
583583
584584
Current thread 0x[0-9a-f]+ \(most recent call first\):
585-
File "<string>", line {lineno} in dump
586-
File "<string>", line 28 in <module>$
585+
File "<string>-0", line {lineno} in dump
586+
File "<string>-0", line 28 in <module>$
587587
"""
588588
regex = dedent(regex.format(lineno=lineno)).strip()
589589
self.assertRegex(output, regex)

Lib/test/test_io.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4396,11 +4396,11 @@ def test_check_encoding_warning(self):
43964396
''')
43974397
proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code)
43984398
warnings = proc.err.splitlines()
4399-
self.assertEqual(len(warnings), 2)
4399+
self.assertEqual(len(warnings), 4)
44004400
self.assertTrue(
4401-
warnings[0].startswith(b"<string>:5: EncodingWarning: "))
4401+
warnings[0].startswith(b"<string>-0:5: EncodingWarning: "))
44024402
self.assertTrue(
4403-
warnings[1].startswith(b"<string>:8: EncodingWarning: "))
4403+
warnings[2].startswith(b"<string>-0:8: EncodingWarning: "))
44044404

44054405
def test_text_encoding(self):
44064406
# PEP 597, bpo-47000. io.text_encoding() returns "locale" or "utf-8"

Lib/test/test_repl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def bar(x):
184184
p.stdin.write(user_input)
185185
user_input2 = dedent("""
186186
import linecache
187-
print(linecache.cache['<python-input-1>'])
187+
print(linecache.cache['<stdin>-1'])
188188
""")
189189
p.stdin.write(user_input2)
190190
output = kill_python(p)

Lib/test/test_subprocess.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,9 +1769,9 @@ def test_encoding_warning(self):
17691769
cp = subprocess.run([sys.executable, "-Xwarn_default_encoding", "-c", code],
17701770
capture_output=True)
17711771
lines = cp.stderr.splitlines()
1772-
self.assertEqual(len(lines), 2, lines)
1773-
self.assertTrue(lines[0].startswith(b"<string>:2: EncodingWarning: "))
1774-
self.assertTrue(lines[1].startswith(b"<string>:3: EncodingWarning: "))
1772+
self.assertEqual(len(lines), 4, lines)
1773+
self.assertTrue(lines[0].startswith(b"<string>-0:2: EncodingWarning: "))
1774+
self.assertTrue(lines[2].startswith(b"<string>-0:3: EncodingWarning: "))
17751775

17761776

17771777
def _get_test_grp_name():

Lib/test/test_sys.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,14 +1114,18 @@ def check(tracebacklimit, expected):
11141114
traceback = [
11151115
b'Traceback (most recent call last):',
11161116
b' File "<string>", line 8, in <module>',
1117+
b' f2()',
11171118
b' File "<string>", line 6, in f2',
1119+
b' f1()',
11181120
b' File "<string>", line 4, in f1',
1121+
b' 1 / 0',
1122+
b' ~~^~~',
11191123
b'ZeroDivisionError: division by zero'
11201124
]
11211125
check(10, traceback)
11221126
check(3, traceback)
1123-
check(2, traceback[:1] + traceback[2:])
1124-
check(1, traceback[:1] + traceback[3:])
1127+
check(2, traceback[:1] + traceback[3:])
1128+
check(1, traceback[:1] + traceback[5:])
11251129
check(0, [traceback[-1]])
11261130
check(-1, [traceback[-1]])
11271131
check(1<<1000, traceback)

Lib/test/test_traceback.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ def __del__(self):
313313
rc, stdout, stderr = assert_python_ok('-c', code)
314314
expected = [b'Traceback (most recent call last):',
315315
b' File "<string>", line 8, in __init__',
316+
b' x = 1 / 0',
317+
b' ^^^^^',
316318
b'ZeroDivisionError: division by zero']
317319
self.assertEqual(stderr.splitlines(), expected)
318320

Lib/test/test_warnings/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,10 @@ def test_conflicting_envvar_and_command_line(self):
12331233
self.assertEqual(stderr.splitlines(),
12341234
[b"Traceback (most recent call last):",
12351235
b" File \"<string>\", line 1, in <module>",
1236+
b' import sys, warnings; sys.stdout.write(str(sys.warnoptions)); warnings.w'
1237+
b"arn('Message', DeprecationWarning)",
1238+
b' ^^^^^^^^^^'
1239+
b'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^',
12361240
b"DeprecationWarning: Message"])
12371241

12381242
def test_default_filter_configuration(self):
@@ -1353,7 +1357,7 @@ def __del__(self):
13531357
"""
13541358
rc, out, err = assert_python_ok("-c", code)
13551359
self.assertEqual(err.decode().rstrip(),
1356-
'<string>:7: UserWarning: test')
1360+
'<string>-0:7: UserWarning: test')
13571361

13581362
def test_late_resource_warning(self):
13591363
# Issue #21925: Emitting a ResourceWarning late during the Python

Lib/traceback.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -479,12 +479,13 @@ def format_frame_summary(self, frame_summary):
479479
gets called for every frame to be printed in the stack summary.
480480
"""
481481
row = []
482-
if frame_summary.filename.startswith("<python-input"):
483-
row.append(' File "<stdin>", line {}, in {}\n'.format(
484-
frame_summary.lineno, frame_summary.name))
485-
else:
486-
row.append(' File "{}", line {}, in {}\n'.format(
487-
frame_summary.filename, frame_summary.lineno, frame_summary.name))
482+
filename = frame_summary.filename
483+
if frame_summary.filename.startswith("<stdin>-"):
484+
filename = "<stdin>"
485+
elif frame_summary.filename.startswith("<string>-"):
486+
filename = "<string>"
487+
row.append(' File "{}", line {}, in {}\n'.format(
488+
filename, frame_summary.lineno, frame_summary.name))
488489
if frame_summary.line:
489490
stripped_line = frame_summary.line.strip()
490491
row.append(' {}\n'.format(stripped_line))

Modules/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pymain_run_command(wchar_t *command)
249249

250250
PyCompilerFlags cf = _PyCompilerFlags_INIT;
251251
cf.cf_flags |= PyCF_IGNORE_COOKIE;
252-
ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), &cf);
252+
ret = _PyRun_SimpleStringFlagsWithName(PyBytes_AsString(bytes), "<string>", &cf);
253253
Py_DECREF(bytes);
254254
return (ret != 0);
255255

Python/pythonrun.c

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *);
4747
static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start,
4848
PyObject *globals, PyObject *locals, int closeit,
4949
PyCompilerFlags *flags);
50-
50+
static PyObject *
51+
_PyRun_StringFlagsWithName(const char *str, PyObject* name, int start,
52+
PyObject *globals, PyObject *locals, PyCompilerFlags *flags);
5153

5254
int
5355
_PyRun_AnyFileObject(FILE *fp, PyObject *filename, int closeit,
@@ -499,16 +501,25 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
499501

500502

501503
int
502-
PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
503-
{
504+
_PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags) {
504505
PyObject *main_module = PyImport_AddModuleRef("__main__");
505506
if (main_module == NULL) {
506507
return -1;
507508
}
508509
PyObject *dict = PyModule_GetDict(main_module); // borrowed ref
509510

510-
PyObject *res = PyRun_StringFlags(command, Py_file_input,
511-
dict, dict, flags);
511+
PyObject *res = NULL;
512+
if (name == NULL) {
513+
res = PyRun_StringFlags(command, Py_file_input, dict, dict, flags);
514+
} else {
515+
PyObject* the_name = PyUnicode_FromString(name);
516+
if (!the_name) {
517+
PyErr_Print();
518+
return -1;
519+
}
520+
res = _PyRun_StringFlagsWithName(command, the_name, Py_file_input, dict, dict, flags);
521+
Py_DECREF(the_name);
522+
}
512523
Py_DECREF(main_module);
513524
if (res == NULL) {
514525
PyErr_Print();
@@ -519,6 +530,12 @@ PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
519530
return 0;
520531
}
521532

533+
int
534+
PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
535+
{
536+
return _PyRun_SimpleStringFlagsWithName(command, NULL, flags);
537+
}
538+
522539
int
523540
_Py_HandleSystemExit(int *exitcode_p)
524541
{
@@ -1131,9 +1148,9 @@ void PyErr_DisplayException(PyObject *exc)
11311148
PyErr_Display(NULL, exc, NULL);
11321149
}
11331150

1134-
PyObject *
1135-
PyRun_StringFlags(const char *str, int start, PyObject *globals,
1136-
PyObject *locals, PyCompilerFlags *flags)
1151+
static PyObject *
1152+
_PyRun_StringFlagsWithName(const char *str, PyObject* name, int start,
1153+
PyObject *globals, PyObject *locals, PyCompilerFlags *flags)
11371154
{
11381155
PyObject *ret = NULL;
11391156
mod_ty mod;
@@ -1143,24 +1160,36 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals,
11431160
if (arena == NULL)
11441161
return NULL;
11451162

1163+
PyObject* source = NULL;
11461164
_Py_DECLARE_STR(anon_string, "<string>");
1147-
mod = _PyParser_ASTFromString(
1148-
str, &_Py_STR(anon_string), start, flags, arena);
11491165

1150-
PyObject* source = PyUnicode_FromString(str);
1151-
if (!source) {
1152-
goto exit;
1166+
if (name) {
1167+
source = PyUnicode_FromString(str);
1168+
if (!source) {
1169+
PyErr_Clear();
1170+
}
1171+
} else {
1172+
name = &_Py_STR(anon_string);
11531173
}
1154-
if (mod != NULL) {
1155-
ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena, source);
1174+
1175+
mod = _PyParser_ASTFromString(str, name, start, flags, arena);
1176+
1177+
if (mod != NULL) {
1178+
ret = run_mod(mod, name, globals, locals, flags, arena, source);
11561179
}
1157-
Py_DECREF(source);
1158-
exit:
1180+
Py_XDECREF(source);
11591181
_PyArena_Free(arena);
11601182
return ret;
11611183
}
11621184

11631185

1186+
PyObject *
1187+
PyRun_StringFlags(const char *str, int start, PyObject *globals,
1188+
PyObject *locals, PyCompilerFlags *flags) {
1189+
1190+
return _PyRun_StringFlagsWithName(str, NULL, start, globals, locals, flags);
1191+
}
1192+
11641193
static PyObject *
11651194
pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals,
11661195
PyObject *locals, int closeit, PyCompilerFlags *flags)
@@ -1275,7 +1304,7 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
12751304
if (interactive_src) {
12761305
PyInterpreterState *interp = tstate->interp;
12771306
interactive_filename = PyUnicode_FromFormat(
1278-
"<python-input-%d>", interp->_interactive_src_count++
1307+
"%U-%d", filename, interp->_interactive_src_count++
12791308
);
12801309
if (interactive_filename == NULL) {
12811310
return NULL;

0 commit comments

Comments
 (0)
0