From 996fc1fcfc165a8d7f56b6d31933b594a5f48d73 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 14 Nov 2016 00:15:44 -0800 Subject: correctly emulate error semantics of gen.throw in FutureIter_throw --- Lib/test/test_asyncio/test_futures.py | 9 ++++++ 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 * -- cgit v0.12