Skip to main content

Include/cpython/pyframe.h

cpython 3.14 @ ab2d84fe1023/Include/cpython/pyframe.h

The public C API for Python frame objects. The file exposes PyFrameObject introspection functions (PyFrame_GetBack, PyFrame_GetLocals, PyFrame_GetGlobals, PyFrame_GetBuiltins, PyFrame_GetGenerator, PyFrame_GetLasti, PyFrame_GetVar) alongside the PyUnstable_ family intended for PEP 523 custom evaluators. Since 3.11 the actual activation record is _PyInterpreterFrame (defined in Include/internal/pycore_frame.h); the public PyFrameObject is a thin Python-visible wrapper around it. A companion header, Include/cpython/frameobject.h, declares PyFrame_New, PyFrame_LocalsToFast, and the PyFrameLocalsProxyObject struct.

Map

LinesSymbolRolegopy
5PyFrame_TypeType object singletonobjects.FrameType()
6PyFrameLocalsProxy_TypeType for the locals proxynot yet ported
8PyFrame_CheckInstance check macroimplicit via type comparison
9PyFrameLocalsProxy_CheckInstance check macronot yet ported
11PyFrame_GetBackReturns caller frame (strong ref)(*Frame).Back()
12PyFrame_GetLocalsReturns f_locals mapping (strong ref)InterpreterFrame.FrameLocals()
14PyFrame_GetGlobalsReturns f_globals dict (strong ref)(*Frame).Globals()
15PyFrame_GetBuiltinsReturns f_builtins dict (strong ref)(*Frame).Builtins()
17PyFrame_GetGeneratorReturns owning generator/coroutine, or NULLnot yet ported
18PyFrame_GetLastiReturns byte offset of last executed instruction(*Frame).Lasti()
19PyFrame_GetVarLooks up a local by name (strong ref)not yet ported
20PyFrame_GetVarStringSame but takes a C stringnot yet ported
25struct _PyInterpreterFrame (forward)Forward declaration for PEP 523 APIframe.Frame (package frame/)
29PyUnstable_InterpreterFrame_GetCodeCode object from raw interp framenot yet ported
33PyUnstable_InterpreterFrame_GetLastiByte offset from raw interp framenot yet ported
37PyUnstable_InterpreterFrame_GetLineSource line from raw interp framenot yet ported
39-44PyUnstable_EXECUTABLE_KIND_*Executable kind constants for PEP 523not yet ported
45PyUnstable_ExecutableKindsArray of kind type objectsnot yet ported

Reading

Frame accessor API (lines 11 to 20)

cpython 3.14 @ ab2d84fe1023/Include/cpython/pyframe.h#L11-20

These nine functions are the stable public surface for reading frame state. Every function returns a strong reference (the caller must Py_DECREF it) and none of them raise an exception on success.

PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
PyAPI_FUNC(PyObject *) PyFrame_GetLocals(PyFrameObject *frame);
PyAPI_FUNC(PyObject *) PyFrame_GetGlobals(PyFrameObject *frame);
PyAPI_FUNC(PyObject *) PyFrame_GetBuiltins(PyFrameObject *frame);
PyAPI_FUNC(PyObject *) PyFrame_GetGenerator(PyFrameObject *frame);
PyAPI_FUNC(int) PyFrame_GetLasti(PyFrameObject *frame);
PyAPI_FUNC(PyObject*) PyFrame_GetVar(PyFrameObject *frame, PyObject *name);
PyAPI_FUNC(PyObject*) PyFrame_GetVarString(PyFrameObject *frame, const char *name);

In gopy these map to methods on objects.Frame, each delegating to the InterpreterFrame interface. FrameLocals() materialises a snapshot dict from fast locals, mirroring the lazy evaluation CPython does in PyFrame_GetLocals.

PEP 523 unstable API (lines 25 to 45)

cpython 3.14 @ ab2d84fe1023/Include/cpython/pyframe.h#L25-45

The PyUnstable_InterpreterFrame_* functions operate on the raw _PyInterpreterFrame (the actual activation record managed by the eval loop), not on the Python-visible wrapper. They exist so custom evaluators registered via _PyInterpreterState_SetEvalFrameFunc can inspect the frame they are handed before or instead of calling _PyEval_EvalFrameDefault.

struct _PyInterpreterFrame; /* forward-declared here; full struct is internal */

PyAPI_FUNC(PyObject *) PyUnstable_InterpreterFrame_GetCode(
struct _PyInterpreterFrame *frame);
PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLasti(
struct _PyInterpreterFrame *frame);
PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(
struct _PyInterpreterFrame *frame);

The PyUnstable_ prefix signals that these functions may change signature in any minor release, unlike the rest of the stable ABI. gopy's frame.Frame struct owns the activation record and provides equivalent accessors as Go methods.

Type objects and check macros (lines 5 to 9)

cpython 3.14 @ ab2d84fe1023/Include/cpython/pyframe.h#L5-9

PyAPI_DATA(PyTypeObject) PyFrame_Type;
PyAPI_DATA(PyTypeObject) PyFrameLocalsProxy_Type;

#define PyFrame_Check(op) Py_IS_TYPE((op), &PyFrame_Type)
#define PyFrameLocalsProxy_Check(op) Py_IS_TYPE((op), &PyFrameLocalsProxy_Type)

PyFrame_Type is the C-level singleton for the frame built-in type. gopy exposes it as objects.FrameType(). The locals proxy type wraps the per-frame local variable mapping with copy-on-write semantics introduced in 3.13; gopy does not yet port it.

gopy mirror

objects/frame.go splits the CPython design cleanly: objects.InterpreterFrame is a Go interface that the live activation record in frame/frame.go satisfies, and objects.Frame is the thin Python-visible wrapper. All PyFrame_Get* accessors are present as methods on *Frame. The PyUnstable_* family and PyFrameLocalsProxy_Type are not yet ported because gopy does not yet expose a PEP 523 custom-evaluator hook.

CPython 3.14 changes

The file was split from Include/cpython/frameobject.h in 3.13. The PyFrame_GetCode function (present in 3.11-3.12) was removed from the public API in 3.14; callers should now use PyUnstable_InterpreterFrame_GetCode or retrieve the code object through f_code on the frame. The PyFrameLocalsProxy_Type and its check macro are new in 3.14, reflecting the copy-on-write locals proxy that replaces the old eager dict materialisation.