[Python-checkins] cpython (3.6): correctly emulate error semantics of gen.throw in FutureIter_throw

benjamin.peterson python-checkins at python.org
Mon Nov 14 03:15:58 EST 2016


https://hg.python.org/cpython/rev/3ea121235ede
changeset:   105100:3ea121235ede
branch:      3.6
parent:      105098:6312f1eca2ff
user:        Benjamin Peterson <benjamin at python.org>
date:        Mon Nov 14 00:15:44 2016 -0800
summary:
  correctly emulate error semantics of gen.throw in FutureIter_throw

files:
  Lib/test/test_asyncio/test_futures.py |   9 ++
  Modules/_asynciomodule.c              |  55 +++++++++-----
  2 files changed, 44 insertions(+), 20 deletions(-)


diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -466,6 +466,15 @@
             self.fail('StopIteration was expected')
         self.assertEqual(result, (1, 2))
 
+    def test_future_iter_throw(self):
+        fut = self._new_future(loop=self.loop)
+        fi = iter(fut)
+        self.assertRaises(TypeError, fi.throw,
+                          Exception, Exception("elephant"), 32)
+        self.assertRaises(TypeError, fi.throw,
+                          Exception("elephant"), Exception("elephant"))
+        self.assertRaises(TypeError, fi.throw, list)
+
 
 @unittest.skipUnless(hasattr(futures, '_CFuture'),
                      'requires the C _asyncio module')
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -1031,31 +1031,46 @@
     }
     if (tb == Py_None) {
         tb = NULL;
+    } else if (tb != NULL && !PyTraceBack_Check(tb)) {
+        PyErr_SetString(PyExc_TypeError, "throw() third argument must be a traceback");
+        return NULL;
+    }
+
+    Py_INCREF(type);
+    Py_XINCREF(val);
+    Py_XINCREF(tb);
+
+    if (PyExceptionClass_Check(type)) {
+        PyErr_NormalizeException(&type, &val, &tb);
+    } else if (PyExceptionInstance_Check(type)) {
+        if (val) {
+            PyErr_SetString(PyExc_TypeError,
+                            "instance exception may not have a separate value");
+            goto fail;
+        }
+        val = type;
+        type = PyExceptionInstance_Class(type);
+        Py_INCREF(type);
+        if (tb == NULL)
+            tb = PyException_GetTraceback(val);
+    } else {
+        PyErr_SetString(PyExc_TypeError,
+                        "exceptions must be classes deriving BaseException or "
+                        "instances of such a class");
+        goto fail;
     }
 
     Py_CLEAR(self->future);
 
-    if (tb != NULL) {
-        PyErr_Restore(type, val, tb);
-    }
-    else if (val != NULL) {
-        PyErr_SetObject(type, val);
-    }
-    else {
-        if (PyExceptionClass_Check(type)) {
-            val = PyObject_CallObject(type, NULL);
-            PyErr_SetObject(type, val);
-            Py_DECREF(val);
-        }
-        else {
-            val = type;
-            assert (PyExceptionInstance_Check(val));
-            type = (PyObject*)Py_TYPE(val);
-            assert (PyExceptionClass_Check(type));
-            PyErr_SetObject(type, val);
-        }
-    }
+    PyErr_Restore(type, val, tb);
+
     return FutureIter_iternext(self);
+
+  fail:
+    Py_DECREF(type);
+    Py_XDECREF(val);
+    Py_XDECREF(tb);
+    return NULL;
 }
 
 static PyObject *

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


More information about the Python-checkins mailing list