From e0ebb0002f72dfdaea33b29c955b3b71958d7e24 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Mon, 23 Oct 2023 13:42:50 +0900 Subject: [PATCH 1/4] gh-67224: Show source lines in tracebacks when using the -c option when running Python Signed-off-by: Pablo Galindo --- Lib/linecache.py | 8 +++++--- Lib/test/test_cmd_line_script.py | 10 ++++++++++ .../2023-10-23-15-44-47.gh-issue-67224.S4D6CR.rst | 2 ++ Python/pythonrun.c | 11 +++++++++-- 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-23-15-44-47.gh-issue-67224.S4D6CR.rst diff --git a/Lib/linecache.py b/Lib/linecache.py index c1c988d9df436c..329a14053458b7 100644 --- a/Lib/linecache.py +++ b/Lib/linecache.py @@ -5,10 +5,8 @@ that name. """ -import functools import sys import os -import tokenize __all__ = ["getline", "clearcache", "checkcache", "lazycache"] @@ -82,6 +80,8 @@ def updatecache(filename, module_globals=None): If something's wrong, print a message, discard the cache entry, and return an empty list.""" + import tokenize + if filename in cache: if len(cache[filename]) != 1: cache.pop(filename, None) @@ -176,11 +176,13 @@ def lazycache(filename, module_globals): get_source = getattr(loader, 'get_source', None) if name and get_source: - get_lines = functools.partial(get_source, name) + def get_lines(name=name, *args, **kwargs): + return get_source(name, *args, **kwargs) cache[filename] = (get_lines,) return True return False + def _register_code(code, string, name): cache[code] = ( len(string), diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 614c6b3c3b5299..83ef2d2cf65969 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -683,6 +683,16 @@ def test_syntaxerror_null_bytes_in_multiline_string(self): b'SyntaxError: source code cannot contain null bytes' ] ) + + def test_source_lines_are_shown_when_running_source(self): + _, _, stderr = assert_python_failure("-c", "1/0") + expected_lines = [ + b'Traceback (most recent call last):', + b' File "", line 1, in ', + b' 1/0', + b' ~^~', + b'ZeroDivisionError: division by zero'] + self.assertEqual(stderr.splitlines(), expected_lines) def test_consistent_sys_path_for_direct_execution(self): # This test case ensures that the following all give the same diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-23-15-44-47.gh-issue-67224.S4D6CR.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-23-15-44-47.gh-issue-67224.S4D6CR.rst new file mode 100644 index 00000000000000..b0474f38cff6f6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-23-15-44-47.gh-issue-67224.S4D6CR.rst @@ -0,0 +1,2 @@ +Show source lines in tracebacks when using the ``-c`` option when running +Python. Patch by Pablo Galindo diff --git a/Python/pythonrun.c b/Python/pythonrun.c index b915c063d0b456..2382ec6a14fe00 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1147,8 +1147,15 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals, mod = _PyParser_ASTFromString( str, &_Py_STR(anon_string), start, flags, arena); - if (mod != NULL) - ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena, NULL); + PyObject* source = PyUnicode_FromString(str); + if (!source) { + goto exit; + } + if (mod != NULL) { + ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena, source); + } + Py_DECREF(source); +exit: _PyArena_Free(arena); return ret; } From 88a92a1465e8cece151c8faef512ff559597174e Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 24 Oct 2023 17:20:17 +0900 Subject: [PATCH 2/4] fixup! gh-67224: Show source lines in tracebacks when using the -c option when running Python --- Include/internal/pycore_pylifecycle.h | 3 ++ Lib/test/test_faulthandler.py | 22 ++++----- Lib/test/test_io.py | 6 +-- Lib/test/test_repl.py | 2 +- Lib/test/test_subprocess.py | 6 +-- Lib/test/test_sys.py | 8 +++- Lib/test/test_traceback.py | 2 + Lib/test/test_warnings/__init__.py | 6 ++- Lib/traceback.py | 13 +++--- Modules/main.c | 2 +- Python/pythonrun.c | 65 +++++++++++++++++++-------- 11 files changed, 89 insertions(+), 46 deletions(-) diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index ec003a1dad2595..61e0150e89009c 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -114,6 +114,9 @@ extern int _Py_LegacyLocaleDetected(int warn); // Export for 'readline' shared extension PyAPI_FUNC(char*) _Py_SetLocaleFromEnv(int category); +// Export for special main.c string compiling with source tracebacks +int _PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags); + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index d0473500a17735..db3367c5ca078e 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -25,8 +25,8 @@ def expected_traceback(lineno1, lineno2, header, min_count=1): regex = header - regex += ' File "", line %s in func\n' % lineno1 - regex += ' File "", line %s in ' % lineno2 + regex += ' File "-0", line %s in func\n' % lineno1 + regex += ' File "-0", line %s in ' % lineno2 if 1 < min_count: return '^' + (regex + '\n') * (min_count - 1) + regex else: @@ -114,7 +114,7 @@ def check_error(self, code, lineno, fatal_error, *, regex.append(fr'{header} \(most recent call first\):') if garbage_collecting: regex.append(' Garbage-collecting') - regex.append(fr' File "", line {lineno} in {function}') + regex.append(fr' File "-0", line {lineno} in {function}') regex = '\n'.join(regex) if other_regex: @@ -485,9 +485,9 @@ def funcA(): lineno = 14 expected = [ 'Stack (most recent call first):', - ' File "", line %s in funcB' % lineno, - ' File "", line 17 in funcA', - ' File "", line 19 in ' + ' File "-0", line %s in funcB' % lineno, + ' File "-0", line 17 in funcA', + ' File "-0", line 19 in ' ] trace, exitcode = self.get_output(code, filename, fd) self.assertEqual(trace, expected) @@ -523,8 +523,8 @@ def {func_name}(): ) expected = [ 'Stack (most recent call first):', - ' File "", line 4 in %s' % truncated, - ' File "", line 6 in ' + ' File "-0", line 4 in %s' % truncated, + ' File "-0", line 6 in ' ] trace, exitcode = self.get_output(code) self.assertEqual(trace, expected) @@ -577,13 +577,13 @@ def run(self): regex = r""" ^Thread 0x[0-9a-f]+ \(most recent call first\): (?: File ".*threading.py", line [0-9]+ in [_a-z]+ - ){{1,3}} File "", line 23 in run + ){{1,3}} File "-0", line 23 in run File ".*threading.py", line [0-9]+ in _bootstrap_inner File ".*threading.py", line [0-9]+ in _bootstrap Current thread 0x[0-9a-f]+ \(most recent call first\): - File "", line {lineno} in dump - File "", line 28 in $ + File "-0", line {lineno} in dump + File "-0", line 28 in $ """ regex = dedent(regex.format(lineno=lineno)).strip() self.assertRegex(output, regex) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 022cf21a4709a2..53a805562a6356 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4396,11 +4396,11 @@ def test_check_encoding_warning(self): ''') proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code) warnings = proc.err.splitlines() - self.assertEqual(len(warnings), 2) + self.assertEqual(len(warnings), 4) self.assertTrue( - warnings[0].startswith(b":5: EncodingWarning: ")) + warnings[0].startswith(b"-0:5: EncodingWarning: ")) self.assertTrue( - warnings[1].startswith(b":8: EncodingWarning: ")) + warnings[2].startswith(b"-0:8: EncodingWarning: ")) def test_text_encoding(self): # PEP 597, bpo-47000. io.text_encoding() returns "locale" or "utf-8" diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 2ee5117bcd7bd4..7533376e015e73 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -184,7 +184,7 @@ def bar(x): p.stdin.write(user_input) user_input2 = dedent(""" import linecache - print(linecache.cache['']) + print(linecache.cache['-1']) """) p.stdin.write(user_input2) output = kill_python(p) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index a865df1082fba3..3acb95682333b0 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1769,9 +1769,9 @@ def test_encoding_warning(self): cp = subprocess.run([sys.executable, "-Xwarn_default_encoding", "-c", code], capture_output=True) lines = cp.stderr.splitlines() - self.assertEqual(len(lines), 2, lines) - self.assertTrue(lines[0].startswith(b":2: EncodingWarning: ")) - self.assertTrue(lines[1].startswith(b":3: EncodingWarning: ")) + self.assertEqual(len(lines), 4, lines) + self.assertTrue(lines[0].startswith(b"-0:2: EncodingWarning: ")) + self.assertTrue(lines[2].startswith(b"-0:3: EncodingWarning: ")) def _get_test_grp_name(): diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index da213506151594..b16e1e7f70a24a 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1114,14 +1114,18 @@ def check(tracebacklimit, expected): traceback = [ b'Traceback (most recent call last):', b' File "", line 8, in ', + b' f2()', b' File "", line 6, in f2', + b' f1()', b' File "", line 4, in f1', + b' 1 / 0', + b' ~~^~~', b'ZeroDivisionError: division by zero' ] check(10, traceback) check(3, traceback) - check(2, traceback[:1] + traceback[2:]) - check(1, traceback[:1] + traceback[3:]) + check(2, traceback[:1] + traceback[3:]) + check(1, traceback[:1] + traceback[5:]) check(0, [traceback[-1]]) check(-1, [traceback[-1]]) check(1<<1000, traceback) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index a0f7ad81bd540d..f76fcd4c443c5d 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -313,6 +313,8 @@ def __del__(self): rc, stdout, stderr = assert_python_ok('-c', code) expected = [b'Traceback (most recent call last):', b' File "", line 8, in __init__', + b' x = 1 / 0', + b' ^^^^^', b'ZeroDivisionError: division by zero'] self.assertEqual(stderr.splitlines(), expected) diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 83237f5fe0d1b3..0e8d7452cdcc16 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1233,6 +1233,10 @@ def test_conflicting_envvar_and_command_line(self): self.assertEqual(stderr.splitlines(), [b"Traceback (most recent call last):", b" File \"\", line 1, in ", + b' import sys, warnings; sys.stdout.write(str(sys.warnoptions)); warnings.w' + b"arn('Message', DeprecationWarning)", + b' ^^^^^^^^^^' + b'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^', b"DeprecationWarning: Message"]) def test_default_filter_configuration(self): @@ -1353,7 +1357,7 @@ def __del__(self): """ rc, out, err = assert_python_ok("-c", code) self.assertEqual(err.decode().rstrip(), - ':7: UserWarning: test') + '-0:7: UserWarning: test') def test_late_resource_warning(self): # Issue #21925: Emitting a ResourceWarning late during the Python diff --git a/Lib/traceback.py b/Lib/traceback.py index 7cc84b9c762aeb..58f2bf8cb47227 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -479,12 +479,13 @@ def format_frame_summary(self, frame_summary): gets called for every frame to be printed in the stack summary. """ row = [] - if frame_summary.filename.startswith("", line {}, in {}\n'.format( - frame_summary.lineno, frame_summary.name)) - else: - row.append(' File "{}", line {}, in {}\n'.format( - frame_summary.filename, frame_summary.lineno, frame_summary.name)) + filename = frame_summary.filename + if frame_summary.filename.startswith("-"): + filename = "" + elif frame_summary.filename.startswith("-"): + filename = "" + row.append(' File "{}", line {}, in {}\n'.format( + filename, frame_summary.lineno, frame_summary.name)) if frame_summary.line: stripped_line = frame_summary.line.strip() row.append(' {}\n'.format(stripped_line)) diff --git a/Modules/main.c b/Modules/main.c index b5ee34d0141daf..df2ce550245088 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -249,7 +249,7 @@ pymain_run_command(wchar_t *command) PyCompilerFlags cf = _PyCompilerFlags_INIT; cf.cf_flags |= PyCF_IGNORE_COOKIE; - ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), &cf); + ret = _PyRun_SimpleStringFlagsWithName(PyBytes_AsString(bytes), "", &cf); Py_DECREF(bytes); return (ret != 0); diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 2382ec6a14fe00..bbfa0e351eda77 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -47,7 +47,9 @@ static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags); - +static PyObject * +_PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, + PyObject *globals, PyObject *locals, PyCompilerFlags *flags); int _PyRun_AnyFileObject(FILE *fp, PyObject *filename, int closeit, @@ -499,16 +501,25 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, int -PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) -{ +_PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags) { PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { return -1; } PyObject *dict = PyModule_GetDict(main_module); // borrowed ref - PyObject *res = PyRun_StringFlags(command, Py_file_input, - dict, dict, flags); + PyObject *res = NULL; + if (name == NULL) { + res = PyRun_StringFlags(command, Py_file_input, dict, dict, flags); + } else { + PyObject* the_name = PyUnicode_FromString(name); + if (!the_name) { + PyErr_Print(); + return -1; + } + res = _PyRun_StringFlagsWithName(command, the_name, Py_file_input, dict, dict, flags); + Py_DECREF(the_name); + } Py_DECREF(main_module); if (res == NULL) { PyErr_Print(); @@ -519,6 +530,12 @@ PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) return 0; } +int +PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) +{ + return _PyRun_SimpleStringFlagsWithName(command, NULL, flags); +} + int _Py_HandleSystemExit(int *exitcode_p) { @@ -1131,9 +1148,9 @@ void PyErr_DisplayException(PyObject *exc) PyErr_Display(NULL, exc, NULL); } -PyObject * -PyRun_StringFlags(const char *str, int start, PyObject *globals, - PyObject *locals, PyCompilerFlags *flags) +static PyObject * +_PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, + PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { PyObject *ret = NULL; mod_ty mod; @@ -1143,24 +1160,36 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals, if (arena == NULL) return NULL; + PyObject* source = NULL; _Py_DECLARE_STR(anon_string, ""); - mod = _PyParser_ASTFromString( - str, &_Py_STR(anon_string), start, flags, arena); - PyObject* source = PyUnicode_FromString(str); - if (!source) { - goto exit; + if (name) { + source = PyUnicode_FromString(str); + if (!source) { + PyErr_Clear(); + } + } else { + name = &_Py_STR(anon_string); } - if (mod != NULL) { - ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena, source); + + mod = _PyParser_ASTFromString(str, name, start, flags, arena); + + if (mod != NULL) { + ret = run_mod(mod, name, globals, locals, flags, arena, source); } - Py_DECREF(source); -exit: + Py_XDECREF(source); _PyArena_Free(arena); return ret; } +PyObject * +PyRun_StringFlags(const char *str, int start, PyObject *globals, + PyObject *locals, PyCompilerFlags *flags) { + + return _PyRun_StringFlagsWithName(str, NULL, start, globals, locals, flags); +} + static PyObject * pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags) @@ -1275,7 +1304,7 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, if (interactive_src) { PyInterpreterState *interp = tstate->interp; interactive_filename = PyUnicode_FromFormat( - "", interp->_interactive_src_count++ + "%U-%d", filename, interp->_interactive_src_count++ ); if (interactive_filename == NULL) { return NULL; From 5a83c3d293c8567882ad023b66a3873ba1971ada Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 24 Oct 2023 17:27:01 +0900 Subject: [PATCH 3/4] fixup! fixup! gh-67224: Show source lines in tracebacks when using the -c option when running Python --- Lib/test/test_cmd_line_script.py | 2 +- Lib/test/test_traceback.py | 2 +- Python/pythonrun.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 83ef2d2cf65969..385394a48191ef 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -683,7 +683,7 @@ def test_syntaxerror_null_bytes_in_multiline_string(self): b'SyntaxError: source code cannot contain null bytes' ] ) - + def test_source_lines_are_shown_when_running_source(self): _, _, stderr = assert_python_failure("-c", "1/0") expected_lines = [ diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index f76fcd4c443c5d..43f15ab6179beb 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -314,7 +314,7 @@ def __del__(self): expected = [b'Traceback (most recent call last):', b' File "", line 8, in __init__', b' x = 1 / 0', - b' ^^^^^', + b' ^^^^^', b'ZeroDivisionError: division by zero'] self.assertEqual(stderr.splitlines(), expected) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index bbfa0e351eda77..519a922d30c8c4 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1171,7 +1171,7 @@ _PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, } else { name = &_Py_STR(anon_string); } - + mod = _PyParser_ASTFromString(str, name, start, flags, arena); if (mod != NULL) { From 7c04b729e4c256513736165e10f622c22883fba5 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 25 Oct 2023 15:14:42 +0900 Subject: [PATCH 4/4] fixup! fixup! fixup! gh-67224: Show source lines in tracebacks when using the -c option when running Python --- Lib/test/test_cmd_line_script.py | 2 +- Lib/test/test_faulthandler.py | 22 +++++++++++----------- Lib/test/test_io.py | 4 ++-- Lib/test/test_subprocess.py | 4 ++-- Lib/test/test_warnings/__init__.py | 2 +- Lib/traceback.py | 2 -- Python/pythonrun.c | 30 ++++++++++++++++++------------ 7 files changed, 35 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 385394a48191ef..1c9dedaec20a23 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -688,7 +688,7 @@ def test_source_lines_are_shown_when_running_source(self): _, _, stderr = assert_python_failure("-c", "1/0") expected_lines = [ b'Traceback (most recent call last):', - b' File "", line 1, in ', + b' File "", line 1, in ', b' 1/0', b' ~^~', b'ZeroDivisionError: division by zero'] diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index db3367c5ca078e..d0473500a17735 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -25,8 +25,8 @@ def expected_traceback(lineno1, lineno2, header, min_count=1): regex = header - regex += ' File "-0", line %s in func\n' % lineno1 - regex += ' File "-0", line %s in ' % lineno2 + regex += ' File "", line %s in func\n' % lineno1 + regex += ' File "", line %s in ' % lineno2 if 1 < min_count: return '^' + (regex + '\n') * (min_count - 1) + regex else: @@ -114,7 +114,7 @@ def check_error(self, code, lineno, fatal_error, *, regex.append(fr'{header} \(most recent call first\):') if garbage_collecting: regex.append(' Garbage-collecting') - regex.append(fr' File "-0", line {lineno} in {function}') + regex.append(fr' File "", line {lineno} in {function}') regex = '\n'.join(regex) if other_regex: @@ -485,9 +485,9 @@ def funcA(): lineno = 14 expected = [ 'Stack (most recent call first):', - ' File "-0", line %s in funcB' % lineno, - ' File "-0", line 17 in funcA', - ' File "-0", line 19 in ' + ' File "", line %s in funcB' % lineno, + ' File "", line 17 in funcA', + ' File "", line 19 in ' ] trace, exitcode = self.get_output(code, filename, fd) self.assertEqual(trace, expected) @@ -523,8 +523,8 @@ def {func_name}(): ) expected = [ 'Stack (most recent call first):', - ' File "-0", line 4 in %s' % truncated, - ' File "-0", line 6 in ' + ' File "", line 4 in %s' % truncated, + ' File "", line 6 in ' ] trace, exitcode = self.get_output(code) self.assertEqual(trace, expected) @@ -577,13 +577,13 @@ def run(self): regex = r""" ^Thread 0x[0-9a-f]+ \(most recent call first\): (?: File ".*threading.py", line [0-9]+ in [_a-z]+ - ){{1,3}} File "-0", line 23 in run + ){{1,3}} File "", line 23 in run File ".*threading.py", line [0-9]+ in _bootstrap_inner File ".*threading.py", line [0-9]+ in _bootstrap Current thread 0x[0-9a-f]+ \(most recent call first\): - File "-0", line {lineno} in dump - File "-0", line 28 in $ + File "", line {lineno} in dump + File "", line 28 in $ """ regex = dedent(regex.format(lineno=lineno)).strip() self.assertRegex(output, regex) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 53a805562a6356..4c80429684e525 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4398,9 +4398,9 @@ def test_check_encoding_warning(self): warnings = proc.err.splitlines() self.assertEqual(len(warnings), 4) self.assertTrue( - warnings[0].startswith(b"-0:5: EncodingWarning: ")) + warnings[0].startswith(b":5: EncodingWarning: ")) self.assertTrue( - warnings[2].startswith(b"-0:8: EncodingWarning: ")) + warnings[2].startswith(b":8: EncodingWarning: ")) def test_text_encoding(self): # PEP 597, bpo-47000. io.text_encoding() returns "locale" or "utf-8" diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3acb95682333b0..fe1a3675fced65 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1770,8 +1770,8 @@ def test_encoding_warning(self): capture_output=True) lines = cp.stderr.splitlines() self.assertEqual(len(lines), 4, lines) - self.assertTrue(lines[0].startswith(b"-0:2: EncodingWarning: ")) - self.assertTrue(lines[2].startswith(b"-0:3: EncodingWarning: ")) + self.assertTrue(lines[0].startswith(b":2: EncodingWarning: ")) + self.assertTrue(lines[2].startswith(b":3: EncodingWarning: ")) def _get_test_grp_name(): diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 0e8d7452cdcc16..2c523230e7e97f 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1357,7 +1357,7 @@ def __del__(self): """ rc, out, err = assert_python_ok("-c", code) self.assertEqual(err.decode().rstrip(), - '-0:7: UserWarning: test') + ':7: UserWarning: test') def test_late_resource_warning(self): # Issue #21925: Emitting a ResourceWarning late during the Python diff --git a/Lib/traceback.py b/Lib/traceback.py index 58f2bf8cb47227..a7984dbc0f91a4 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -482,8 +482,6 @@ def format_frame_summary(self, frame_summary): filename = frame_summary.filename if frame_summary.filename.startswith("-"): filename = "" - elif frame_summary.filename.startswith("-"): - filename = "" row.append(' File "{}", line {}, in {}\n'.format( filename, frame_summary.lineno, frame_summary.name)) if frame_summary.line: diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 519a922d30c8c4..8fe05ef4677cc5 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -40,7 +40,7 @@ /* Forward */ static void flush_io(void); static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, - PyCompilerFlags *, PyArena *, PyObject*); + PyCompilerFlags *, PyArena *, PyObject*, int); static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *, PyCompilerFlags *); static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); @@ -49,7 +49,8 @@ static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, PyCompilerFlags *flags); static PyObject * _PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, - PyObject *globals, PyObject *locals, PyCompilerFlags *flags); + PyObject *globals, PyObject *locals, PyCompilerFlags *flags, + int generate_new_source); int _PyRun_AnyFileObject(FILE *fp, PyObject *filename, int closeit, @@ -283,7 +284,7 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, } PyObject *main_dict = PyModule_GetDict(main_module); // borrowed ref - PyObject *res = run_mod(mod, filename, main_dict, main_dict, flags, arena, interactive_src); + PyObject *res = run_mod(mod, filename, main_dict, main_dict, flags, arena, interactive_src, 1); _PyArena_Free(arena); Py_DECREF(main_module); if (res == NULL) { @@ -517,7 +518,7 @@ _PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompil PyErr_Print(); return -1; } - res = _PyRun_StringFlagsWithName(command, the_name, Py_file_input, dict, dict, flags); + res = _PyRun_StringFlagsWithName(command, the_name, Py_file_input, dict, dict, flags, 0); Py_DECREF(the_name); } Py_DECREF(main_module); @@ -1150,7 +1151,8 @@ void PyErr_DisplayException(PyObject *exc) static PyObject * _PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, - PyObject *globals, PyObject *locals, PyCompilerFlags *flags) + PyObject *globals, PyObject *locals, PyCompilerFlags *flags, + int generate_new_source) { PyObject *ret = NULL; mod_ty mod; @@ -1175,7 +1177,7 @@ _PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, mod = _PyParser_ASTFromString(str, name, start, flags, arena); if (mod != NULL) { - ret = run_mod(mod, name, globals, locals, flags, arena, source); + ret = run_mod(mod, name, globals, locals, flags, arena, source, generate_new_source); } Py_XDECREF(source); _PyArena_Free(arena); @@ -1187,7 +1189,7 @@ PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { - return _PyRun_StringFlagsWithName(str, NULL, start, globals, locals, flags); + return _PyRun_StringFlagsWithName(str, NULL, start, globals, locals, flags, 0); } static PyObject * @@ -1209,7 +1211,7 @@ pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *ret; if (mod != NULL) { - ret = run_mod(mod, filename, globals, locals, flags, arena, NULL); + ret = run_mod(mod, filename, globals, locals, flags, arena, NULL, 0); } else { ret = NULL; @@ -1297,15 +1299,19 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py static PyObject * 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, + int generate_new_source) { PyThreadState *tstate = _PyThreadState_GET(); PyObject* interactive_filename = filename; if (interactive_src) { PyInterpreterState *interp = tstate->interp; - interactive_filename = PyUnicode_FromFormat( - "%U-%d", filename, interp->_interactive_src_count++ - ); + if (generate_new_source) { + interactive_filename = PyUnicode_FromFormat( + "%U-%d", filename, interp->_interactive_src_count++); + } else { + Py_INCREF(interactive_filename); + } if (interactive_filename == NULL) { return NULL; }