@@ -136,13 +136,15 @@ gen_dealloc(PyGenObject *gen)
136
136
PyObject_GC_Del (gen );
137
137
}
138
138
139
- static PyObject *
140
- gen_send_ex (PyGenObject * gen , PyObject * arg , int exc , int closing , int * is_return_value )
139
+ static PySendResult
140
+ gen_send_ex2 (PyGenObject * gen , PyObject * arg , PyObject * * presult ,
141
+ int exc , int closing )
141
142
{
142
143
PyThreadState * tstate = _PyThreadState_GET ();
143
144
PyFrameObject * f = gen -> gi_frame ;
144
145
PyObject * result ;
145
146
147
+ * presult = NULL ;
146
148
if (f != NULL && _PyFrame_IsExecuting (f )) {
147
149
const char * msg = "generator already executing" ;
148
150
if (PyCoro_CheckExact (gen )) {
@@ -152,7 +154,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
152
154
msg = "async generator already executing" ;
153
155
}
154
156
PyErr_SetString (PyExc_ValueError , msg );
155
- return NULL ;
157
+ return PYGEN_ERROR ;
156
158
}
157
159
if (f == NULL || _PyFrameHasCompleted (f )) {
158
160
if (PyCoro_CheckExact (gen ) && !closing ) {
@@ -165,19 +167,12 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
165
167
}
166
168
else if (arg && !exc ) {
167
169
/* `gen` is an exhausted generator:
168
- only set exception if called from send(). */
169
- if (PyAsyncGen_CheckExact (gen )) {
170
- PyErr_SetNone (PyExc_StopAsyncIteration );
171
- }
172
- else {
173
- if (is_return_value != NULL ) {
174
- * is_return_value = 1 ;
175
- Py_RETURN_NONE ;
176
- }
177
- PyErr_SetNone (PyExc_StopIteration );
178
- }
170
+ only return value if called from send(). */
171
+ * presult = Py_None ;
172
+ Py_INCREF (* presult );
173
+ return PYGEN_RETURN ;
179
174
}
180
- return NULL ;
175
+ return PYGEN_ERROR ;
181
176
}
182
177
183
178
assert (_PyFrame_IsRunnable (f ));
@@ -193,7 +188,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
193
188
"just-started async generator" ;
194
189
}
195
190
PyErr_SetString (PyExc_TypeError , msg );
196
- return NULL ;
191
+ return PYGEN_ERROR ;
197
192
}
198
193
} else {
199
194
/* Push arg onto the frame's value stack */
@@ -229,92 +224,94 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing, int *is_retur
229
224
230
225
/* If the generator just returned (as opposed to yielding), signal
231
226
* that the generator is exhausted. */
232
- if (result && _PyFrameHasCompleted (f )) {
233
- if (result == Py_None ) {
234
- /* Delay exception instantiation if we can */
235
- if (PyAsyncGen_CheckExact (gen )) {
236
- PyErr_SetNone (PyExc_StopAsyncIteration );
237
- Py_CLEAR (result );
238
- }
239
- else if (arg ) {
240
- if (is_return_value != NULL ) {
241
- * is_return_value = 1 ;
242
- }
243
- else {
244
- /* Set exception if not called by gen_iternext() */
245
- PyErr_SetNone (PyExc_StopIteration );
246
- Py_CLEAR (result );
247
- }
248
- }
249
- else {
250
- Py_CLEAR (result );
251
- }
227
+ if (result ) {
228
+ if (!_PyFrameHasCompleted (f )) {
229
+ * presult = result ;
230
+ return PYGEN_NEXT ;
252
231
}
253
- else {
254
- /* Async generators cannot return anything but None */
255
- assert (!PyAsyncGen_CheckExact (gen ));
256
- if (is_return_value != NULL ) {
257
- * is_return_value = 1 ;
258
- }
259
- else {
260
- _PyGen_SetStopIterationValue (result );
261
- Py_CLEAR (result );
262
- }
232
+ assert (result == Py_None || !PyAsyncGen_CheckExact (gen ));
233
+ if (result == Py_None && !PyAsyncGen_CheckExact (gen ) && !arg ) {
234
+ /* Return NULL if called by gen_iternext() */
235
+ Py_CLEAR (result );
263
236
}
264
237
}
265
- else if (!result && PyErr_ExceptionMatches (PyExc_StopIteration )) {
266
- const char * msg = "generator raised StopIteration" ;
267
- if (PyCoro_CheckExact (gen )) {
268
- msg = "coroutine raised StopIteration" ;
238
+ else {
239
+ if (PyErr_ExceptionMatches (PyExc_StopIteration )) {
240
+ const char * msg = "generator raised StopIteration" ;
241
+ if (PyCoro_CheckExact (gen )) {
242
+ msg = "coroutine raised StopIteration" ;
243
+ }
244
+ else if (PyAsyncGen_CheckExact (gen )) {
245
+ msg = "async generator raised StopIteration" ;
246
+ }
247
+ _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
269
248
}
270
- else if (PyAsyncGen_CheckExact (gen )) {
271
- msg = "async generator raised StopIteration" ;
249
+ else if (PyAsyncGen_CheckExact (gen ) &&
250
+ PyErr_ExceptionMatches (PyExc_StopAsyncIteration ))
251
+ {
252
+ /* code in `gen` raised a StopAsyncIteration error:
253
+ raise a RuntimeError.
254
+ */
255
+ const char * msg = "async generator raised StopAsyncIteration" ;
256
+ _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
272
257
}
273
- _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
274
-
275
- }
276
- else if (!result && PyAsyncGen_CheckExact (gen ) &&
277
- PyErr_ExceptionMatches (PyExc_StopAsyncIteration ))
278
- {
279
- /* code in `gen` raised a StopAsyncIteration error:
280
- raise a RuntimeError.
281
- */
282
- const char * msg = "async generator raised StopAsyncIteration" ;
283
- _PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
284
258
}
285
259
286
- if ((is_return_value && * is_return_value ) || !result || _PyFrameHasCompleted (f )) {
287
- /* generator can't be rerun, so release the frame */
288
- /* first clean reference cycle through stored exception traceback */
289
- _PyErr_ClearExcState (& gen -> gi_exc_state );
290
- gen -> gi_frame -> f_gen = NULL ;
291
- gen -> gi_frame = NULL ;
292
- Py_DECREF (f );
293
- }
260
+ /* generator can't be rerun, so release the frame */
261
+ /* first clean reference cycle through stored exception traceback */
262
+ _PyErr_ClearExcState (& gen -> gi_exc_state );
263
+ gen -> gi_frame -> f_gen = NULL ;
264
+ gen -> gi_frame = NULL ;
265
+ Py_DECREF (f );
266
+
267
+ * presult = result ;
268
+ return result ? PYGEN_RETURN : PYGEN_ERROR ;
269
+ }
270
+
271
+ PySendResult
272
+ PyGen_Send (PyGenObject * gen , PyObject * arg , PyObject * * result )
273
+ {
274
+ assert (PyGen_CheckExact (gen ) || PyCoro_CheckExact (gen ));
275
+ assert (result != NULL );
276
+ assert (arg != NULL );
277
+
278
+ return gen_send_ex2 (gen , arg , result , 0 , 0 );
279
+ }
294
280
281
+ static PyObject *
282
+ gen_send_ex (PyGenObject * gen , PyObject * arg , int exc , int closing )
283
+ {
284
+ PyObject * result ;
285
+ if (gen_send_ex2 (gen , arg , & result , exc , closing ) == PYGEN_RETURN ) {
286
+ if (PyAsyncGen_CheckExact (gen )) {
287
+ assert (result == Py_None );
288
+ PyErr_SetNone (PyExc_StopAsyncIteration );
289
+ }
290
+ else if (result == Py_None ) {
291
+ PyErr_SetNone (PyExc_StopIteration );
292
+ }
293
+ else {
294
+ _PyGen_SetStopIterationValue (result );
295
+ }
296
+ Py_CLEAR (result );
297
+ }
295
298
return result ;
296
299
}
297
300
298
301
PyDoc_STRVAR (send_doc ,
299
302
"send(arg) -> send 'arg' into generator,\n\
300
303
return next yielded value or raise StopIteration." );
301
304
302
- PyObject *
303
- _PyGen_Send (PyGenObject * gen , PyObject * arg )
305
+ static PyObject *
306
+ gen_send (PyGenObject * gen , PyObject * arg )
304
307
{
305
- return gen_send_ex (gen , arg , 0 , 0 , NULL );
308
+ return gen_send_ex (gen , arg , 0 , 0 );
306
309
}
307
310
308
- PySendResult
309
- PyGen_Send (PyGenObject * gen , PyObject * arg , PyObject * * result )
311
+ PyObject *
312
+ _PyGen_Send (PyGenObject * gen , PyObject * arg )
310
313
{
311
- assert (result != NULL );
312
-
313
- int is_return_value = 0 ;
314
- if ((* result = gen_send_ex (gen , arg , 0 , 0 , & is_return_value )) == NULL ) {
315
- return PYGEN_ERROR ;
316
- }
317
- return is_return_value ? PYGEN_RETURN : PYGEN_NEXT ;
314
+ return gen_send (gen , arg );
318
315
}
319
316
320
317
PyDoc_STRVAR (close_doc ,
@@ -396,7 +393,7 @@ gen_close(PyGenObject *gen, PyObject *args)
396
393
}
397
394
if (err == 0 )
398
395
PyErr_SetNone (PyExc_GeneratorExit );
399
- retval = gen_send_ex (gen , Py_None , 1 , 1 , NULL );
396
+ retval = gen_send_ex (gen , Py_None , 1 , 1 );
400
397
if (retval ) {
401
398
const char * msg = "generator ignored GeneratorExit" ;
402
399
if (PyCoro_CheckExact (gen )) {
@@ -444,7 +441,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
444
441
gen -> gi_frame -> f_state = state ;
445
442
Py_DECREF (yf );
446
443
if (err < 0 )
447
- return gen_send_ex (gen , Py_None , 1 , 0 , NULL );
444
+ return gen_send_ex (gen , Py_None , 1 , 0 );
448
445
goto throw_here ;
449
446
}
450
447
if (PyGen_CheckExact (yf ) || PyCoro_CheckExact (yf )) {
@@ -496,10 +493,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
496
493
assert (gen -> gi_frame -> f_lasti >= 0 );
497
494
gen -> gi_frame -> f_lasti += sizeof (_Py_CODEUNIT );
498
495
if (_PyGen_FetchStopIterationValue (& val ) == 0 ) {
499
- ret = gen_send_ex (gen , val , 0 , 0 , NULL );
496
+ ret = gen_send (gen , val );
500
497
Py_DECREF (val );
501
498
} else {
502
- ret = gen_send_ex (gen , Py_None , 1 , 0 , NULL );
499
+ ret = gen_send_ex (gen , Py_None , 1 , 0 );
503
500
}
504
501
}
505
502
return ret ;
@@ -553,7 +550,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
553
550
}
554
551
555
552
PyErr_Restore (typ , val , tb );
556
- return gen_send_ex (gen , Py_None , 1 , 0 , NULL );
553
+ return gen_send_ex (gen , Py_None , 1 , 0 );
557
554
558
555
failed_throw :
559
556
/* Didn't use our arguments, so restore their original refcounts */
@@ -582,7 +579,15 @@ gen_throw(PyGenObject *gen, PyObject *args)
582
579
static PyObject *
583
580
gen_iternext (PyGenObject * gen )
584
581
{
585
- return gen_send_ex (gen , NULL , 0 , 0 , NULL );
582
+ PyObject * result ;
583
+ assert (PyGen_CheckExact (gen ) || PyCoro_CheckExact (gen ));
584
+ if (gen_send_ex2 (gen , NULL , & result , 0 , 0 ) == PYGEN_RETURN ) {
585
+ if (result != Py_None ) {
586
+ _PyGen_SetStopIterationValue (result );
587
+ }
588
+ Py_CLEAR (result );
589
+ }
590
+ return result ;
586
591
}
587
592
588
593
/*
@@ -767,7 +772,7 @@ static PyMemberDef gen_memberlist[] = {
767
772
};
768
773
769
774
static PyMethodDef gen_methods [] = {
770
- {"send" ,(PyCFunction )_PyGen_Send , METH_O , send_doc },
775
+ {"send" ,(PyCFunction )gen_send , METH_O , send_doc },
771
776
{"throw" ,(PyCFunction )gen_throw , METH_VARARGS , throw_doc },
772
777
{"close" ,(PyCFunction )gen_close , METH_NOARGS , close_doc },
773
778
{NULL , NULL } /* Sentinel */
@@ -1082,13 +1087,13 @@ coro_wrapper_dealloc(PyCoroWrapper *cw)
1082
1087
static PyObject *
1083
1088
coro_wrapper_iternext (PyCoroWrapper * cw )
1084
1089
{
1085
- return gen_send_ex ((PyGenObject * )cw -> cw_coroutine , NULL , 0 , 0 , NULL );
1090
+ return gen_iternext ((PyGenObject * )cw -> cw_coroutine );
1086
1091
}
1087
1092
1088
1093
static PyObject *
1089
1094
coro_wrapper_send (PyCoroWrapper * cw , PyObject * arg )
1090
1095
{
1091
- return gen_send_ex ((PyGenObject * )cw -> cw_coroutine , arg , 0 , 0 , NULL );
1096
+ return gen_send ((PyGenObject * )cw -> cw_coroutine , arg );
1092
1097
}
1093
1098
1094
1099
static PyObject *
@@ -1601,7 +1606,7 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
1601
1606
}
1602
1607
1603
1608
o -> ags_gen -> ag_running_async = 1 ;
1604
- result = gen_send_ex ((PyGenObject * )o -> ags_gen , arg , 0 , 0 , NULL );
1609
+ result = gen_send ((PyGenObject * )o -> ags_gen , arg );
1605
1610
result = async_gen_unwrap_value (o -> ags_gen , result );
1606
1611
1607
1612
if (result == NULL ) {
@@ -1957,7 +1962,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
1957
1962
1958
1963
assert (o -> agt_state == AWAITABLE_STATE_ITER );
1959
1964
1960
- retval = gen_send_ex ((PyGenObject * )gen , arg , 0 , 0 , NULL );
1965
+ retval = gen_send ((PyGenObject * )gen , arg );
1961
1966
if (o -> agt_args ) {
1962
1967
return async_gen_unwrap_value (o -> agt_gen , retval );
1963
1968
} else {
0 commit comments