Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7eff607

Browse files
[3.12] gh-111058: Change coro.cr_frame/gen.gi_frame to be None for a closed coroutine/generator. (GH-112428) (#112589)
1 parent edce0c4 commit 7eff607

File tree

5 files changed

+22
-1
lines changed

5 files changed

+22
-1
lines changed

Include/internal/pycore_frame.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ typedef enum _framestate {
3939
FRAME_CLEARED = 4
4040
} PyFrameState;
4141

42+
#define FRAME_STATE_FINISHED(S) ((S) >= FRAME_COMPLETED)
43+
4244
enum _frameowner {
4345
FRAME_OWNED_BY_THREAD = 0,
4446
FRAME_OWNED_BY_GENERATOR = 1,

Lib/test/test_coroutines.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,14 @@ async def f():
22162216
gen.cr_frame.clear()
22172217
gen.close()
22182218

2219+
def test_cr_frame_after_close(self):
2220+
async def f():
2221+
pass
2222+
gen = f()
2223+
self.assertIsNotNone(gen.cr_frame)
2224+
gen.close()
2225+
self.assertIsNone(gen.cr_frame)
2226+
22192227
def test_stack_in_coroutine_throw(self):
22202228
# Regression test for https://github.com/python/cpython/issues/93592
22212229
async def a():

Lib/test/test_inspect/test_inspect.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,6 +2264,10 @@ def test_closed_after_immediate_exception(self):
22642264
self.generator.throw(RuntimeError)
22652265
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
22662266

2267+
def test_closed_after_close(self):
2268+
self.generator.close()
2269+
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
2270+
22672271
def test_running(self):
22682272
# As mentioned on issue #10220, checking for the RUNNING state only
22692273
# makes sense inside the generator itself.
@@ -2373,6 +2377,10 @@ def test_closed_after_immediate_exception(self):
23732377
self.coroutine.throw(RuntimeError)
23742378
self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED)
23752379

2380+
def test_closed_after_close(self):
2381+
self.coroutine.close()
2382+
self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED)
2383+
23762384
def test_easy_debugging(self):
23772385
# repr() and str() of a coroutine state should contain the state name
23782386
names = 'CORO_CREATED CORO_RUNNING CORO_SUSPENDED CORO_CLOSED'.split()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Change coro.cr_frame/gen.gi_frame to return ``None`` after the coroutine/generator has been closed.
2+
This fixes a bug where :func:`~inspect.getcoroutinestate` and :func:`~inspect.getgeneratorstate`
3+
return the wrong state for a closed coroutine/generator.

Objects/genobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ _gen_getframe(PyGenObject *gen, const char *const name)
750750
if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
751751
return NULL;
752752
}
753-
if (gen->gi_frame_state == FRAME_CLEARED) {
753+
if (FRAME_STATE_FINISHED(gen->gi_frame_state)) {
754754
Py_RETURN_NONE;
755755
}
756756
return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((_PyInterpreterFrame *)gen->gi_iframe));

0 commit comments

Comments
 (0)