Index: Python/errors.c =================================================================== --- Python/errors.c (revision 73429) +++ Python/errors.c (working copy) @@ -642,7 +642,73 @@ } +/* Returns the exception string as a new + PyUnicode object or NULL if the conversion failed */ +PyObject * +PyErr_AsUnicode(void) +{ + PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */ + PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */ + PyObject *string_io = NULL; + PyObject *string_io_buf = NULL; + PyObject *string_io_mod; + PyObject *string_io_getvalue; + + PyObject *error_type, *error_value, *error_traceback; + + if (!PyErr_Occurred()) + return NULL; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyErr_Clear(); + + /* import io + * string_io = io.StringIO() + */ + if(! (string_io_mod= PyImport_ImportModule("io")) ) { + PyErr_Clear(); + return NULL; + } + else if (! (string_io= PyObject_CallMethod(string_io_mod, "StringIO", NULL))) { + PyErr_Clear(); + Py_DECREF(string_io_mod); + return NULL; + } + else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) { + PyErr_Clear(); + Py_DECREF(string_io_mod); + Py_DECREF(string_io); + return NULL; + } + + Py_INCREF(stdout_backup); /* since these were borrowed we dont want them freed when replaced. */ + Py_INCREF(stderr_backup); + + PySys_SetObject("stdout", string_io); /* both of these are free'd when restoring */ + PySys_SetObject("stderr", string_io); + + PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Print(); /* print the error */ + PyErr_Clear(); + + string_io_buf = PyObject_CallObject(string_io_getvalue, NULL); + + PySys_SetObject("stdout", stdout_backup); + PySys_SetObject("stderr", stderr_backup); + + Py_DECREF(stdout_backup); /* now sys owns the ref again */ + Py_DECREF(stderr_backup); + + Py_DECREF(string_io_mod); + Py_DECREF(string_io_getvalue); + Py_DECREF(string_io); /* free the original reference */ + + PyErr_Clear(); + return string_io_buf; +} + PyObject * PyErr_NewException(const char *name, PyObject *base, PyObject *dict) { Index: Include/pyerrors.h =================================================================== --- Include/pyerrors.h (revision 73429) +++ Include/pyerrors.h (working copy) @@ -184,6 +184,8 @@ PyAPI_FUNC(PyObject *) PyErr_Format(PyObject *, const char *, ...); +PyAPI_FUNC(PyObject *) PyErr_AsUnicode(void); + #ifdef MS_WINDOWS PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilenameObject( int, const char *); Index: Doc/c-api/exceptions.rst =================================================================== --- Doc/c-api/exceptions.rst (revision 73429) +++ Doc/c-api/exceptions.rst (working copy) @@ -204,6 +204,12 @@ copied as-is to the result string, and any extra arguments discarded. +.. cfunction:: PyObject* PyErr_AsUnicode() + + This function returns the output of :cfunc:`PyErr_Print` as a string. + it returns *NULL* without setting an exception if the conversion fails. + + .. cfunction:: void PyErr_SetNone(PyObject *type) This is a shorthand for ``PyErr_SetObject(type, Py_None)``.