https://github.com/python/cpython/commit/6293e1e7b44bd10aca3666f9723bc0e3bd70c732
commit: 6293e1e7b44bd10aca3666f9723bc0e3bd70c732
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-01-20T12:59:42+02:00
summary:

[3.14] gh-143999: Fix: handle suspended state on types.coroutine wrappers 
(GH-144000) (GH-144066)

(cherry picked from commit 76b484b9d16d6a3b1749dc89d99773b5b4a5c4a5)

Co-authored-by: Yongtao Huang <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst
M Lib/test/test_inspect/test_inspect.py
M Lib/types.py

diff --git a/Lib/test/test_inspect/test_inspect.py 
b/Lib/test/test_inspect/test_inspect.py
index 1ba253db48151e..35e31cd5ed1cf4 100644
--- a/Lib/test/test_inspect/test_inspect.py
+++ b/Lib/test/test_inspect/test_inspect.py
@@ -2757,6 +2757,30 @@ def running_check_generator():
         # Running after the first yield
         next(self.generator)
 
+    def test_types_coroutine_wrapper_state(self):
+        def gen():
+            yield 1
+            yield 2
+
+        @types.coroutine
+        def wrapped_generator_coro():
+            # return a generator iterator so types.coroutine
+            # wraps it into types._GeneratorWrapper.
+            return gen()
+
+        g = wrapped_generator_coro()
+        self.addCleanup(g.close)
+        self.assertIs(type(g), types._GeneratorWrapper)
+
+        # _GeneratorWrapper must provide gi_suspended/cr_suspended
+        # so inspect.get*state() doesn't raise AttributeError.
+        self.assertEqual(inspect.getgeneratorstate(g), inspect.GEN_CREATED)
+        self.assertEqual(inspect.getcoroutinestate(g), inspect.CORO_CREATED)
+
+        next(g)
+        self.assertEqual(inspect.getgeneratorstate(g), inspect.GEN_SUSPENDED)
+        self.assertEqual(inspect.getcoroutinestate(g), inspect.CORO_SUSPENDED)
+
     def test_easy_debugging(self):
         # repr() and str() of a generator state should contain the state name
         names = 'GEN_CREATED GEN_RUNNING GEN_SUSPENDED GEN_CLOSED'.split()
diff --git a/Lib/types.py b/Lib/types.py
index 6efac3394345a5..fa6324fb434db5 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -274,10 +274,14 @@ def gi_running(self):
     @property
     def gi_yieldfrom(self):
         return self.__wrapped.gi_yieldfrom
+    @property
+    def gi_suspended(self):
+        return self.__wrapped.gi_suspended
     cr_code = gi_code
     cr_frame = gi_frame
     cr_running = gi_running
     cr_await = gi_yieldfrom
+    cr_suspended = gi_suspended
     def __next__(self):
         return next(self.__wrapped)
     def __iter__(self):
diff --git 
a/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst 
b/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst
new file mode 100644
index 00000000000000..dc87411aacc821
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst
@@ -0,0 +1 @@
+Fix an issue where :func:`inspect.getgeneratorstate` and 
:func:`inspect.getcoroutinestate` could fail for generators wrapped by 
:func:`types.coroutine` in the suspended state.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to