gen.cr_frame.clear()
gen.close()
+ def test_cr_frame_after_close(self):
+ async def f():
+ pass
+ gen = f()
+ self.assertIsNotNone(gen.cr_frame)
+ gen.close()
+ self.assertIsNone(gen.cr_frame)
+
def test_stack_in_coroutine_throw(self):
# Regression test for https://github.com/python/cpython/issues/93592
async def a():
self.generator.throw(RuntimeError)
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
+ def test_closed_after_close(self):
+ self.generator.close()
+ self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
+
def test_running(self):
# As mentioned on issue #10220, checking for the RUNNING state only
# makes sense inside the generator itself.
self.coroutine.throw(RuntimeError)
self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED)
+ def test_closed_after_close(self):
+ self.coroutine.close()
+ self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED)
+
def test_easy_debugging(self):
# repr() and str() of a coroutine state should contain the state name
names = 'CORO_CREATED CORO_RUNNING CORO_SUSPENDED CORO_CLOSED'.split()
--- /dev/null
+Change coro.cr_frame/gen.gi_frame to return ``None`` after the coroutine/generator has been closed.
+This fixes a bug where :func:`~inspect.getcoroutinestate` and :func:`~inspect.getgeneratorstate`
+return the wrong state for a closed coroutine/generator.
if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
return NULL;
}
- if (gen->gi_frame_state == FRAME_CLEARED) {
+ if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
Py_RETURN_NONE;
}
return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((_PyInterpreterFrame *)gen->gi_iframe));