summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/reference/datamodel.rst7
-rw-r--r--Doc/whatsnew/3.13.rst4
-rw-r--r--Lib/test/test_frame.py15
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst1
-rw-r--r--Objects/frameobject.c7
5 files changed, 27 insertions, 7 deletions
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 9e9fe83..f7d3d2d 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1214,10 +1214,15 @@ Frame objects support one method:
objects (for example when catching an exception and storing its
traceback for later use).
- :exc:`RuntimeError` is raised if the frame is currently executing.
+ :exc:`RuntimeError` is raised if the frame is currently executing
+ or suspended.
.. versionadded:: 3.4
+ .. versionchanged:: 3.13
+ Attempting to clear a suspended frame raises :exc:`RuntimeError`
+ (as has always been the case for executing frames).
+
.. _traceback-objects:
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index e12c2a1..ef83f66 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -397,6 +397,10 @@ Deprecated
and methods that consider plural forms even if the translation was not found.
(Contributed by Serhiy Storchaka in :gh:`88434`.)
+* Calling :meth:`frame.clear` on a suspended frame raises :exc:`RuntimeError`
+ (as has always been the case for an executing frame).
+ (Contributed by Irit Katriel in :gh:`79932`.)
+
Pending Removal in Python 3.14
------------------------------
diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py
index 9491c7f..7f17666 100644
--- a/Lib/test/test_frame.py
+++ b/Lib/test/test_frame.py
@@ -80,9 +80,11 @@ class ClearTest(unittest.TestCase):
gen = g()
next(gen)
self.assertFalse(endly)
- # Clearing the frame closes the generator
- gen.gi_frame.clear()
- self.assertTrue(endly)
+
+ # Cannot clear a suspended frame
+ with self.assertRaisesRegex(RuntimeError, r'suspended frame'):
+ gen.gi_frame.clear()
+ self.assertFalse(endly)
def test_clear_executing(self):
# Attempting to clear an executing frame is forbidden.
@@ -114,9 +116,10 @@ class ClearTest(unittest.TestCase):
gen = g()
f = next(gen)
self.assertFalse(endly)
- # Clearing the frame closes the generator
- f.clear()
- self.assertTrue(endly)
+ # Cannot clear a suspended frame
+ with self.assertRaisesRegex(RuntimeError, 'suspended frame'):
+ f.clear()
+ self.assertFalse(endly)
def test_lineno_with_tracing(self):
def record_line():
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst
new file mode 100644
index 0000000..543dbe4
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-11-06-16-44-09.gh-issue-79932.2qv7uD.rst
@@ -0,0 +1 @@
+Raise exception if :meth:`frame.clear` is called on a suspended frame.
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 3a10f62..be330a7 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -937,6 +937,9 @@ frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
if (gen->gi_frame_state == FRAME_EXECUTING) {
goto running;
}
+ if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) {
+ goto suspended;
+ }
_PyGen_Finalize((PyObject *)gen);
}
else if (f->f_frame->owner == FRAME_OWNED_BY_THREAD) {
@@ -951,6 +954,10 @@ running:
PyErr_SetString(PyExc_RuntimeError,
"cannot clear an executing frame");
return NULL;
+suspended:
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot clear a suspended frame");
+ return NULL;
}
PyDoc_STRVAR(clear__doc__,