gen_getattr: make the gi_running and gi_frame members discoverable (but
not writable -- too dangerous!) from Python code.
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 3646001..86898bb 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -368,7 +368,7 @@
[1, 2, 3, 4]
5-combs of [1, 2, 3, 4]:
-# From the Iterators list, about the types of these things.
+From the Iterators list, about the types of these things.
>>> def g():
... yield 1
@@ -379,7 +379,7 @@
>>> type(i)
<type 'generator'>
>>> dir(i)
-['next']
+['gi_frame', 'gi_running', 'next']
>>> print i.next.__doc__
next() -- get the next value, or raise StopIteration
>>> iter(i) is i
@@ -387,6 +387,26 @@
>>> import types
>>> isinstance(i, types.GeneratorType)
1
+
+And more, added later.
+
+>>> i.gi_running
+0
+>>> type(i.gi_frame)
+<type 'frame'>
+>>> i.gi_running = 42
+Traceback (most recent call last):
+ ...
+TypeError: object has read-only attributes
+>>> def g():
+... yield me.gi_running
+>>> me = g()
+>>> me.gi_running
+0
+>>> me.next()
+1
+>>> me.gi_running
+0
"""
# Fun tests (for sufficiently warped notions of "fun").
diff --git a/Python/ceval.c b/Python/ceval.c
index e4620ab..a73e4d0 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -115,8 +115,8 @@
PyFrameObject *gi_frame;
- /* True if generator is being executed. */
- int gi_running;
+ /* True if generator is being executed. */
+ int gi_running;
} genobject;
static PyObject *
@@ -207,14 +207,27 @@
static struct PyMethodDef gen_methods[] = {
{"next", (PyCFunction)gen_next, METH_VARARGS,
- "next() -- get the next value, or raise StopIteration"},
+ "next() -- get the next value, or raise StopIteration"},
{NULL, NULL} /* Sentinel */
};
static PyObject *
gen_getattr(genobject *gen, char *name)
{
- return Py_FindMethod(gen_methods, (PyObject *)gen, name);
+ PyObject *result;
+
+ if (strcmp(name, "gi_frame") == 0) {
+ result = (PyObject *)gen->gi_frame;
+ assert(result != NULL);
+ Py_INCREF(result);
+ }
+ else if (strcmp(name, "gi_running") == 0)
+ result = (PyObject *)PyInt_FromLong((long)gen->gi_running);
+ else if (strcmp(name, "__members__") == 0)
+ result = Py_BuildValue("[ss]", "gi_frame", "gi_running");
+ else
+ result = Py_FindMethod(gen_methods, (PyObject *)gen, name);
+ return result;
}
statichere PyTypeObject gentype = {