diff options
author | Benjamin Peterson <benjamin@python.org> | 2016-11-14 08:15:44 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2016-11-14 08:15:44 (GMT) |
commit | 996fc1fcfc165a8d7f56b6d31933b594a5f48d73 (patch) | |
tree | e655847d7f22f0201fa306b524ac9377478e18e1 | |
parent | f8cebad2901799ebfceb3228a7ba69a504e21f75 (diff) | |
download | cpython-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.py | 9 | ||||
-rw-r--r-- | Modules/_asynciomodule.c | 53 |
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 * |