Skip to content

Commit 18b5dd6

Browse files
authored
bpo-46836: Move PyFrameObject to pycore_frame.h (GH-31530)
Move the PyFrameObject type definition (struct _frame) to the internal C API pycore_frame.h header file.
1 parent 4657bf7 commit 18b5dd6

File tree

5 files changed

+58
-49
lines changed

5 files changed

+58
-49
lines changed

Doc/c-api/veryhigh.rst

+10-2
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,16 @@ the same library that the Python runtime is using.
288288
289289
.. c:type:: PyFrameObject
290290
291-
The C structure of the objects used to describe frame objects. The
292-
fields of this type are subject to change at any time.
291+
The C structure of the objects used to describe frame objects.
292+
293+
The structure is only part of the internal C API: fields should not be
294+
access directly. Use getter functions like :c:func:`PyFrame_GetCode` and
295+
:c:func:`PyFrame_GetBack`.
296+
297+
Debuggers and profilers can use the limited C API to access this structure.
298+
299+
.. versionchanged:: 3.11
300+
The structure moved to the internal C API headers.
293301
294302
295303
.. c:function:: PyObject* PyEval_EvalFrame(PyFrameObject *f)

Doc/whatsnew/3.11.rst

+34-34
Original file line numberDiff line numberDiff line change
@@ -837,40 +837,40 @@ Porting to Python 3.11
837837
which are not available in the limited C API.
838838
(Contributed by Victor Stinner in :issue:`46007`.)
839839

840-
* Changes of the private :c:type:`PyFrameObject` structure members.
840+
* The :c:type:`PyFrameObject` structure member has been moved to the internal C
841+
API headers.
841842

842-
While the documentation notes that the fields of ``PyFrameObject`` are
843-
subject to change at any time, they have been stable for a long time
844-
and were used in several popular extensions.
845-
In Python 3.11, the frame struct was reorganized to allow performance
846-
optimizations. Rather than reading the fields directly, extensions should
847-
use functions:
843+
While the documentation notes that the :c:type:`PyFrameObject` fields are
844+
subject to change at any time, they have been stable for a long time and were
845+
used in several popular extensions.
848846

849-
* ``f_code``: removed, use :c:func:`PyFrame_GetCode` instead.
850-
Warning: the function returns a :term:`strong reference`, need to call
851-
:c:func:`Py_DECREF`.
852-
* ``f_back``: changed (see below), use :c:func:`PyFrame_GetBack`.
853-
* ``f_builtins``: removed,
854-
use ``PyObject_GetAttrString((PyObject*)frame, "f_builtins")``.
855-
* ``f_globals``: removed,
856-
use ``PyObject_GetAttrString((PyObject*)frame, "f_globals")``.
857-
* ``f_locals``: removed,
858-
use ``PyObject_GetAttrString((PyObject*)frame, "f_locals")``.
859-
* ``f_lasti``: removed,
860-
use ``PyObject_GetAttrString((PyObject*)frame, "f_lasti")``.
861-
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` should use
847+
In Python 3.11, the frame struct was reorganized to allow performance
848+
optimizations. Some fields were removed entirely, as they were details of the
849+
old implementation.
850+
851+
:c:type:`PyFrameObject` fields:
852+
853+
* ``f_back``: use :c:func:`PyFrame_GetBack`.
854+
* ``f_blockstack``: removed.
855+
* ``f_builtins``: use ``PyObject_GetAttrString((PyObject*)frame, "f_builtins")``.
856+
* ``f_code``: use :c:func:`PyFrame_GetCode`.
857+
* ``f_gen``: removed.
858+
* ``f_globals``: use ``PyObject_GetAttrString((PyObject*)frame, "f_globals")``.
859+
* ``f_iblock``: removed.
860+
* ``f_lasti``: use ``PyObject_GetAttrString((PyObject*)frame, "f_lasti")``.
861+
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` must use
862862
:c:func:`PyFrame_GetLineNumber` instead.
863-
864-
The following fields were removed entirely, as they were details
865-
of the old implementation:
866-
867-
* ``f_valuesstack``
868-
* ``f_stackdepth``
869-
* ``f_gen``
870-
* ``f_iblock``
871-
* ``f_state``
872-
* ``f_blockstack``
873-
* ``f_localsplus``
863+
* ``f_lineno``: use :c:func:`PyFrame_GetLineNumber`
864+
* ``f_locals``: use ``PyObject_GetAttrString((PyObject*)frame, "f_locals")``.
865+
* ``f_stackdepth``: removed.
866+
* ``f_state``: no public API (renamed to ``f_frame.f_state``).
867+
* ``f_trace``: no public API.
868+
* ``f_trace_lines``: use ``PyObject_GetAttrString((PyObject*)frame, "f_trace_lines")``
869+
(it also be modified).
870+
* ``f_trace_opcodes``: use ``PyObject_GetAttrString((PyObject*)frame, "f_trace_opcodes")``
871+
(it also be modified).
872+
* ``f_localsplus``: no public API (renamed to ``f_frame.localsplus``).
873+
* ``f_valuestack``: removed.
874874

875875
The Python frame object is now created lazily. A side effect is that the
876876
``f_back`` member must not be accessed directly, since its value is now also
@@ -897,9 +897,9 @@ Porting to Python 3.11
897897
}
898898
#endif
899899

900-
Or use `the pythoncapi_compat project
901-
<https://github.com/pythoncapi/pythoncapi_compat>`__ to get these APIs
902-
on older Python versions.
900+
Or use the `pythoncapi_compat project
901+
<https://github.com/pythoncapi/pythoncapi_compat>`__ to get these two
902+
functions on older Python versions.
903903

904904
* Changes of the :c:type:`PyThreadState` structure members:
905905

Include/cpython/frameobject.h

-13
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,6 @@
44
# error "this header file must not be included directly"
55
#endif
66

7-
struct _frame {
8-
PyObject_HEAD
9-
PyFrameObject *f_back; /* previous frame, or NULL */
10-
struct _interpreter_frame *f_frame; /* points to the frame data */
11-
PyObject *f_trace; /* Trace function */
12-
int f_lineno; /* Current line number. Only valid if non-zero */
13-
char f_trace_lines; /* Emit per-line trace events? */
14-
char f_trace_opcodes; /* Emit per-opcode trace events? */
15-
char f_owns_frame; /* This frame owns the frame */
16-
/* The frame data, if this frame object owns the frame */
17-
PyObject *_f_frame_data[1];
18-
};
19-
207
/* Standard object interface */
218

229
PyAPI_DATA(PyTypeObject) PyFrame_Type;

Include/internal/pycore_frame.h

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ extern "C" {
66

77
#include <stdbool.h>
88

9+
struct _frame {
10+
PyObject_HEAD
11+
PyFrameObject *f_back; /* previous frame, or NULL */
12+
struct _interpreter_frame *f_frame; /* points to the frame data */
13+
PyObject *f_trace; /* Trace function */
14+
int f_lineno; /* Current line number. Only valid if non-zero */
15+
char f_trace_lines; /* Emit per-line trace events? */
16+
char f_trace_opcodes; /* Emit per-opcode trace events? */
17+
char f_owns_frame; /* This frame owns the frame */
18+
/* The frame data, if this frame object owns the frame */
19+
PyObject *_f_frame_data[1];
20+
};
921

1022
/* runtime lifecycle */
1123

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Move the :c:type:`PyFrameObject` type definition (``struct _frame``) to the
2+
internal C API ``pycore_frame.h`` header file. Patch by Victor Stinner.

0 commit comments

Comments
 (0)