Skip to content

Commit 24201d4

Browse files
committed
Issue #18776: atexit callbacks now display their full traceback when they raise an exception.
1 parent 4e98567 commit 24201d4

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

Lib/test/test_atexit.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,25 @@ def test_raise_unnormalized(self):
7474
self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
7575
self.assertIn("ZeroDivisionError", self.stream.getvalue())
7676

77+
def test_print_tracebacks(self):
78+
# Issue #18776: the tracebacks should be printed when errors occur.
79+
def f():
80+
1/0 # one
81+
def g():
82+
1/0 # two
83+
def h():
84+
1/0 # three
85+
atexit.register(f)
86+
atexit.register(g)
87+
atexit.register(h)
88+
89+
self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
90+
stderr = self.stream.getvalue()
91+
self.assertEqual(stderr.count("ZeroDivisionError"), 3)
92+
self.assertIn("# one", stderr)
93+
self.assertIn("# two", stderr)
94+
self.assertIn("# three", stderr)
95+
7796
def test_stress(self):
7897
a = [0]
7998
def inc():

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ Core and Builtins
7676
Library
7777
-------
7878

79+
- Issue #18776: atexit callbacks now display their full traceback when they
80+
raise an exception.
81+
7982
- Issue #17827: Add the missing documentation for ``codecs.encode`` and
8083
``codecs.decode``.
8184

Python/pythonrun.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,16 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
18801880
{
18811881
PyObject *seen;
18821882
PyObject *f = PySys_GetObject("stderr");
1883+
if (PyExceptionInstance_Check(value)
1884+
&& tb != NULL && PyTraceBack_Check(tb)) {
1885+
/* Put the traceback on the exception, otherwise it won't get
1886+
displayed. See issue #18776. */
1887+
PyObject *cur_tb = PyException_GetTraceback(value);
1888+
if (cur_tb == NULL)
1889+
PyException_SetTraceback(value, tb);
1890+
else
1891+
Py_DECREF(cur_tb);
1892+
}
18831893
if (f == Py_None) {
18841894
/* pass */
18851895
}

0 commit comments

Comments
 (0)