coroutines: Error when awaiting on coroutine that's being awaited
Issue #25888
This commit is contained in:
parent
e076ffb068
commit
c724bae51c
|
@ -43,6 +43,7 @@ PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(struct _frame *,
|
||||||
PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *);
|
PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *);
|
||||||
PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **);
|
PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **);
|
||||||
PyObject *_PyGen_Send(PyGenObject *, PyObject *);
|
PyObject *_PyGen_Send(PyGenObject *, PyObject *);
|
||||||
|
PyObject *_PyGen_yf(PyGenObject *);
|
||||||
PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self);
|
PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self);
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
|
|
|
@ -942,6 +942,24 @@ class CoroutineTest(unittest.TestCase):
|
||||||
with self.assertRaises(Marker):
|
with self.assertRaises(Marker):
|
||||||
c.throw(ZeroDivisionError)
|
c.throw(ZeroDivisionError)
|
||||||
|
|
||||||
|
def test_await_15(self):
|
||||||
|
@types.coroutine
|
||||||
|
def nop():
|
||||||
|
yield
|
||||||
|
|
||||||
|
async def coroutine():
|
||||||
|
await nop()
|
||||||
|
|
||||||
|
async def waiter(coro):
|
||||||
|
await coro
|
||||||
|
|
||||||
|
coro = coroutine()
|
||||||
|
coro.send(None)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(RuntimeError,
|
||||||
|
"coroutine is being awaited already"):
|
||||||
|
waiter(coro).send(None)
|
||||||
|
|
||||||
def test_with_1(self):
|
def test_with_1(self):
|
||||||
class Manager:
|
class Manager:
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
|
|
@ -267,8 +267,8 @@ gen_close_iter(PyObject *yf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
PyObject *
|
||||||
gen_yf(PyGenObject *gen)
|
_PyGen_yf(PyGenObject *gen)
|
||||||
{
|
{
|
||||||
PyObject *yf = NULL;
|
PyObject *yf = NULL;
|
||||||
PyFrameObject *f = gen->gi_frame;
|
PyFrameObject *f = gen->gi_frame;
|
||||||
|
@ -290,7 +290,7 @@ static PyObject *
|
||||||
gen_close(PyGenObject *gen, PyObject *args)
|
gen_close(PyGenObject *gen, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *retval;
|
PyObject *retval;
|
||||||
PyObject *yf = gen_yf(gen);
|
PyObject *yf = _PyGen_yf(gen);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (yf) {
|
if (yf) {
|
||||||
|
@ -330,7 +330,7 @@ gen_throw(PyGenObject *gen, PyObject *args)
|
||||||
PyObject *typ;
|
PyObject *typ;
|
||||||
PyObject *tb = NULL;
|
PyObject *tb = NULL;
|
||||||
PyObject *val = NULL;
|
PyObject *val = NULL;
|
||||||
PyObject *yf = gen_yf(gen);
|
PyObject *yf = _PyGen_yf(gen);
|
||||||
_Py_IDENTIFIER(throw);
|
_Py_IDENTIFIER(throw);
|
||||||
|
|
||||||
if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb))
|
if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb))
|
||||||
|
@ -564,7 +564,7 @@ gen_set_qualname(PyGenObject *op, PyObject *value)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
gen_getyieldfrom(PyGenObject *gen)
|
gen_getyieldfrom(PyGenObject *gen)
|
||||||
{
|
{
|
||||||
PyObject *yf = gen_yf(gen);
|
PyObject *yf = _PyGen_yf(gen);
|
||||||
if (yf == NULL)
|
if (yf == NULL)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
return yf;
|
return yf;
|
||||||
|
@ -799,7 +799,7 @@ coro_await(PyCoroObject *coro)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
coro_get_cr_await(PyCoroObject *coro)
|
coro_get_cr_await(PyCoroObject *coro)
|
||||||
{
|
{
|
||||||
PyObject *yf = gen_yf((PyGenObject *) coro);
|
PyObject *yf = _PyGen_yf((PyGenObject *) coro);
|
||||||
if (yf == NULL)
|
if (yf == NULL)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
return yf;
|
return yf;
|
||||||
|
|
|
@ -2021,6 +2021,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||||
|
|
||||||
Py_DECREF(iterable);
|
Py_DECREF(iterable);
|
||||||
|
|
||||||
|
if (iter != NULL && PyCoro_CheckExact(iter)) {
|
||||||
|
PyObject *yf = _PyGen_yf((PyGenObject*)iter);
|
||||||
|
if (yf != NULL) {
|
||||||
|
/* `iter` is a coroutine object that is being
|
||||||
|
awaited, `yf` is a pointer to the current awaitable
|
||||||
|
being awaited on. */
|
||||||
|
Py_DECREF(yf);
|
||||||
|
Py_CLEAR(iter);
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_RuntimeError,
|
||||||
|
"coroutine is being awaited already");
|
||||||
|
/* The code below jumps to `error` if `iter` is NULL. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SET_TOP(iter); /* Even if it's NULL */
|
SET_TOP(iter); /* Even if it's NULL */
|
||||||
|
|
||||||
if (iter == NULL) {
|
if (iter == NULL) {
|
||||||
|
|
Loading…
Reference in New Issue