diff -r 6b3be9f38f2a Include/pyerrors.h --- a/Include/pyerrors.h Tue Oct 18 13:23:18 2016 +0300 +++ b/Include/pyerrors.h Tue Oct 18 13:55:07 2016 +0300 @@ -254,6 +254,17 @@ PyAPI_FUNC(PyObject *) PyErr_FormatV( va_list vargs); #endif +#ifndef Py_LIMITED_API +/* Like PyErr_Format(), but saves current exception as __context__ and + __cause__. + */ +PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( + PyObject *exception, + const char *format, /* ASCII-encoded string */ + ... + ); +#endif + #ifdef MS_WINDOWS PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( int ierr, diff -r 6b3be9f38f2a Modules/zipimport.c --- a/Modules/zipimport.c Tue Oct 18 13:23:18 2016 +0300 +++ b/Modules/zipimport.c Tue Oct 18 13:55:07 2016 +0300 @@ -907,10 +907,8 @@ read_directory(PyObject *archive) fp = _Py_fopen_obj(archive, "rb"); if (fp == NULL) { if (PyErr_ExceptionMatches(PyExc_OSError)) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - PyErr_Format(ZipImportError, "can't open Zip file: %R", archive); - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_FormatFromCause(ZipImportError, + "can't open Zip file: %R", archive); } return NULL; } diff -r 6b3be9f38f2a Objects/abstract.c --- a/Objects/abstract.c Tue Oct 18 13:23:18 2016 +0300 +++ b/Objects/abstract.c Tue Oct 18 13:55:07 2016 +0300 @@ -2118,20 +2118,18 @@ PyObject* } else { if (err_occurred) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - Py_DECREF(result); - if (func) - PyErr_Format(PyExc_SystemError, - "%R returned a result with an error set", - func); - else - PyErr_Format(PyExc_SystemError, - "%s returned a result with an error set", - where); - _PyErr_ChainExceptions(exc, val, tb); + if (func) { + _PyErr_FormatFromCause(PyExc_SystemError, + "%R returned a result with an error set", + func); + } + else { + _PyErr_FormatFromCause(PyExc_SystemError, + "%s returned a result with an error set", + where); + } #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode */ Py_FatalError("a function returned a result with an error set"); diff -r 6b3be9f38f2a Objects/genobject.c --- a/Objects/genobject.c Tue Oct 18 13:23:18 2016 +0300 +++ b/Objects/genobject.c Tue Oct 18 13:55:07 2016 +0300 @@ -170,23 +170,10 @@ gen_send_ex(PyGenObject *gen, PyObject * if (((PyCodeObject *)gen->gi_code)->co_flags & (CO_FUTURE_GENERATOR_STOP | CO_COROUTINE | CO_ITERABLE_COROUTINE)) { - PyObject *exc, *val, *val2, *tb; char *msg = "generator raised StopIteration"; if (PyCoro_CheckExact(gen)) msg = "coroutine raised StopIteration"; - PyErr_Fetch(&exc, &val, &tb); - PyErr_NormalizeException(&exc, &val, &tb); - if (tb != NULL) - PyException_SetTraceback(val, tb); - Py_DECREF(exc); - Py_XDECREF(tb); - PyErr_SetString(PyExc_RuntimeError, msg); - PyErr_Fetch(&exc, &val2, &tb); - PyErr_NormalizeException(&exc, &val2, &tb); - Py_INCREF(val); - PyException_SetCause(val2, val); - PyException_SetContext(val2, val); - PyErr_Restore(exc, val2, tb); + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } else { PyObject *exc, *val, *tb; diff -r 6b3be9f38f2a Python/errors.c --- a/Python/errors.c Tue Oct 18 13:23:18 2016 +0300 +++ b/Python/errors.c Tue Oct 18 13:55:07 2016 +0300 @@ -388,6 +388,9 @@ void PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + } Py_DECREF(exc); Py_XDECREF(tb); PyErr_NormalizeException(&exc2, &val2, &tb2); @@ -399,6 +402,49 @@ void } } +static PyObject * +_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs) +{ + PyObject *exc, *val, *val2, *tb; + + assert(PyErr_Occurred()); + PyErr_Fetch(&exc, &val, &tb); + PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + } + + Py_DECREF(exc); + Py_XDECREF(tb); + + assert(!PyErr_Occurred()); + PyErr_FormatV(exception, format, vargs); + PyErr_Fetch(&exc, &val2, &tb); + PyErr_NormalizeException(&exc, &val2, &tb); + + Py_INCREF(val); + PyException_SetCause(val2, val); + PyException_SetContext(val2, val); + + PyErr_Restore(exc, val2, tb); + + return NULL; +} + +PyObject * +_PyErr_FormatFromCause(PyObject *exception, const char *format, ...) +{ + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + _PyErr_FormatVFromCause(exception, format, vargs); + va_end(vargs); + return NULL; +} + /* Convenience functions to set a type error exception and return 0 */ int