summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2016-11-14 08:15:44 (GMT)
committerBenjamin Peterson <benjamin@python.org>2016-11-14 08:15:44 (GMT)
commit996fc1fcfc165a8d7f56b6d31933b594a5f48d73 (patch)
treee655847d7f22f0201fa306b524ac9377478e18e1
parentf8cebad2901799ebfceb3228a7ba69a504e21f75 (diff)
downloadcpython-996fc1fcfc165a8d7f56b6d31933b594a5f48d73.zip
cpython-996fc1fcfc165a8d7f56b6d31933b594a5f48d73.tar.gz
cpython-996fc1fcfc165a8d7f56b6d31933b594a5f48d73.tar.bz2
correctly emulate error semantics of gen.throw in FutureIter_throw
-rw-r--r--Lib/test/test_asyncio/test_futures.py9
-rw-r--r--Modules/_asynciomodule.c53
2 files changed, 43 insertions, 19 deletions
diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py
index c147608..89afdca 100644
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -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')
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index df81b10..b65fc02 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -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 *