]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-121804: always show error location for SyntaxError's in basic repl (#123202)
authorSergey B Kirpichev <skirpichev@gmail.com>
Tue, 3 Sep 2024 12:37:29 +0000 (15:37 +0300)
committerGitHub <noreply@github.com>
Tue, 3 Sep 2024 12:37:29 +0000 (12:37 +0000)
Lib/test/test_repl.py
Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst [new file with mode: 0644]
Python/pythonrun.c

index 0b938623856e4fa0340fa8654ef29e605df0f4ab..363808cb4443225ada3525d1f2454ee24f870091 100644 (file)
@@ -187,6 +187,19 @@ class TestInteractiveInterpreter(unittest.TestCase):
         ]
         self.assertEqual(traceback_lines, expected_lines)
 
+    def test_runsource_show_syntax_error_location(self):
+        user_input = dedent("""def f(x, x): ...
+                            """)
+        p = spawn_repl()
+        p.stdin.write(user_input)
+        output = kill_python(p)
+        expected_lines = [
+            '    def f(x, x): ...',
+            '             ^',
+            "SyntaxError: duplicate argument 'x' in function definition"
+        ]
+        self.assertEqual(output.splitlines()[4:-1], expected_lines)
+
     def test_interactive_source_is_in_linecache(self):
         user_input = dedent("""
         def foo(x):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst b/Misc/NEWS.d/next/Core and Builtins/2024-08-21-15-22-53.gh-issue-121804.r5K3PS.rst
new file mode 100644 (file)
index 0000000..ce96c31
--- /dev/null
@@ -0,0 +1,2 @@
+Correctly show error locations when a :exc:`SyntaxError` is raised
+in the basic REPL. Patch by Sergey B Kirpichev.
index ce7f194e929c9c9466a86e3397b0dbf69806f07a..b67597113ead45dae8309afe193d3a0755241f1f 100644 (file)
@@ -280,11 +280,42 @@ 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, 1);
+    Py_INCREF(interactive_src);
     _PyArena_Free(arena);
     Py_DECREF(main_module);
     if (res == NULL) {
+        PyThreadState *tstate = _PyThreadState_GET();
+        PyObject *exc = _PyErr_GetRaisedException(tstate);
+        if (PyType_IsSubtype(Py_TYPE(exc),
+                             (PyTypeObject *) PyExc_SyntaxError))
+        {
+            /* fix "text" attribute */
+            assert(interactive_src != NULL);
+            PyObject *xs = PyUnicode_Splitlines(interactive_src, 1);
+            if (xs == NULL) {
+                goto error;
+            }
+            PyObject *exc_lineno = PyObject_GetAttr(exc, &_Py_ID(lineno));
+            if (exc_lineno == NULL) {
+                Py_DECREF(xs);
+                goto error;
+            }
+            int n = PyLong_AsInt(exc_lineno);
+            Py_DECREF(exc_lineno);
+            if (n <= 0 || n > PyList_GET_SIZE(xs)) {
+                Py_DECREF(xs);
+                goto error;
+            }
+            PyObject *line = PyList_GET_ITEM(xs, n - 1);
+            PyObject_SetAttr(exc, &_Py_ID(text), line);
+            Py_DECREF(xs);
+        }
+error:
+        Py_DECREF(interactive_src);
+        _PyErr_SetRaisedException(tstate, exc);
         return -1;
     }
+    Py_DECREF(interactive_src);
     Py_DECREF(res);
 
     flush_io();