code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
if type.is_pyobject:
code.putln('%s->%s = 0;' % (Naming.cur_scope_cname, save_cname))
- code.putln('%s = __pyx_send_value;' % self.result())
+ code.putln('%s = __pyx_send_value; %s' %
+ (self.result(), code.error_goto_if_null(self.result(), self.pos)))
code.put_incref(self.result(), py_object_type)
class StopIterationNode(Node):
proto="""
static PyObject *__CyGenerator_Next(PyObject *self);
static PyObject *__CyGenerator_Send(PyObject *self, PyObject *value);
+static PyObject *__CyGenerator_Close(PyObject *self);
typedef PyObject *(*__cygenerator_body_t)(PyObject *, PyObject *, int);
""",
impl="""
{
return __CyGenerator_SendEx((struct __CyGenerator *) self, value, 0);
}
+
+static PyObject *__CyGenerator_Close(PyObject *self)
+{
+ struct __CyGenerator *generator = (struct __CyGenerator *) self;
+ PyObject *retval;
+ PyErr_SetNone(PyExc_GeneratorExit);
+ retval = __CyGenerator_SendEx(generator, NULL, 0);
+ if (retval) {
+ Py_DECREF(retval);
+ PyErr_SetString(PyExc_RuntimeError,
+ "generator ignored GeneratorExit");
+ return NULL;
+ }
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)
+ || PyErr_ExceptionMatches(PyExc_GeneratorExit))
+ {
+ PyErr_Clear(); /* ignore these errors */
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return NULL;
+}
""", proto_block='utility_code_proto_before_types')
first_run_label = code.new_label('first_run')
code.use_label(first_run_label)
code.put_label(first_run_label)
+ code.putln('%s' %
+ (code.error_goto_if_null('__pyx_send_value', self.pos)))
if not self.is_generator:
self.generate_argument_parsing_code(env, code)
# If an argument is assigned to in the body, we must
e.func_cname = '__CyGenerator_Send'
e.signature = TypeSlots.binaryfunc
- #e = klass.declare_pyfunction('close', pos)
- #e.func_cname = '__CyGenerator_Close'
- #e.signature = TypeSlots.unaryfunc
+ e = klass.declare_pyfunction('close', pos)
+ e.func_cname = '__CyGenerator_Close'
+ e.signature = TypeSlots.unaryfunc
#e = klass.declare_pyfunction('throw', pos)
#e.func_cname = '__CyGenerator_Throw'
>>> next(x)
Traceback (most recent call last):
StopIteration
+ >>> x = very_simple()
+ >>> x.send(1)
+ Traceback (most recent call last):
+ TypeError: can't send non-None value to a just-started generator
"""
yield 1
+
def simple():
"""
>>> x = simple()
yield i
raise StopIteration
return generator
+
+def test_close():
+ """
+ >>> x = test_close()
+ >>> x.close()
+ >>> x = test_close()
+ >>> next(x)
+ >>> x.close()
+ >>> x.next()
+ Traceback (most recent call last):
+ StopIteration
+ """
+ while True:
+ yield
+
+def test_ignore_close():
+ """
+ >>> x = test_ignore_close()
+ >>> x.close()
+ >>> x = test_ignore_close()
+ >>> next(x)
+ >>> x.close()
+ Traceback (most recent call last):
+ RuntimeError: generator ignored GeneratorExit
+ """
+ try:
+ yield
+ except GeneratorExit:
+ yield
+
+class Foo(object):
+ """
+ >>> obj = Foo()
+ >>> list(obj.simple(1, 2, 3))
+ [1, 2, 3]
+ """
+ def simple(self, *args):
+ for i in args:
+ yield i