]> granicus.if.org Git - python/commitdiff
correctly emulate error semantics of gen.throw in FutureIter_throw
authorBenjamin Peterson <benjamin@python.org>
Mon, 14 Nov 2016 08:15:44 +0000 (00:15 -0800)
committerBenjamin Peterson <benjamin@python.org>
Mon, 14 Nov 2016 08:15:44 +0000 (00:15 -0800)
Lib/test/test_asyncio/test_futures.py
Modules/_asynciomodule.c

index c1476089f49587a2c2996dcbe703be47dcc1f6bd..89afdcaff2866589d16f85bd958c23c436036c47 100644 (file)
@@ -466,6 +466,15 @@ class BaseFutureTests:
             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')
index df81b105ec505cdda9acc10c3bdcf25d00c57af7..b65fc02ebd1f1e2f60eafd947ddbeacd4730e461 100644 (file)
@@ -1031,31 +1031,46 @@ FutureIter_throw(futureiterobject *self, PyObject *args)
     }
     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_CLEAR(self->future);
+    Py_INCREF(type);
+    Py_XINCREF(val);
+    Py_XINCREF(tb);
 
-    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);
+    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);
+
+    PyErr_Restore(type, val, tb);
+
     return FutureIter_iternext(self);
+
+  fail:
+    Py_DECREF(type);
+    Py_XDECREF(val);
+    Py_XDECREF(tb);
+    return NULL;
 }
 
 static PyObject *