mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	coroutines: Error when awaiting on coroutine that's being awaited
Issue #25888
This commit is contained in:
		
							parent
							
								
									e076ffb068
								
							
						
					
					
						commit
						c724bae51c
					
				
					 4 changed files with 40 additions and 6 deletions
				
			
		|  | @ -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 @@ async def coro2(): | ||||||
|         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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Yury Selivanov
						Yury Selivanov