gh-134170: Add colorization to unraisable exceptions (#134183)

Default implementation of sys.unraisablehook() now uses traceback._print_exception_bltin() to print exceptions with colorized text.

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Peter Bierma 2025-08-04 10:35:00 -04:00 committed by GitHub
parent 8943bb722f
commit e8251dc0ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 55 additions and 6 deletions

View file

@ -1444,12 +1444,16 @@ make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type,
It can be called to log the exception of a custom sys.unraisablehook.
Do nothing if sys.stderr attribute doesn't exist or is set to None. */
This assumes 'file' is neither NULL nor None.
*/
static int
write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
PyObject *exc_value, PyObject *exc_tb,
PyObject *err_msg, PyObject *obj, PyObject *file)
{
assert(file != NULL);
assert(!Py_IsNone(file));
if (obj != NULL && obj != Py_None) {
if (err_msg != NULL && err_msg != Py_None) {
if (PyFile_WriteObject(err_msg, file, Py_PRINT_RAW) < 0) {
@ -1484,6 +1488,27 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
}
}
// Try printing the exception using the stdlib module.
// If this fails, then we have to use the C implementation.
PyObject *print_exception_fn = PyImport_ImportModuleAttrString("traceback",
"_print_exception_bltin");
if (print_exception_fn != NULL && PyCallable_Check(print_exception_fn)) {
PyObject *args[2] = {exc_value, file};
PyObject *result = PyObject_Vectorcall(print_exception_fn, args, 2, NULL);
int ok = (result != NULL);
Py_DECREF(print_exception_fn);
Py_XDECREF(result);
if (ok) {
// Nothing else to do
return 0;
}
}
else {
Py_XDECREF(print_exception_fn);
}
// traceback module failed, fall back to pure C
_PyErr_Clear(tstate);
if (exc_tb != NULL && exc_tb != Py_None) {
if (PyTraceBack_Print(exc_tb, file) < 0) {
/* continue even if writing the traceback failed */