]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-120321: Add gi_state, cr_state, and ag_state attributes (gh-144409)
authorSam Gross <colesbury@gmail.com>
Tue, 3 Feb 2026 18:06:32 +0000 (13:06 -0500)
committerGitHub <noreply@github.com>
Tue, 3 Feb 2026 18:06:32 +0000 (13:06 -0500)
Add `gi_state`, `cr_state`, and `ag_state` attributes to generators,
coroutines, and async generators respectively. These attributes return the
current state as a string (e.g., `GEN_RUNNING`, `CORO_SUSPENDED`).

The `inspect.getgeneratorstate()`, `inspect.getcoroutinestate()`, and
`inspect.getasyncgenstate()` functions now return these attributes directly.

This is in preparation for making `gi_frame` thread-safe, which may involve
stop-the-world synchronization. The new state attributes avoid potential
performance cliffs in `inspect.getgeneratorstate()` and similar functions by
not requiring frame access.

Also removes unused `FRAME_COMPLETED` state and renumbers the frame state enum
to start at 0 instead of -1.

12 files changed:
Doc/library/inspect.rst
Include/internal/pycore_frame.h
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Lib/inspect.py
Lib/test/test_generators.py
Lib/types.py
Misc/NEWS.d/next/Core_and_Builtins/2026-02-02-17-50-14.gh-issue-120321.Xfr7tL.rst [new file with mode: 0644]
Objects/genobject.c
Tools/c-analyzer/cpython/ignored.tsv

index 5133f9f0c8e43b4a572f25460b54f652f89a78ab..f6bc904bdab4bd69511ca8f226858544f64f26bb 100644 (file)
@@ -262,6 +262,12 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
 |                 |                   | ``yield from``, or        |
 |                 |                   | ``None``                  |
 +-----------------+-------------------+---------------------------+
+|                 | gi_state          | state of the generator,   |
+|                 |                   | one of ``GEN_CREATED``,   |
+|                 |                   | ``GEN_RUNNING``,          |
+|                 |                   | ``GEN_SUSPENDED``, or     |
+|                 |                   | ``GEN_CLOSED``            |
++-----------------+-------------------+---------------------------+
 | async generator | __name__          | name                      |
 +-----------------+-------------------+---------------------------+
 |                 | __qualname__      | qualified name            |
@@ -278,6 +284,13 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
 +-----------------+-------------------+---------------------------+
 |                 | ag_code           | code                      |
 +-----------------+-------------------+---------------------------+
+|                 | ag_state          | state of the async        |
+|                 |                   | generator, one of         |
+|                 |                   | ``AGEN_CREATED``,         |
+|                 |                   | ``AGEN_RUNNING``,         |
+|                 |                   | ``AGEN_SUSPENDED``, or    |
+|                 |                   | ``AGEN_CLOSED``           |
++-----------------+-------------------+---------------------------+
 | coroutine       | __name__          | name                      |
 +-----------------+-------------------+---------------------------+
 |                 | __qualname__      | qualified name            |
@@ -298,6 +311,12 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
 |                 |                   | created, or ``None``. See |
 |                 |                   | |coroutine-origin-link|   |
 +-----------------+-------------------+---------------------------+
+|                 | cr_state          | state of the coroutine,   |
+|                 |                   | one of ``CORO_CREATED``,  |
+|                 |                   | ``CORO_RUNNING``,         |
+|                 |                   | ``CORO_SUSPENDED``, or    |
+|                 |                   | ``CORO_CLOSED``           |
++-----------------+-------------------+---------------------------+
 | builtin         | __doc__           | documentation string      |
 +-----------------+-------------------+---------------------------+
 |                 | __name__          | original name of this     |
@@ -341,6 +360,11 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
 
    Add ``f_generator`` attribute to frames.
 
+.. versionchanged:: next
+
+   Add ``gi_state`` attribute to generators, ``cr_state`` attribute to
+   coroutines, and ``ag_state`` attribute to async generators.
+
 .. function:: getmembers(object[, predicate])
 
    Return all the members of an object in a list of ``(name, value)``
index 50908f2cb7a1d296ce3d8480893efd0a6eba99e3..5e73ae3c8549b846e49da8be84988a10c7fb46cb 100644 (file)
@@ -44,18 +44,16 @@ extern PyFrameObject* _PyFrame_New_NoTrack(PyCodeObject *code);
 /* other API */
 
 typedef enum _framestate {
-    FRAME_CREATED = -4,
-    FRAME_SUSPENDED = -3,
-    FRAME_SUSPENDED_YIELD_FROM = -2,
-    FRAME_SUSPENDED_YIELD_FROM_LOCKED = -1,
-    FRAME_EXECUTING = 0,
-    FRAME_COMPLETED = 1,
-    FRAME_CLEARED = 4
+    FRAME_CREATED = 0,
+    FRAME_SUSPENDED = 1,
+    FRAME_SUSPENDED_YIELD_FROM = 2,
+    FRAME_SUSPENDED_YIELD_FROM_LOCKED = 3,
+    FRAME_EXECUTING = 4,
+    FRAME_CLEARED = 5
 } PyFrameState;
 
 #define FRAME_STATE_SUSPENDED(S) ((S) >= FRAME_SUSPENDED && (S) <= FRAME_SUSPENDED_YIELD_FROM_LOCKED)
-#define FRAME_STATE_FINISHED(S) ((S) >= FRAME_COMPLETED)
-
+#define FRAME_STATE_FINISHED(S) ((S) == FRAME_CLEARED)
 #ifdef __cplusplus
 }
 #endif
index fc297a2933a7865c14ad6f904f08b630371d6cfb..cb62d9424a86b070751651bebb9ab6a4b1849d16 100644 (file)
@@ -1335,11 +1335,23 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(str_replace_inf));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(AGEN_CLOSED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(AGEN_CREATED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(AGEN_RUNNING));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(AGEN_SUSPENDED));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CORO_CLOSED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CORO_CREATED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CORO_RUNNING));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CORO_SUSPENDED));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(Emax));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(Emin));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(FINISHED));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(False));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(GEN_CLOSED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(GEN_CREATED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(GEN_RUNNING));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(GEN_SUSPENDED));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(JSONDecodeError));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(PENDING));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(Py_Repr));
index 563ccd7cf6d3f4cdf8dda43ba4feeb9659fc6675..92de92079379ea7ac7282efc11b9e59f2b74f74b 100644 (file)
@@ -58,11 +58,23 @@ struct _Py_global_strings {
     } literals;
 
     struct {
+        STRUCT_FOR_ID(AGEN_CLOSED)
+        STRUCT_FOR_ID(AGEN_CREATED)
+        STRUCT_FOR_ID(AGEN_RUNNING)
+        STRUCT_FOR_ID(AGEN_SUSPENDED)
         STRUCT_FOR_ID(CANCELLED)
+        STRUCT_FOR_ID(CORO_CLOSED)
+        STRUCT_FOR_ID(CORO_CREATED)
+        STRUCT_FOR_ID(CORO_RUNNING)
+        STRUCT_FOR_ID(CORO_SUSPENDED)
         STRUCT_FOR_ID(Emax)
         STRUCT_FOR_ID(Emin)
         STRUCT_FOR_ID(FINISHED)
         STRUCT_FOR_ID(False)
+        STRUCT_FOR_ID(GEN_CLOSED)
+        STRUCT_FOR_ID(GEN_CREATED)
+        STRUCT_FOR_ID(GEN_RUNNING)
+        STRUCT_FOR_ID(GEN_SUSPENDED)
         STRUCT_FOR_ID(JSONDecodeError)
         STRUCT_FOR_ID(PENDING)
         STRUCT_FOR_ID(Py_Repr)
index ba7c0e6843451716414004b6e13f2af82bac3a35..dc05495e20d69dbda03f9deaa58cffaf5cb0125b 100644 (file)
@@ -1333,11 +1333,23 @@ extern "C" {
 }
 
 #define _Py_str_identifiers_INIT { \
+    INIT_ID(AGEN_CLOSED), \
+    INIT_ID(AGEN_CREATED), \
+    INIT_ID(AGEN_RUNNING), \
+    INIT_ID(AGEN_SUSPENDED), \
     INIT_ID(CANCELLED), \
+    INIT_ID(CORO_CLOSED), \
+    INIT_ID(CORO_CREATED), \
+    INIT_ID(CORO_RUNNING), \
+    INIT_ID(CORO_SUSPENDED), \
     INIT_ID(Emax), \
     INIT_ID(Emin), \
     INIT_ID(FINISHED), \
     INIT_ID(False), \
+    INIT_ID(GEN_CLOSED), \
+    INIT_ID(GEN_CREATED), \
+    INIT_ID(GEN_RUNNING), \
+    INIT_ID(GEN_SUSPENDED), \
     INIT_ID(JSONDecodeError), \
     INIT_ID(PENDING), \
     INIT_ID(Py_Repr), \
index 44063794293990549805b343a67c0ab8197db35f..10085149f09b6c73c2cfc7299f0190f110c76e45 100644 (file)
@@ -12,10 +12,42 @@ extern "C" {
 static inline void
 _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     PyObject *string;
+    string = &_Py_ID(AGEN_CLOSED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(AGEN_CREATED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(AGEN_RUNNING);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(AGEN_SUSPENDED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(CANCELLED);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(CORO_CLOSED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(CORO_CREATED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(CORO_RUNNING);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(CORO_SUSPENDED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(Emax);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -32,6 +64,22 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(GEN_CLOSED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(GEN_CREATED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(GEN_RUNNING);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(GEN_SUSPENDED);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(JSONDecodeError);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
index 0dba3c6628c6e596cabcd5f6a6b739aa7b4889c7..0eed68d17c702baf6611f5a2bf144070def83542 100644 (file)
@@ -1813,13 +1813,7 @@ def getgeneratorstate(generator):
       GEN_SUSPENDED: Currently suspended at a yield expression.
       GEN_CLOSED: Execution has completed.
     """
-    if generator.gi_running:
-        return GEN_RUNNING
-    if generator.gi_suspended:
-        return GEN_SUSPENDED
-    if generator.gi_frame is None:
-        return GEN_CLOSED
-    return GEN_CREATED
+    return generator.gi_state
 
 
 def getgeneratorlocals(generator):
@@ -1855,13 +1849,7 @@ def getcoroutinestate(coroutine):
       CORO_SUSPENDED: Currently suspended at an await expression.
       CORO_CLOSED: Execution has completed.
     """
-    if coroutine.cr_running:
-        return CORO_RUNNING
-    if coroutine.cr_suspended:
-        return CORO_SUSPENDED
-    if coroutine.cr_frame is None:
-        return CORO_CLOSED
-    return CORO_CREATED
+    return coroutine.cr_state
 
 
 def getcoroutinelocals(coroutine):
@@ -1894,13 +1882,7 @@ def getasyncgenstate(agen):
       AGEN_SUSPENDED: Currently suspended at a yield expression.
       AGEN_CLOSED: Execution has completed.
     """
-    if agen.ag_running:
-        return AGEN_RUNNING
-    if agen.ag_suspended:
-        return AGEN_SUSPENDED
-    if agen.ag_frame is None:
-        return AGEN_CLOSED
-    return AGEN_CREATED
+    return agen.ag_state
 
 
 def getasyncgenlocals(agen):
index c181da2e34991512052312eb8f940b4c397be651..6eb25960101a9e345c74ee1d8134d508ccc3e8c5 100644 (file)
@@ -1366,7 +1366,7 @@ From the Iterators list, about the types of these things.
 >>> type(i)
 <class 'generator'>
 >>> [s for s in dir(i) if not s.startswith('_')]
-['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_suspended', 'gi_yieldfrom', 'send', 'throw']
+['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_state', 'gi_suspended', 'gi_yieldfrom', 'send', 'throw']
 >>> from test.support import HAVE_DOCSTRINGS
 >>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).')
 Implement next(self).
index 73a69c40c8d4b840548475a3c0dd1cfb2e9e9b41..99f23c3f44270f5fada410f042320fa34ea271e3 100644 (file)
@@ -279,6 +279,12 @@ class _GeneratorWrapper:
     @property
     def gi_suspended(self):
         return self.__wrapped.gi_suspended
+    @property
+    def gi_state(self):
+        return self.__wrapped.gi_state
+    @property
+    def cr_state(self):
+        return self.__wrapped.gi_state.replace('GEN_', 'CORO_')
     cr_code = gi_code
     cr_frame = gi_frame
     cr_running = gi_running
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-02-17-50-14.gh-issue-120321.Xfr7tL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-02-17-50-14.gh-issue-120321.Xfr7tL.rst
new file mode 100644 (file)
index 0000000..3e868c8
--- /dev/null
@@ -0,0 +1,5 @@
+Add ``gi_state``, ``cr_state``, and ``ag_state`` attributes to generators,
+coroutines, and async generators that return the current state as a string
+(e.g., ``GEN_RUNNING``). The :mod:`inspect` module functions
+:func:`~inspect.getgeneratorstate`, :func:`~inspect.getcoroutinestate`, and
+:func:`~inspect.getasyncgenstate` now return these attributes directly.
index 5ff4618255c852f9664b84674751733cf40bc6aa..5088500fc4142b8a3b170f5049f59ab8e64054fa 100644 (file)
@@ -926,6 +926,26 @@ gen_getsuspended(PyObject *self, void *Py_UNUSED(ignored))
     return FRAME_STATE_SUSPENDED(frame_state) ? Py_True : Py_False;
 }
 
+static PyObject *
+gen_getstate(PyObject *self, void *Py_UNUSED(ignored))
+{
+    PyGenObject *gen = _PyGen_CAST(self);
+    int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state);
+
+    static PyObject *const state_strings[] = {
+        [FRAME_CREATED] = &_Py_ID(GEN_CREATED),
+        [FRAME_SUSPENDED] = &_Py_ID(GEN_SUSPENDED),
+        [FRAME_SUSPENDED_YIELD_FROM] = &_Py_ID(GEN_SUSPENDED),
+        [FRAME_SUSPENDED_YIELD_FROM_LOCKED] = &_Py_ID(GEN_SUSPENDED),
+        [FRAME_EXECUTING] = &_Py_ID(GEN_RUNNING),
+        [FRAME_CLEARED] = &_Py_ID(GEN_CLOSED),
+    };
+
+    assert(frame_state >= 0 &&
+           (size_t)frame_state < Py_ARRAY_LENGTH(state_strings));
+    return state_strings[frame_state];
+}
+
 static PyObject *
 _gen_getframe(PyGenObject *gen, const char *const name)
 {
@@ -974,6 +994,8 @@ static PyGetSetDef gen_getsetlist[] = {
     {"gi_frame", gen_getframe,  NULL, NULL},
     {"gi_suspended", gen_getsuspended,  NULL, NULL},
     {"gi_code", gen_getcode,  NULL, NULL},
+    {"gi_state", gen_getstate, NULL,
+     PyDoc_STR("state of the generator")},
     {NULL} /* Sentinel */
 };
 
@@ -1291,6 +1313,26 @@ cr_getcode(PyObject *coro, void *Py_UNUSED(ignored))
     return _gen_getcode(_PyGen_CAST(coro), "cr_code");
 }
 
+static PyObject *
+cr_getstate(PyObject *self, void *Py_UNUSED(ignored))
+{
+    PyGenObject *gen = _PyGen_CAST(self);
+    int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state);
+
+    static PyObject *const state_strings[] = {
+        [FRAME_CREATED] = &_Py_ID(CORO_CREATED),
+        [FRAME_SUSPENDED] = &_Py_ID(CORO_SUSPENDED),
+        [FRAME_SUSPENDED_YIELD_FROM] = &_Py_ID(CORO_SUSPENDED),
+        [FRAME_SUSPENDED_YIELD_FROM_LOCKED] = &_Py_ID(CORO_SUSPENDED),
+        [FRAME_EXECUTING] = &_Py_ID(CORO_RUNNING),
+        [FRAME_CLEARED] = &_Py_ID(CORO_CLOSED),
+    };
+
+    assert(frame_state >= 0 &&
+           (size_t)frame_state < Py_ARRAY_LENGTH(state_strings));
+    return state_strings[frame_state];
+}
+
 static PyGetSetDef coro_getsetlist[] = {
     {"__name__", gen_get_name, gen_set_name,
      PyDoc_STR("name of the coroutine")},
@@ -1302,6 +1344,8 @@ static PyGetSetDef coro_getsetlist[] = {
     {"cr_frame", cr_getframe, NULL, NULL},
     {"cr_code", cr_getcode, NULL, NULL},
     {"cr_suspended", gen_getsuspended, NULL, NULL},
+    {"cr_state", cr_getstate, NULL,
+     PyDoc_STR("state of the coroutine")},
     {NULL} /* Sentinel */
 };
 
@@ -1717,6 +1761,26 @@ ag_getcode(PyObject *gen, void *Py_UNUSED(ignored))
     return _gen_getcode((PyGenObject*)gen, "ag_code");
 }
 
+static PyObject *
+ag_getstate(PyObject *self, void *Py_UNUSED(ignored))
+{
+    PyGenObject *gen = _PyGen_CAST(self);
+    int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state);
+
+    static PyObject *const state_strings[] = {
+        [FRAME_CREATED] = &_Py_ID(AGEN_CREATED),
+        [FRAME_SUSPENDED] = &_Py_ID(AGEN_SUSPENDED),
+        [FRAME_SUSPENDED_YIELD_FROM] = &_Py_ID(AGEN_SUSPENDED),
+        [FRAME_SUSPENDED_YIELD_FROM_LOCKED] = &_Py_ID(AGEN_SUSPENDED),
+        [FRAME_EXECUTING] = &_Py_ID(AGEN_RUNNING),
+        [FRAME_CLEARED] = &_Py_ID(AGEN_CLOSED),
+    };
+
+    assert(frame_state >= 0 &&
+           (size_t)frame_state < Py_ARRAY_LENGTH(state_strings));
+    return state_strings[frame_state];
+}
+
 static PyGetSetDef async_gen_getsetlist[] = {
     {"__name__", gen_get_name, gen_set_name,
      PyDoc_STR("name of the async generator")},
@@ -1727,6 +1791,8 @@ static PyGetSetDef async_gen_getsetlist[] = {
      {"ag_frame", ag_getframe, NULL, NULL},
      {"ag_code", ag_getcode, NULL, NULL},
      {"ag_suspended", gen_getsuspended, NULL, NULL},
+     {"ag_state", ag_getstate, NULL,
+      PyDoc_STR("state of the async generator")},
     {NULL} /* Sentinel */
 };
 
index 6ad3fc5f76e57abc78e67a488ae1557261ff0560..91bbf94990ecc186f54089dfd2e315411f3ba532 100644 (file)
@@ -332,6 +332,9 @@ Objects/complexobject.c     -       c_1     -
 Objects/exceptions.c   -       static_exceptions       -
 Objects/genobject.c    -       ASYNC_GEN_IGNORED_EXIT_MSG      -
 Objects/genobject.c    -       NON_INIT_CORO_MSG       -
+Objects/genobject.c    gen_getstate    state_strings   -
+Objects/genobject.c    cr_getstate     state_strings   -
+Objects/genobject.c    ag_getstate     state_strings   -
 Objects/longobject.c   -       _PyLong_DigitValue      -
 Objects/longobject.c   -       PyLong_LAYOUT   -
 Objects/object.c       -       _Py_SwappedOp   -