From 24201d497cf23d399cceadad8058261c13ae536f Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 13 Oct 2013 21:53:13 +0200 Subject: Issue #18776: atexit callbacks now display their full traceback when they raise an exception. --- Lib/test/test_atexit.py | 19 +++++++++++++++++++ Misc/NEWS | 3 +++ Python/pythonrun.c | 10 ++++++++++ 3 files changed, 32 insertions(+) diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py index 5200af7..30c3b4a 100644 --- a/Lib/test/test_atexit.py +++ b/Lib/test/test_atexit.py @@ -74,6 +74,25 @@ class TestCase(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(): diff --git a/Misc/NEWS b/Misc/NEWS index 32b9395..3b5b4c5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -76,6 +76,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``. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 9ef653b..ee277b6 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1880,6 +1880,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 */ } -- cgit v0.12