[Python-checkins] gh-103895: Improve how invalid `Exception.__notes__` are displayed (#103897)

iritkatriel webhook-mailer at python.org
Mon May 1 03:32:36 EDT 2023


https://github.com/python/cpython/commit/487f55d5801a9ae7d79d37e259e8c377c9acd39b
commit: 487f55d5801a9ae7d79d37e259e8c377c9acd39b
branch: main
author: Carey Metcalfe <carey at cmetcalfe.ca>
committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com>
date: 2023-05-01T08:32:04+01:00
summary:

gh-103895: Improve how invalid `Exception.__notes__` are displayed (#103897)

files:
A Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst
M Lib/test/test_traceback.py
M Lib/traceback.py
M Python/pythonrun.c

diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index 5e2b35378299..19a2be88d2c1 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -1539,11 +1539,11 @@ def __repr__(self):
 
         e.__notes__ = BadThing()
         notes_repr = 'bad repr'
-        self.assertEqual(self.get_report(e), vanilla + notes_repr)
+        self.assertEqual(self.get_report(e), vanilla + notes_repr + '\n')
 
         e.__notes__ = Unprintable()
         err_msg = '<__notes__ repr() failed>'
-        self.assertEqual(self.get_report(e), vanilla + err_msg)
+        self.assertEqual(self.get_report(e), vanilla + err_msg + '\n')
 
         # non-string item in the __notes__ sequence
         e.__notes__  = [BadThing(), 'Final Note']
@@ -1555,6 +1555,14 @@ def __repr__(self):
         err_msg = '<note str() failed>'
         self.assertEqual(self.get_report(e), vanilla + err_msg + '\nFinal Note\n')
 
+        e.__notes__  = "please do not explode me"
+        err_msg = "'please do not explode me'"
+        self.assertEqual(self.get_report(e), vanilla + err_msg + '\n')
+
+        e.__notes__  = b"please do not show me as numbers"
+        err_msg = "b'please do not show me as numbers'"
+        self.assertEqual(self.get_report(e), vanilla + err_msg + '\n')
+
     def test_exception_with_note_with_multiple_notes(self):
         e = ValueError(42)
         vanilla = self.get_report(e)
diff --git a/Lib/traceback.py b/Lib/traceback.py
index 9e720ac9948f..ba4a9ffd001b 100644
--- a/Lib/traceback.py
+++ b/Lib/traceback.py
@@ -852,12 +852,16 @@ def format_exception_only(self):
             yield _format_final_exc_line(stype, self._str)
         else:
             yield from self._format_syntax_error(stype)
-        if isinstance(self.__notes__, collections.abc.Sequence):
+
+        if (
+            isinstance(self.__notes__, collections.abc.Sequence)
+            and not isinstance(self.__notes__, (str, bytes))
+        ):
             for note in self.__notes__:
                 note = _safe_string(note, 'note')
                 yield from [l + '\n' for l in note.split('\n')]
         elif self.__notes__ is not None:
-            yield _safe_string(self.__notes__, '__notes__', func=repr)
+            yield "{}\n".format(_safe_string(self.__notes__, '__notes__', func=repr))
 
     def _format_syntax_error(self, stype):
         """Format SyntaxError exceptions (internal helper)."""
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst
new file mode 100644
index 000000000000..6fed304c9132
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst	
@@ -0,0 +1,3 @@
+Improve handling of edge cases in showing ``Exception.__notes__``. Ensures
+that the messages always end with a newline and that string/bytes are not
+exploded over multiple lines. Patch by Carey Metcalfe.
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index b16d3f53f89f..05e7b4370869 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -1107,7 +1107,7 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value)
     if (notes == NULL) {
         return -1;
     }
-    if (!PySequence_Check(notes)) {
+    if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) {
         int res = 0;
         if (write_indented_margin(ctx, f) < 0) {
             res = -1;
@@ -1122,6 +1122,9 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value)
             Py_DECREF(s);
         }
         Py_DECREF(notes);
+        if (PyFile_WriteString("\n", f) < 0) {
+            res = -1;
+        }
         return res;
     }
     Py_ssize_t num_notes = PySequence_Length(notes);



More information about the Python-checkins mailing list