diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 075e1802bebc3e..1536af15440575 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -2804,6 +2804,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 legacy_coro(): + # return a generator iterator so types.coroutine + # wraps it into types._GeneratorWrapper. + return gen() + + g = legacy_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 f96c75b46daba7..73a69c40c8d4b8 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -276,10 +276,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.