Skip to content

Commit

Permalink
revert deprecation, treat as bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
iritkatriel committed Nov 6, 2023
1 parent 07b480a commit 4196b0a
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 45 deletions.
14 changes: 5 additions & 9 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1206,26 +1206,22 @@ by writing to f_lineno.

Frame objects support one method:

.. method:: frame.clear([raise_if_suspended])
.. method:: frame.clear()

This method clears all references to local variables held by the
frame. Also, if the frame belonged to a generator, the generator
is finalized. This helps break reference cycles involving frame
objects (for example when catching an exception and storing its
traceback for later use).

:exc:`RuntimeError` is raised if the frame is currently executing.

Clearing a suspended frame is deprecated.
The optional argument *raise_if_suspended* can be passed ``True`` to
make this function raise a :exc:`RuntimeError` instead of issuing a
deprecation warning if the frame is suspended.
:exc:`RuntimeError` is raised if the frame is currently executing
or suspended.

.. versionadded:: 3.4

.. versionchanged:: 3.13
Clearing a suspended frame is deprecated. Added the *raise_if_suspended*
argument.
Attempting to clear a suspended frame raises :exc:`RuntimeError`.


.. _traceback-objects:

Expand Down
3 changes: 2 additions & 1 deletion Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ 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 is deprecated.
* 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`.)


Expand Down
23 changes: 8 additions & 15 deletions Lib/test/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import threading
import types
import unittest
import warnings
import weakref
try:
import _testcapi
Expand Down Expand Up @@ -84,17 +83,13 @@ def g():

# Raise exception when attempting to clear a suspended frame
with self.assertRaisesRegex(RuntimeError, r'suspended frame'):
gen.gi_frame.clear(True)
gen.gi_frame.clear()
self.assertFalse(endly)

# Clearing the frame closes the generator
try:
with self.assertWarnsRegex(DeprecationWarning, r'suspended frame'):
gen.gi_frame.clear()
except DeprecationWarning:
# Suppress the warning when running with -We
pass
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.
Expand Down Expand Up @@ -126,12 +121,10 @@ def g():
gen = g()
f = next(gen)
self.assertFalse(endly)
# Clearing the frame closes the generator
with warnings.catch_warnings():
warnings.filterwarnings('ignore', category=DeprecationWarning)
# Cannot clear a suspended frame
with self.assertRaisesRegex(RuntimeError, 'suspended frame'):
f.clear()

self.assertTrue(endly)
self.assertFalse(endly)

def test_lineno_with_tracing(self):
def record_line():
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Deprecate clearing a suspended frame.
Raise exception if :meth:`frame.clear` is called on a suspended frame.
26 changes: 7 additions & 19 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,31 +933,15 @@ frame_tp_clear(PyFrameObject *f)
}

static PyObject *
frame_clear(PyFrameObject *f, PyObject *args, PyObject *kwds)
frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
{
bool raise_if_suspended = false;
PyObject *v = NULL;
if (!PyArg_UnpackTuple(args, "clear", 0, 1, &v)) {
return NULL;
}
if (v != NULL && PyObject_IsTrue(v)) {
raise_if_suspended = true;
}

if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) {
PyGenObject *gen = _PyFrame_GetGenerator(f->f_frame);
if (gen->gi_frame_state == FRAME_EXECUTING) {
goto running;
}
if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) {
if (raise_if_suspended) {
PyErr_SetString(PyExc_RuntimeError, "cannot clear a suspended frame");
return NULL;
}
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"clearing a suspended frame is deprecated", 1) < 0) {
return NULL;
}
goto suspended;
}
_PyGen_Finalize((PyObject *)gen);
}
Expand All @@ -973,6 +957,10 @@ frame_clear(PyFrameObject *f, PyObject *args, PyObject *kwds)
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__,
Expand Down Expand Up @@ -1002,7 +990,7 @@ frame_repr(PyFrameObject *f)
}

static PyMethodDef frame_methods[] = {
{"clear", (PyCFunction)frame_clear, METH_VARARGS,
{"clear", (PyCFunction)frame_clear, METH_NOARGS,
clear__doc__},
{"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS,
sizeof__doc__},
Expand Down

0 comments on commit 4196b0a

Please sign in to comment.