event: Fix `await gather()` returning first item instead of tuple
Fixes #1738
This commit is contained in:
parent
7d7a08e66f
commit
41e4cf5d11
|
|
@ -167,8 +167,27 @@ static PyObject *gen_next(PyObject *self) {
|
||||||
} else {
|
} else {
|
||||||
PyObject *result = get_done_result(future);
|
PyObject *result = get_done_result(future);
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
Py_INCREF(PyExc_StopIteration);
|
// See python/cpython#101578 - PyErr_SetObject has a special case where
|
||||||
PyErr_Restore(PyExc_StopIteration, result, nullptr);
|
// it interprets a tuple specially, so we bypass that by creating the
|
||||||
|
// exception directly.
|
||||||
|
#if PY_VERSION_HEX >= 0x030C0000 // 3.12
|
||||||
|
PyObject *exc = PyObject_CallOneArg(PyExc_StopIteration, result);
|
||||||
|
if (LIKELY(exc != nullptr)) {
|
||||||
|
// This function steals a reference to exc.
|
||||||
|
PyErr_SetRaisedException(exc);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (PyTuple_Check(result)) {
|
||||||
|
PyObject *exc = PyObject_CallOneArg(PyExc_StopIteration, result);
|
||||||
|
if (LIKELY(exc != nullptr)) {
|
||||||
|
PyErr_SetObject(PyExc_StopIteration, exc);
|
||||||
|
Py_DECREF(exc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Py_INCREF(PyExc_StopIteration);
|
||||||
|
PyErr_Restore(PyExc_StopIteration, result, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,21 @@ else:
|
||||||
CancelledError = Exception
|
CancelledError = Exception
|
||||||
|
|
||||||
|
|
||||||
|
def check_result(fut, expected):
|
||||||
|
"""Asserts the result of the future is the expected value."""
|
||||||
|
|
||||||
|
if fut.result() != expected:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Make sure that await also returns the values properly
|
||||||
|
with pytest.raises(StopIteration) as e:
|
||||||
|
next(fut.__await__())
|
||||||
|
if e.value.value != expected:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def test_future_cancelled():
|
def test_future_cancelled():
|
||||||
fut = core.AsyncFuture()
|
fut = core.AsyncFuture()
|
||||||
|
|
||||||
|
|
@ -205,15 +220,20 @@ def test_future_result():
|
||||||
ep = core.EventParameter(0.5)
|
ep = core.EventParameter(0.5)
|
||||||
fut = core.AsyncFuture()
|
fut = core.AsyncFuture()
|
||||||
fut.set_result(ep)
|
fut.set_result(ep)
|
||||||
assert fut.result() == 0.5
|
assert check_result(fut, 0.5)
|
||||||
assert fut.result() == 0.5
|
assert check_result(fut, 0.5)
|
||||||
|
|
||||||
# Store TypedObject
|
# Store TypedObject
|
||||||
dg = core.Datagram(b"test")
|
dg = core.Datagram(b"test")
|
||||||
fut = core.AsyncFuture()
|
fut = core.AsyncFuture()
|
||||||
fut.set_result(dg)
|
fut.set_result(dg)
|
||||||
assert fut.result() == dg
|
assert check_result(fut, dg)
|
||||||
assert fut.result() == dg
|
assert check_result(fut, dg)
|
||||||
|
|
||||||
|
# Store tuple
|
||||||
|
fut = core.AsyncFuture()
|
||||||
|
fut.set_result((1, 2))
|
||||||
|
assert check_result(fut, (1, 2))
|
||||||
|
|
||||||
# Store arbitrary Python object
|
# Store arbitrary Python object
|
||||||
obj = object()
|
obj = object()
|
||||||
|
|
@ -250,7 +270,7 @@ def test_future_gather():
|
||||||
assert gather.done()
|
assert gather.done()
|
||||||
|
|
||||||
assert not gather.cancelled()
|
assert not gather.cancelled()
|
||||||
assert tuple(gather.result()) == (1, 2)
|
assert check_result(gather, (1, 2))
|
||||||
|
|
||||||
|
|
||||||
def test_future_gather_cancel_inner():
|
def test_future_gather_cancel_inner():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue