Issue #18776: atexit callbacks now display their full traceback when they raise an exception.

This commit is contained in:
Antoine Pitrou 2013-10-13 21:54:15 +02:00
commit 6039db8de3
3 changed files with 32 additions and 0 deletions

View File

@ -77,6 +77,25 @@ class GeneralTest(unittest.TestCase):
self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
self.assertIn("ZeroDivisionError", self.stream.getvalue())
def test_print_tracebacks(self):
# Issue #18776: the tracebacks should be printed when errors occur.
def f():
1/0 # one
def g():
1/0 # two
def h():
1/0 # three
atexit.register(f)
atexit.register(g)
atexit.register(h)
self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
stderr = self.stream.getvalue()
self.assertEqual(stderr.count("ZeroDivisionError"), 3)
self.assertIn("# one", stderr)
self.assertIn("# two", stderr)
self.assertIn("# three", stderr)
def test_stress(self):
a = [0]
def inc():

View File

@ -42,6 +42,9 @@ Core and Builtins
Library
-------
- Issue #18776: atexit callbacks now display their full traceback when they
raise an exception.
- Issue #17827: Add the missing documentation for ``codecs.encode`` and
``codecs.decode``.

View File

@ -1919,6 +1919,16 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
{
PyObject *seen;
PyObject *f = PySys_GetObject("stderr");
if (PyExceptionInstance_Check(value)
&& tb != NULL && PyTraceBack_Check(tb)) {
/* Put the traceback on the exception, otherwise it won't get
displayed. See issue #18776. */
PyObject *cur_tb = PyException_GetTraceback(value);
if (cur_tb == NULL)
PyException_SetTraceback(value, tb);
else
Py_DECREF(cur_tb);
}
if (f == Py_None) {
/* pass */
}