]> granicus.if.org Git - python/commitdiff
Close #20105: set __traceback__ when chaining exceptions in C
authorNick Coghlan <ncoghlan@gmail.com>
Sun, 26 Jan 2014 14:53:38 +0000 (00:53 +1000)
committerNick Coghlan <ncoghlan@gmail.com>
Sun, 26 Jan 2014 14:53:38 +0000 (00:53 +1000)
Doc/c-api/exceptions.rst
Doc/whatsnew/3.4.rst
Lib/test/test_codecs.py
Misc/NEWS
Objects/exceptions.c

index 8658a585410463a36a03c02d5432ab03c87a02a6..d4065e08c9038a1b099c86eba7ad5f3b30d35bd8 100644 (file)
@@ -90,6 +90,16 @@ in various ways.  There is a separate error indicator for each thread.
    the class in that case.  If the values are already normalized, nothing happens.
    The delayed normalization is implemented to improve performance.
 
+   .. note::
+
+      This function *does not* implicitly set the ``__traceback__``
+      attribute on the exception value. If setting the traceback
+      appropriately is desired, the following additional snippet is needed::
+
+         if (tb != NULL) {
+           PyException_SetTraceback(val, tb);
+         }
+
 
 .. c:function:: void PyErr_Clear()
 
index 5d397fec26044e48a8281b39736b7e20ceec82b1..1d889653d96eb3d89af24d61be6ec1170021bd91 100644 (file)
@@ -264,6 +264,9 @@ name of the codec responsible for producing the error::
     >>> import codecs
 
     >>> codecs.decode(b"abcdefgh", "hex")
+    Traceback (most recent call last):
+      File "/usr/lib/python3.4/encodings/hex_codec.py", line 20, in hex_decode
+        return (binascii.a2b_hex(input), len(input))
     binascii.Error: Non-hexadecimal digit found
 
     The above exception was the direct cause of the following exception:
@@ -273,6 +276,11 @@ name of the codec responsible for producing the error::
     binascii.Error: decoding with 'hex' codec failed (Error: Non-hexadecimal digit found)
 
     >>> codecs.encode("hello", "bz2")
+    Traceback (most recent call last):
+      File "/usr/lib/python3.4/encodings/bz2_codec.py", line 17, in bz2_encode
+        return (bz2.compress(input), len(input))
+      File "/usr/lib/python3.4/bz2.py", line 498, in compress
+        return comp.compress(data) + comp.flush()
     TypeError: 'str' does not support the buffer interface
 
     The above exception was the direct cause of the following exception:
index f9c9e69f23267ff434d1e1050946a43db5667135..a32ce76bc8d1271e65148954c19c133f2c91904d 100644 (file)
@@ -2522,6 +2522,7 @@ class ExceptionChainingTest(unittest.TestCase):
         with self.assertRaisesRegex(exc_type, full_msg) as caught:
             yield caught
         self.assertIsInstance(caught.exception.__cause__, exc_type)
+        self.assertIsNotNone(caught.exception.__cause__.__traceback__)
 
     def raise_obj(self, *args, **kwds):
         # Helper to dynamically change the object raised by a test codec
index c248d7c4a391e3d52113a39f6fe020f81d5ae912..25167357181b218149a9e3e54c69276ceaea4fef 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -36,6 +36,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #20105: the codec exception chaining now correctly sets the
+  traceback of the original exception as its __traceback__ attribute.
+
 - asyncio: Various improvements and small changes not all covered by
   issues listed below.  E.g. wait_for() now cancels the inner task if
   the timeout occcurs; tweaked the set of exported symbols; renamed
index bff7f0819e3978a079a439bb83eef2b631126749..2531ead50fbda1294e623f88ad071d17c2fbea62 100644 (file)
@@ -2689,8 +2689,11 @@ _PyErr_TrySetFromCause(const char *format, ...)
      * types as well, but that's quite a bit trickier due to the extra
      * state potentially stored on OSError instances.
      */
-
-    Py_XDECREF(tb);
+    /* Ensure the traceback is set correctly on the existing exception */
+    if (tb != NULL) {
+        PyException_SetTraceback(val, tb);
+        Py_DECREF(tb);
+    }
 
 #ifdef HAVE_STDARG_PROTOTYPES
     va_start(vargs, format);