summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/pyerrors.h11
-rw-r--r--Lib/test/test_capi.py4
-rw-r--r--Modules/zipimport.c6
-rw-r--r--Objects/abstract.c22
-rw-r--r--Objects/genobject.c32
-rw-r--r--Objects/unicodeobject.c7
-rw-r--r--Python/errors.c41
7 files changed, 70 insertions, 53 deletions
diff --git a/Include/pyerrors.h b/Include/pyerrors.h
index 03cee3d..f9f74c0 100644
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -255,6 +255,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 --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index d4faeb3..6c3625d 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -222,8 +222,8 @@ class CAPITest(unittest.TestCase):
br'result with an error set\n'
br'ValueError\n'
br'\n'
- br'During handling of the above exception, '
- br'another exception occurred:\n'
+ br'The above exception was the direct cause '
+ br'of the following exception:\n'
br'\n'
br'SystemError: <built-in '
br'function return_result_with_error> '
diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 7473a8f..59046aa 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -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 --git a/Objects/abstract.c b/Objects/abstract.c
index 747eda0..f9afece 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2198,20 +2198,18 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where)
}
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 --git a/Objects/genobject.c b/Objects/genobject.c
index 7a1e9fd..7bcf016 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -118,33 +118,6 @@ gen_dealloc(PyGenObject *gen)
PyObject_GC_Del(gen);
}
-static void
-gen_chain_runtime_error(const char *msg)
-{
- PyObject *exc, *val, *val2, *tb;
-
- /* TODO: This about rewriting using _PyErr_ChainExceptions. */
-
- 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);
-}
-
static PyObject *
gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
{
@@ -276,8 +249,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
else if PyAsyncGen_CheckExact(gen) {
msg = "async generator raised StopIteration";
}
- /* Raise a RuntimeError */
- gen_chain_runtime_error(msg);
+ _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg);
}
else {
/* `gen` is an ordinary generator without
@@ -309,7 +281,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
raise a RuntimeError.
*/
const char *msg = "async generator raised StopAsyncIteration";
- gen_chain_runtime_error(msg);
+ _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg);
}
if (!result || f->f_stacktop == NULL) {
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index adeec8c..80e6cf2 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -3835,13 +3835,10 @@ PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size)
Py_FileSystemDefaultEncodeErrors);
#ifdef MS_WINDOWS
if (!res && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
- PyObject *exc, *val, *tb;
- PyErr_Fetch(&exc, &val, &tb);
- PyErr_Format(PyExc_RuntimeError,
- "filesystem path bytes were not correctly encoded with '%s'. " \
+ _PyErr_FormatFromCause(PyExc_RuntimeError,
+ "filesystem path bytes were not correctly encoded with '%s'. "
"Please report this at http://bugs.python.org/issue27781",
Py_FileSystemDefaultEncoding);
- _PyErr_ChainExceptions(exc, val, tb);
}
#endif
return res;
diff --git a/Python/errors.c b/Python/errors.c
index 12bde28..918f4df 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -401,6 +401,47 @@ _PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
}
}
+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(tb);
+ }
+ Py_DECREF(exc);
+ 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