8000 gh-109179: Fix traceback display for SyntaxErrors with notes (#109197) · iritkatriel/cpython@2f4dcbc · GitHub
[go: up one dir, main page]

Skip to content

Commit 2f4dcbc

Browse files
committed
pythongh-109179: Fix traceback display for SyntaxErrors with notes (python#109197)
(cherry picked from commit ecd21a6)
1 parent 82a1806 commit 2f4dcbc

File tree

3 files changed

+46
-35
lines changed

3 files changed

+46
-35
lines changed

Lib/test/test_traceback.py

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,27 +1546,36 @@ def __repr__(self):
15461546
err_msg = '<note str() failed>'
15471547
self.assertEqual(self.get_report(e), vanilla + err_msg + '\nFinal Note\n')
15481548

1549-
def test_exception_with_note_with_multiple_notes(self):
1550-
e = ValueError(42)
1551-
vanilla = self.get_report(e)
1552-
1553-
e.add_note('Note 1')
1554-
e.add_note('Note 2')
1555-
e.add_note('Note 3')
1556-
1557-
self.assertEqual(
1558-
self.get_report(e),
1559-
vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n')
1560-
1561-
del e.__notes__
1562-
e.add_note('Note 4')
1563-
del e.__notes__
1564-
e.add_note('Note 5')
1565-
e.add_note('Note 6')
1566-
1567-
self.assertEqual(
1568-
self.get_report(e),
1569-
vanilla + 'Note 5\n' + 'Note 6\n')
1549+
e.__notes__ = "please do not explode me"
1550+
err_msg = "'please do not explode me'"
1551+
self.assertEqual(self.get_report(e), vanilla + err_msg + '\n')
1552+
1553+
e.__notes__ = b"please do not show me as numbers"
1554+
err_msg = "b'please do not show me as numbers'"
1555+
self.assertEqual(self.get_report(e), vanilla + err_msg + '\n')
1556+
1557+
def test_exception_with_multiple_notes(self):
1558+
for e in [ValueError(42), SyntaxError('bad syntax')]:
1559+
with self.subTest(e=e):
1560+
vanilla = self.get_report(e)
1561+
1562+
e.add_note('Note 1')
1563+
e.add_note('Note 2')
1564+
e.add_note('Note 3')
1565+
1566+
self.assertEqual(
1567+
self.get_report(e),
1568+
vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n')
1569+
1570+
del e.__notes__
1571+
e.add_note('Note 4')
1572+
del e.__notes__
1573+
e.add_note('Note 5')
1574+
e.add_note('Note 6')
1575+
1576+
self.assertEqual(
1577+
self.get_report(e),
1578+
vanilla + 'Note 5\n' + 'Note 6\n')
15701579

15711580
def test_exception_qualname(self):
15721581
class A:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix bug where the C traceback display drops notes from :exc:`SyntaxError`.

Python/pythonrun.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,21 +1130,16 @@ print_exception_suggestions(struct exception_print_context *ctx,
11301130
}
11311131

11321132
static int
1133-
print_exception_notes(struct exception_print_context *ctx, PyObject *value)
1133+
print_exception_notes(struct exception_print_context *ctx, PyObject *notes)
11341134
{
11351135
PyObject *f = ctx->file;
11361136

1137-
if (!PyExceptionInstance_Check(value)) {
1137+
if (notes == NULL) {
11381138
return 0;
11391139
}
11401140

1141-
PyObject *notes;
1142-
int res = _PyObject_LookupAttr(value, &_Py_ID(__notes__), &notes);
1143-
if (res <= 0) {
1144-
return res;
1145-
}
1146-
if (!PySequence_Check(notes)) {
1147-
res = 0;
1141+
if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) {
1142+
int res = 0;
11481143
if (write_indented_margin(ctx, f) < 0) {
11491144
res = -1;
11501145
}
@@ -1157,7 +1152,9 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value)
11571152
res = PyFile_WriteObject(s, f, Py_PRINT_RAW);
11581153
Py_DECREF(s);
11591154
}
1160-
Py_DECREF(notes);
1155+
if (PyFile_WriteString("\n", f) < 0) {
1156+
res = -1;
1157+
}
11611158
return res;
11621159
}
11631160
Py_ssize_t num_notes = PySequence_Length(notes);
@@ -1199,17 +1196,16 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value)
11991196
}
12001197
}
12011198

1202-
Py_DECREF(notes);
12031199
return 0;
12041200
error:
12051201
Py_XDECREF(lines);
1206-
Py_DECREF(notes);
12071202
return -1;
12081203
}
12091204

12101205
static int
12111206
print_exception(struct exception_print_context *ctx, PyObject *value)
12121207
{
1208+
PyObject *notes = NULL;
12131209
PyObject *f = ctx->file;
12141210

12151211
if (!PyExceptionInstance_Check(value)) {
@@ -1223,8 +1219,11 @@ print_exception(struct exception_print_context *ctx, PyObject *value)
12231219
goto error;
12241220
}
12251221

1226-
/* grab the type now because value can change below */
1222+
/* grab the type and notes now because value can change below */
12271223
PyObject *type = (PyObject *) Py_TYPE(value);
1224+
if (PyObject_GetOptionalAttr(value, &_Py_ID(__notes__), &notes) < 0) {
1225+
goto error;
1226+
}
12281227

12291228
if (print_exception_file_and_line(ctx, &value) < 0) {
12301229
goto error;
@@ -1238,14 +1237,16 @@ print_exception(struct exception_print_context *ctx, PyObject *value)
12381237
if (PyFile_WriteString("\n", f) < 0) {
12391238
goto error;
12401239
}
1241-
if (print_exception_notes(ctx, value) < 0) {
1240+
if (print_exception_notes(ctx, notes) < 0) {
12421241
goto error;
12431242
}
12441243

1244+
Py_XDECREF(notes);
12451245
Py_DECREF(value);
12461246
assert(!PyErr_Occurred());
12471247
return 0;
12481248
error:
1249+
Py_XDECREF(notes);
12491250
Py_DECREF(value);
12501251
return -1;
12511252
}

0 commit comments

Comments
 (0)
0