changeset: 104588:cfe2109ce2c0 branch: 3.6 parent: 104585:c60d41590054 user: Yury Selivanov date: Thu Oct 20 15:54:20 2016 -0400 files: Lib/test/test_asyncio/test_futures.py Misc/NEWS Modules/_asynciomodule.c description: Issue #28492: Fix how StopIteration is raised in _asyncio.Future diff -r c60d41590054 -r cfe2109ce2c0 Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py Thu Oct 20 15:40:22 2016 -0400 +++ b/Lib/test/test_asyncio/test_futures.py Thu Oct 20 15:54:20 2016 -0400 @@ -464,6 +464,19 @@ futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) + def test_future_stop_iteration_args(self): + fut = asyncio.Future(loop=self.loop) + fut.set_result((1, 2)) + fi = fut.__iter__() + result = None + try: + fi.send(None) + except StopIteration as ex: + result = ex.args[0] + else: + self.fail('StopIteration was expected') + self.assertEqual(result, (1, 2)) + class FutureDoneCallbackTests(test_utils.TestCase): diff -r c60d41590054 -r cfe2109ce2c0 Misc/NEWS --- a/Misc/NEWS Thu Oct 20 15:40:22 2016 -0400 +++ b/Misc/NEWS Thu Oct 20 15:54:20 2016 -0400 @@ -28,6 +28,8 @@ - Issue #20766: Fix references leaked by pdb in the handling of SIGINT handlers. +- Issue #28492: Fix how StopIteration exception is raised in _asyncio.Future. + Build ----- diff -r c60d41590054 -r cfe2109ce2c0 Modules/_asynciomodule.c --- a/Modules/_asynciomodule.c Thu Oct 20 15:40:22 2016 -0400 +++ b/Modules/_asynciomodule.c Thu Oct 20 15:54:20 2016 -0400 @@ -787,9 +787,26 @@ res = FutureObj_result(fut, NULL); if (res != NULL) { - // normal result - PyErr_SetObject(PyExc_StopIteration, res); + /* The result of the Future is not an exception. + + We cunstruct an exception instance manually with + PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject + (similarly to what genobject.c does). + + This is to handle a situation when "res" is a tuple, in which + case PyErr_SetObject would set the value of StopIteration to + the first element of the tuple. + + (See PyErr_SetObject/_PyErr_CreateException code for details.) + */ + PyObject *e = PyObject_CallFunctionObjArgs( + PyExc_StopIteration, res, NULL); Py_DECREF(res); + if (e == NULL) { + return NULL; + } + PyErr_SetObject(PyExc_StopIteration, e); + Py_DECREF(e); } it->future = NULL;