Issue #28492: Fix how StopIteration is raised in _asyncio.Future

This commit is contained in:
Yury Selivanov 2016-10-20 15:54:20 -04:00
parent 82919ec44f
commit a4b884f900
3 changed files with 34 additions and 2 deletions

View file

@ -464,6 +464,19 @@ def test_set_result_unless_cancelled(self):
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):

View file

@ -28,6 +28,8 @@ Library
- 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
-----

View file

@ -787,9 +787,26 @@ FutureIter_iternext(futureiterobject *it)
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;