@@ -154,12 +154,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
154154 /* Delay exception instantiation if we can */
155155 PyErr_SetNone (PyExc_StopIteration );
156156 } else {
157- PyObject * e = PyObject_CallFunctionObjArgs (
158- PyExc_StopIteration , result , NULL );
159- if (e != NULL ) {
160- PyErr_SetObject (PyExc_StopIteration , e );
161- Py_DECREF (e );
162- }
157+ _PyGen_SetStopIterationValue (result );
163158 }
164159 Py_CLEAR (result );
165160 }
@@ -459,6 +454,43 @@ gen_iternext(PyGenObject *gen)
459454 return gen_send_ex (gen , NULL , 0 , 0 );
460455}
461456
457+ /*
458+ * Set StopIteration with specified value. Value can be arbitrary object
459+ * or NULL.
460+ *
461+ * Returns 0 if StopIteration is set and -1 if any other exception is set.
462+ */
463+ int
464+ _PyGen_SetStopIterationValue (PyObject * value )
465+ {
466+ PyObject * e ;
467+
468+ if (value == NULL ||
469+ (!PyTuple_Check (value ) &&
470+ !PyObject_TypeCheck (value , (PyTypeObject * ) PyExc_StopIteration )))
471+ {
472+ /* Delay exception instantiation if we can */
473+ PyErr_SetObject (PyExc_StopIteration , value );
474+ return 0 ;
475+ }
476+ /* Construct an exception instance manually with
477+ * PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject.
478+ *
479+ * We do this to handle a situation when "value" is a tuple, in which
480+ * case PyErr_SetObject would set the value of StopIteration to
481+ * the first element of the tuple.
482+ *
483+ * (See PyErr_SetObject/_PyErr_CreateException code for details.)
484+ */
485+ e = PyObject_CallFunctionObjArgs (PyExc_StopIteration , value , NULL );
486+ if (e == NULL ) {
487+ return -1 ;
488+ }
489+ PyErr_SetObject (PyExc_StopIteration , e );
490+ Py_DECREF (e );
491+ return 0 ;
492+ }
493+
462494/*
463495 * If StopIteration exception is set, fetches its 'value'
464496 * attribute if any, otherwise sets pvalue to None.
@@ -469,7 +501,8 @@ gen_iternext(PyGenObject *gen)
469501 */
470502
471503int
472- _PyGen_FetchStopIterationValue (PyObject * * pvalue ) {
504+ _PyGen_FetchStopIterationValue (PyObject * * pvalue )
505+ {
473506 PyObject * et , * ev , * tb ;
474507 PyObject * value = NULL ;
475508
@@ -481,8 +514,15 @@ _PyGen_FetchStopIterationValue(PyObject **pvalue) {
481514 value = ((PyStopIterationObject * )ev )-> value ;
482515 Py_INCREF (value );
483516 Py_DECREF (ev );
484- } else if (et == PyExc_StopIteration ) {
485- /* avoid normalisation and take ev as value */
517+ } else if (et == PyExc_StopIteration && !PyTuple_Check (ev )) {
518+ /* Avoid normalisation and take ev as value.
519+ *
520+ * Normalization is required if the value is a tuple, in
521+ * that case the value of StopIteration would be set to
522+ * the first element of the tuple.
523+ *
524+ * (See _PyErr_CreateException code for details.)
525+ */
486526 value = ev ;
487527 } else {
488528 /* normalisation required */
@@ -1012,7 +1052,7 @@ typedef struct {
10121052static PyObject *
10131053aiter_wrapper_iternext (PyAIterWrapper * aw )
10141054{
1015- PyErr_SetObject ( PyExc_StopIteration , aw -> aw_aiter );
1055+ _PyGen_SetStopIterationValue ( aw -> aw_aiter );
10161056 return NULL ;
10171057}
10181058
0 commit comments