Close #20105: set __traceback__ when chaining exceptions in C

This commit is contained in:
Nick Coghlan 2014-01-27 00:53:38 +10:00
parent 23e37aa7b7
commit 77b286b2cc
5 changed files with 27 additions and 2 deletions

View 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 class in that case. If the values are already normalized, nothing happens.
The delayed normalization is implemented to improve performance. 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() .. c:function:: void PyErr_Clear()

View file

@ -264,6 +264,9 @@ name of the codec responsible for producing the error::
>>> import codecs >>> import codecs
>>> codecs.decode(b"abcdefgh", "hex") >>> 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 binascii.Error: Non-hexadecimal digit found
The above exception was the direct cause of the following exception: 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) binascii.Error: decoding with 'hex' codec failed (Error: Non-hexadecimal digit found)
>>> codecs.encode("hello", "bz2") >>> 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 TypeError: 'str' does not support the buffer interface
The above exception was the direct cause of the following exception: The above exception was the direct cause of the following exception:

View file

@ -2522,6 +2522,7 @@ class ExceptionChainingTest(unittest.TestCase):
with self.assertRaisesRegex(exc_type, full_msg) as caught: with self.assertRaisesRegex(exc_type, full_msg) as caught:
yield caught yield caught
self.assertIsInstance(caught.exception.__cause__, exc_type) self.assertIsInstance(caught.exception.__cause__, exc_type)
self.assertIsNotNone(caught.exception.__cause__.__traceback__)
def raise_obj(self, *args, **kwds): def raise_obj(self, *args, **kwds):
# Helper to dynamically change the object raised by a test codec # Helper to dynamically change the object raised by a test codec

View file

@ -36,6 +36,9 @@ Core and Builtins
Library 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 - asyncio: Various improvements and small changes not all covered by
issues listed below. E.g. wait_for() now cancels the inner task if issues listed below. E.g. wait_for() now cancels the inner task if
the timeout occcurs; tweaked the set of exported symbols; renamed the timeout occcurs; tweaked the set of exported symbols; renamed

View file

@ -2689,8 +2689,11 @@ _PyErr_TrySetFromCause(const char *format, ...)
* types as well, but that's quite a bit trickier due to the extra * types as well, but that's quite a bit trickier due to the extra
* state potentially stored on OSError instances. * state potentially stored on OSError instances.
*/ */
/* Ensure the traceback is set correctly on the existing exception */
Py_XDECREF(tb); if (tb != NULL) {
PyException_SetTraceback(val, tb);
Py_DECREF(tb);
}
#ifdef HAVE_STDARG_PROTOTYPES #ifdef HAVE_STDARG_PROTOTYPES
va_start(vargs, format); va_start(vargs, format);