summaryrefslogtreecommitdiffstats
path: root/Python/errors.c
diff options
context:
space:
mode:
authorPeter Bierma <zintensitydev@gmail.com>2025-08-04 14:35:00 (GMT)
committerGitHub <noreply@github.com>2025-08-04 14:35:00 (GMT)
commite8251dc0ae6a85f6a0e427ae64fb0fe847eb3cf8 (patch)
tree4b84339ca33cacefe3a80b24a97f5cbaf62bcf9d /Python/errors.c
parent8943bb722f2f88a95ea6c5ee36bb5d540740d792 (diff)
downloadcpython-e8251dc0ae6a85f6a0e427ae64fb0fe847eb3cf8.zip
cpython-e8251dc0ae6a85f6a0e427ae64fb0fe847eb3cf8.tar.gz
cpython-e8251dc0ae6a85f6a0e427ae64fb0fe847eb3cf8.tar.bz2
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>
Diffstat (limited to 'Python/errors.c')
-rw-r--r--Python/errors.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/Python/errors.c b/Python/errors.c
index a3122f7..2688396 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -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 */