]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-109179: Fix traceback display for SyntaxErrors with notes (#109197) (#109283)
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Tue, 12 Sep 2023 09:57:28 +0000 (10:57 +0100)
committerGitHub <noreply@github.com>
Tue, 12 Sep 2023 09:57:28 +0000 (09:57 +0000)
gh-109179: Fix traceback display for SyntaxErrors with notes (#109197)

(cherry picked from commit ecd21a629a2a30bcae89902f7cad5670e9441e2c)

Lib/test/test_traceback.py
Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst [new file with mode: 0644]
Python/pythonrun.c

index 544b24c01b37d8aaf354dcf40b562c1976911565..ccc59870c2a9520ee6a147d269166d33327bf35f 100644 (file)
@@ -1546,27 +1546,28 @@ class BaseExceptionReportingTests:
         err_msg = '<note str() failed>'
         self.assertEqual(self.get_report(e), vanilla + err_msg + '\nFinal Note\n')
 
-    def test_exception_with_note_with_multiple_notes(self):
-        e = ValueError(42)
-        vanilla = self.get_report(e)
-
-        e.add_note('Note 1')
-        e.add_note('Note 2')
-        e.add_note('Note 3')
-
-        self.assertEqual(
-            self.get_report(e),
-            vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n')
-
-        del e.__notes__
-        e.add_note('Note 4')
-        del e.__notes__
-        e.add_note('Note 5')
-        e.add_note('Note 6')
-
-        self.assertEqual(
-            self.get_report(e),
-            vanilla + 'Note 5\n' + 'Note 6\n')
+    def test_exception_with_multiple_notes(self):
+        for e in [ValueError(42), SyntaxError('bad syntax')]:
+            with self.subTest(e=e):
+                vanilla = self.get_report(e)
+
+                e.add_note('Note 1')
+                e.add_note('Note 2')
+                e.add_note('Note 3')
+
+                self.assertEqual(
+                    self.get_report(e),
+                    vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n')
+
+                del e.__notes__
+                e.add_note('Note 4')
+                del e.__notes__
+                e.add_note('Note 5')
+                e.add_note('Note 6')
+
+                self.assertEqual(
+                    self.get_report(e),
+                    vanilla + 'Note 5\n' + 'Note 6\n')
 
     def test_exception_qualname(self):
         class A:
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst
new file mode 100644 (file)
index 0000000..dd95a8e
--- /dev/null
@@ -0,0 +1 @@
+Fix bug where the C traceback display drops notes from :exc:`SyntaxError`.
index 03e366a8d095dd829e50385232eb19cb6dafb989..91c2ad3a13d43270b1ebe8f3f487cb55e50428fb 100644 (file)
@@ -1130,21 +1130,16 @@ error:
 }
 
 static int
-print_exception_notes(struct exception_print_context *ctx, PyObject *value)
+print_exception_notes(struct exception_print_context *ctx, PyObject *notes)
 {
     PyObject *f = ctx->file;
 
-    if (!PyExceptionInstance_Check(value)) {
+    if (notes == NULL) {
         return 0;
     }
 
-    PyObject *notes;
-    int res = _PyObject_LookupAttr(value, &_Py_ID(__notes__), &notes);
-    if (res <= 0) {
-        return res;
-    }
     if (!PySequence_Check(notes)) {
-        res = 0;
+        int res = 0;
         if (write_indented_margin(ctx, f) < 0) {
             res = -1;
         }
@@ -1157,7 +1152,6 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value)
             res = PyFile_WriteObject(s, f, Py_PRINT_RAW);
             Py_DECREF(s);
         }
-        Py_DECREF(notes);
         return res;
     }
     Py_ssize_t num_notes = PySequence_Length(notes);
@@ -1199,17 +1193,16 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value)
         }
     }
 
-    Py_DECREF(notes);
     return 0;
 error:
     Py_XDECREF(lines);
-    Py_DECREF(notes);
     return -1;
 }
 
 static int
 print_exception(struct exception_print_context *ctx, PyObject *value)
 {
+    PyObject *notes = NULL;
     PyObject *f = ctx->file;
 
     if (!PyExceptionInstance_Check(value)) {
@@ -1223,8 +1216,11 @@ print_exception(struct exception_print_context *ctx, PyObject *value)
         goto error;
     }
 
-    /* grab the type now because value can change below */
+    /* grab the type and notes now because value can change below */
     PyObject *type = (PyObject *) Py_TYPE(value);
+    if (_PyObject_LookupAttr(value, &_Py_ID(__notes__), &notes) < 0) {
+        goto error;
+    }
 
     if (print_exception_file_and_line(ctx, &value) < 0) {
         goto error;
@@ -1238,14 +1234,16 @@ print_exception(struct exception_print_context *ctx, PyObject *value)
     if (PyFile_WriteString("\n", f) < 0) {
         goto error;
     }
-    if (print_exception_notes(ctx, value) < 0) {
+    if (print_exception_notes(ctx, notes) < 0) {
         goto error;
     }
 
+    Py_XDECREF(notes);
     Py_DECREF(value);
     assert(!PyErr_Occurred());
     return 0;
 error:
+    Py_XDECREF(notes);
     Py_DECREF(value);
     return -1;
 }