bpo-1230540: Add threading.excepthook() (GH-13515)

Add a new threading.excepthook() function which handles uncaught
Thread.run() exception. It can be overridden to control how uncaught
exceptions are handled.

threading.ExceptHookArgs is not documented on purpose: it should not
be used directly.

* threading.excepthook() and threading.ExceptHookArgs.
* Add _PyErr_Display(): similar to PyErr_Display(), but accept a
  'file' parameter.
* Add _thread._excepthook(): C implementation of the exception hook
  calling _PyErr_Display().
* Add _thread._ExceptHookArgs: structseq type.
* Add threading._invoke_excepthook_wrapper() which handles the gory
  details to ensure that everything remains alive during Python
  shutdown.
* Add unit tests.
This commit is contained in:
Victor Stinner 2019-05-28 00:39:52 +02:00 committed by GitHub
parent 23b4b697e5
commit cd590a7ced
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 424 additions and 67 deletions

View file

@ -953,10 +953,11 @@ print_exception_recursive(PyObject *f, PyObject *value, PyObject *seen)
}
void
PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
_PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb)
{
assert(file != NULL && file != Py_None);
PyObject *seen;
PyObject *f = _PySys_GetObjectId(&PyId_stderr);
if (PyExceptionInstance_Check(value)
&& tb != NULL && PyTraceBack_Check(tb)) {
/* Put the traceback on the exception, otherwise it won't get
@ -967,23 +968,32 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
else
Py_DECREF(cur_tb);
}
if (f == Py_None) {
/* pass */
/* We choose to ignore seen being possibly NULL, and report
at least the main exception (it could be a MemoryError).
*/
seen = PySet_New(NULL);
if (seen == NULL) {
PyErr_Clear();
}
else if (f == NULL) {
print_exception_recursive(file, value, seen);
Py_XDECREF(seen);
}
void
PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
{
PyObject *file = _PySys_GetObjectId(&PyId_stderr);
if (file == NULL) {
_PyObject_Dump(value);
fprintf(stderr, "lost sys.stderr\n");
return;
}
else {
/* We choose to ignore seen being possibly NULL, and report
at least the main exception (it could be a MemoryError).
*/
seen = PySet_New(NULL);
if (seen == NULL)
PyErr_Clear();
print_exception_recursive(f, value, seen);
Py_XDECREF(seen);
if (file == Py_None) {
return;
}
_PyErr_Display(file, exception, value, tb);
}
PyObject *