[Python-checkins] cpython (merge 3.6 -> default): Issue #28410: Added _PyErr_FormatFromCause() -- the helper for raising

serhiy.storchaka python-checkins at python.org
Fri Oct 21 10:15:58 EDT 2016


https://hg.python.org/cpython/rev/2119cb0beace
changeset:   104609:2119cb0beace
parent:      104607:e853492da42c
parent:      104608:969c8bfe8872
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Fri Oct 21 17:10:42 2016 +0300
summary:
  Issue #28410: Added _PyErr_FormatFromCause() -- the helper for raising
new exception with setting current exception as __cause__.

_PyErr_FormatFromCause(exception, format, args...) is equivalent to Python

    raise exception(format % args) from sys.exc_info()[1]

files:
  Include/pyerrors.h      |  11 +++++++
  Lib/test/test_capi.py   |   4 +-
  Modules/zipimport.c     |   6 +--
  Objects/abstract.c      |  22 +++++++--------
  Objects/genobject.c     |  32 +---------------------
  Objects/unicodeobject.c |   7 +---
  Python/errors.c         |  41 +++++++++++++++++++++++++++++
  7 files changed, 70 insertions(+), 53 deletions(-)


diff --git a/Include/pyerrors.h b/Include/pyerrors.h
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -255,6 +255,17 @@
     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
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -222,8 +222,8 @@
                                 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
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -907,10 +907,8 @@
     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
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2198,20 +2198,18 @@
     }
     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
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -118,33 +118,6 @@
     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 @@
             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 @@
            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
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -3831,13 +3831,10 @@
                                 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
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -401,6 +401,47 @@
     }
 }
 
+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

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list