Skip to content

Commit 7c59d7c

Browse files
authored
bpo-40421: Add pyframe.h header file (GH-19755)
Add a new separated pyframe.h header file of the PyFrame public C API: it is included by Python.h. Add PyFrame_GetLineNumber() to the limited C API. Replace "struct _frame" with "PyFrameObject" in header files. PyFrameObject is now defined as struct _frame by pyframe.h which is included early enough in Python.h.
1 parent 5da3526 commit 7c59d7c

19 files changed

+63
-42
lines changed

Doc/c-api/reflection.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Reflection
3535
3636
Return the line number that *frame* is currently executing.
3737
38+
*frame* must not be ``NULL``.
39+
3840
3941
.. c:function:: const char* PyEval_GetFuncName(PyObject *func)
4042

Doc/whatsnew/3.9.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ Optimizations
537537
Build and C API Changes
538538
=======================
539539

540+
* Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
541+
(Contributed by Victor Stinner in :issue:`40421`.)
542+
540543
* New :c:func:`PyThreadState_GetInterpreter` and
541544
:c:func:`PyInterpreterState_Get` functions to get the interpreter.
542545
New :c:func:`PyThreadState_GetFrame` function to get the current frame of a

Include/Python.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
#include "classobject.h"
115115
#include "fileobject.h"
116116
#include "pycapsule.h"
117+
#include "pyframe.h"
117118
#include "traceback.h"
118119
#include "sliceobject.h"
119120
#include "cellobject.h"

Include/ceval.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@ Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallFunction(
2828
Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallMethod(
2929
PyObject *obj, const char *name, const char *format, ...);
3030

31-
struct _frame; /* Avoid including frameobject.h */
32-
3331
PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void);
3432
PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void);
3533
PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
36-
PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void);
34+
PyAPI_FUNC(PyFrameObject *) PyEval_GetFrame(void);
3735

3836
PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg);
3937
PyAPI_FUNC(int) Py_MakePendingCalls(void);
@@ -80,8 +78,8 @@ PyAPI_FUNC(void) Py_LeaveRecursiveCall(void);
8078
PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *);
8179
PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *);
8280

83-
PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *);
84-
PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc);
81+
PyAPI_FUNC(PyObject *) PyEval_EvalFrame(PyFrameObject *);
82+
PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(PyFrameObject *f, int exc);
8583

8684
/* Interface for threads.
8785

Include/cpython/ceval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *);
2323
flag was set, else return 0. */
2424
PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
2525

26-
PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, struct _frame *f, int exc);
26+
PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int exc);
2727

2828
PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
2929
PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);

Include/cpython/frameobject.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ typedef struct {
1414
int b_level; /* value stack level to pop to */
1515
} PyTryBlock;
1616

17-
typedef struct _frame {
17+
struct _frame {
1818
PyObject_VAR_HEAD
1919
struct _frame *f_back; /* previous frame, or NULL */
2020
PyCodeObject *f_code; /* code segment */
@@ -44,7 +44,7 @@ typedef struct _frame {
4444
char f_executing; /* whether the frame is still executing */
4545
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
4646
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
47-
} PyFrameObject;
47+
};
4848

4949

5050
/* Standard object interface */
@@ -79,9 +79,6 @@ PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
7979

8080
PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
8181

82-
/* Return the line of code the frame is currently executing. */
83-
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
84-
8582
#ifdef __cplusplus
8683
}
8784
#endif

Include/cpython/pystate.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *);
1616
/* State unique per thread */
1717

1818
/* Py_tracefunc return -1 when raising an exception, or 0 for success. */
19-
typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *);
19+
typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
2020

2121
/* The following values are used for 'what' for tracefunc functions
2222
*
@@ -56,7 +56,7 @@ struct _ts {
5656
PyInterpreterState *interp;
5757

5858
/* Borrowed reference to the current frame (it can be NULL) */
59-
struct _frame *frame;
59+
PyFrameObject *frame;
6060
int recursion_depth;
6161
char overflowed; /* The stack has overflowed. Allow 50 more calls
6262
to handle the runtime error. */
@@ -184,7 +184,7 @@ PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void);
184184

185185
/* Frame evaluation API */
186186

187-
typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, struct _frame *, int);
187+
typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *, int);
188188

189189
PyAPI_FUNC(_PyFrameEvalFunction) _PyInterpreterState_GetEvalFrameFunc(
190190
PyInterpreterState *interp);

Include/cpython/traceback.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ extern "C" {
99
typedef struct _traceback {
1010
PyObject_HEAD
1111
struct _traceback *tb_next;
12-
struct _frame *tb_frame;
12+
PyFrameObject *tb_frame;
1313
int tb_lasti;
1414
int tb_lineno;
1515
} PyTracebackObject;

Include/frameobject.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
extern "C" {
77
#endif
88

9-
/* There are currently no frame related APIs in the stable ABI
10-
* (they're all in the full CPython-specific API)
11-
*/
9+
#include "pyframe.h"
1210

1311
#ifndef Py_LIMITED_API
1412
# define Py_CPYTHON_FRAMEOBJECT_H

Include/genobject.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ extern "C" {
1010

1111
#include "pystate.h" /* _PyErr_StackItem */
1212

13-
struct _frame; /* Avoid including frameobject.h */
14-
1513
/* _PyGenObject_HEAD defines the initial segment of generator
1614
and coroutine objects. */
1715
#define _PyGenObject_HEAD(prefix) \
1816
PyObject_HEAD \
1917
/* Note: gi_frame can be NULL if the generator is "finished" */ \
20-
struct _frame *prefix##_frame; \
18+
PyFrameObject *prefix##_frame; \
2119
/* True if generator is being executed. */ \
2220
char prefix##_running; \
2321
/* The code object backing the generator */ \
@@ -40,8 +38,8 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
4038
#define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type)
4139
#define PyGen_CheckExact(op) Py_IS_TYPE(op, &PyGen_Type)
4240

43-
PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *);
44-
PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(struct _frame *,
41+
PyAPI_FUNC(PyObject *) PyGen_New(PyFrameObject *);
42+
PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(PyFrameObject *,
4543
PyObject *name, PyObject *qualname);
4644
PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *);
4745
PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **);
@@ -60,7 +58,7 @@ PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type;
6058

6159
#define PyCoro_CheckExact(op) Py_IS_TYPE(op, &PyCoro_Type)
6260
PyObject *_PyCoro_GetAwaitableIter(PyObject *o);
63-
PyAPI_FUNC(PyObject *) PyCoro_New(struct _frame *,
61+
PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *,
6462
PyObject *name, PyObject *qualname);
6563

6664
/* Asynchronous Generators */
@@ -86,7 +84,7 @@ PyAPI_DATA(PyTypeObject) _PyAsyncGenASend_Type;
8684
PyAPI_DATA(PyTypeObject) _PyAsyncGenWrappedValue_Type;
8785
PyAPI_DATA(PyTypeObject) _PyAsyncGenAThrow_Type;
8886

89-
PyAPI_FUNC(PyObject *) PyAsyncGen_New(struct _frame *,
87+
PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *,
9088
PyObject *name, PyObject *qualname);
9189

9290
#define PyAsyncGen_CheckExact(op) Py_IS_TYPE(op, &PyAsyncGen_Type)

Include/internal/pycore_ceval.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ extern "C" {
1111
/* Forward declarations */
1212
struct pyruntimestate;
1313
struct _ceval_runtime_state;
14-
struct _frame;
1514

1615
#include "pycore_interp.h" /* PyInterpreterState.eval_frame */
1716

@@ -36,7 +35,7 @@ PyAPI_FUNC(void) _PyEval_SetCoroutineOriginTrackingDepth(
3635
void _PyEval_Fini(void);
3736

3837
static inline PyObject*
39-
_PyEval_EvalFrame(PyThreadState *tstate, struct _frame *f, int throwflag)
38+
_PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
4039
{
4140
return tstate->interp->eval_frame(tstate, f, throwflag);
4241
}

Include/internal/pycore_traceback.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ PyAPI_FUNC(void) _Py_DumpHexadecimal(
8989

9090
PyAPI_FUNC(PyObject*) _PyTraceBack_FromFrame(
9191
PyObject *tb_next,
92-
struct _frame *frame);
92+
PyFrameObject *frame);
9393

9494
#ifdef __cplusplus
9595
}

Include/pyframe.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Limited C API of PyFrame API
2+
*
3+
* Include "frameobject.h" to get the PyFrameObject structure.
4+
*/
5+
6+
#ifndef Py_PYFRAME_H
7+
#define Py_PYFRAME_H
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
typedef struct _frame PyFrameObject;
13+
14+
/* Return the line of code the frame is currently executing. */
15+
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
16+
17+
#ifdef __cplusplus
18+
}
19+
#endif
20+
#endif /* !Py_PYFRAME_H */

Include/pystate.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ removed (with effort). */
1313

1414
/* Forward declarations for PyFrameObject, PyThreadState
1515
and PyInterpreterState */
16-
struct _frame;
1716
struct _ts;
1817
struct _is;
1918

@@ -88,7 +87,7 @@ PyAPI_FUNC(int) PyThreadState_SetAsyncExc(unsigned long, PyObject *);
8887
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
8988
/* New in 3.9 */
9089
PyAPI_FUNC(PyInterpreterState*) PyThreadState_GetInterpreter(PyThreadState *tstate);
91-
PyAPI_FUNC(struct _frame*) PyThreadState_GetFrame(PyThreadState *tstate);
90+
PyAPI_FUNC(PyFrameObject*) PyThreadState_GetFrame(PyThreadState *tstate);
9291
PyAPI_FUNC(uint64_t) PyThreadState_GetID(PyThreadState *tstate);
9392
#endif
9493

Include/traceback.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44
extern "C" {
55
#endif
66

7-
struct _frame;
8-
97
/* Traceback interface */
108

11-
PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
9+
PyAPI_FUNC(int) PyTraceBack_Here(PyFrameObject *);
1210
PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
1311

1412
/* Reveal traceback type so we can typecheck traceback objects */

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,7 @@ PYTHON_HEADERS= \
10471047
$(srcdir)/Include/pydtrace.h \
10481048
$(srcdir)/Include/pyerrors.h \
10491049
$(srcdir)/Include/pyfpe.h \
1050+
$(srcdir)/Include/pyframe.h \
10501051
$(srcdir)/Include/pyhash.h \
10511052
$(srcdir)/Include/pylifecycle.h \
10521053
$(srcdir)/Include/pymacconfig.h \

Objects/frameobject.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ frame_getlocals(PyFrameObject *f, void *closure)
3434
int
3535
PyFrame_GetLineNumber(PyFrameObject *f)
3636
{
37-
if (f->f_trace)
37+
assert(f != NULL);
38+
if (f->f_trace) {
3839
return f->f_lineno;
39-
else
40+
}
41+
else {
4042
return PyCode_Addr2Line(f->f_code, f->f_lasti);
43+
}
4144
}
4245

4346
static PyObject *

PCbuild/pythoncore.vcxproj

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@
110110
</Link>
111111
</ItemDefinitionGroup>
112112
<ItemGroup>
113+
<ClInclude Include="..\Include\Python-ast.h" />
114+
<ClInclude Include="..\Include\Python.h" />
113115
<ClInclude Include="..\Include\abstract.h" />
114116
<ClInclude Include="..\Include\asdl.h" />
115117
<ClInclude Include="..\Include\ast.h" />
@@ -165,8 +167,8 @@
165167
<ClInclude Include="..\Include\internal\pycore_abstract.h" />
166168
<ClInclude Include="..\Include\internal\pycore_accu.h" />
167169
<ClInclude Include="..\Include\internal\pycore_atomic.h" />
168-
<ClInclude Include="..\Include\internal\pycore_byteswap.h" />
169170
<ClInclude Include="..\Include\internal\pycore_bytes_methods.h" />
171+
<ClInclude Include="..\Include\internal\pycore_byteswap.h" />
170172
<ClInclude Include="..\Include\internal\pycore_call.h" />
171173
<ClInclude Include="..\Include\internal\pycore_ceval.h" />
172174
<ClInclude Include="..\Include\internal\pycore_code.h" />
@@ -214,7 +216,6 @@
214216
<ClInclude Include="..\Include\parsetok.h" />
215217
<ClInclude Include="..\Include\patchlevel.h" />
216218
<ClInclude Include="..\Include\picklebufobject.h" />
217-
<ClInclude Include="..\Include\pyhash.h" />
218219
<ClInclude Include="..\Include\py_curses.h" />
219220
<ClInclude Include="..\Include\pyarena.h" />
220221
<ClInclude Include="..\Include\pycapsule.h" />
@@ -223,20 +224,20 @@
223224
<ClInclude Include="..\Include\pyerrors.h" />
224225
<ClInclude Include="..\Include\pyexpat.h" />
225226
<ClInclude Include="..\Include\pyfpe.h" />
227+
<ClInclude Include="..\Include\pyframe.h" />
228+
<ClInclude Include="..\Include\pyhash.h" />
226229
<ClInclude Include="..\Include\pylifecycle.h" />
227-
<ClInclude Include="..\Include\pymath.h" />
228-
<ClInclude Include="..\Include\pytime.h" />
229230
<ClInclude Include="..\Include\pymacro.h" />
231+
<ClInclude Include="..\Include\pymath.h" />
230232
<ClInclude Include="..\Include\pymem.h" />
231233
<ClInclude Include="..\Include\pyport.h" />
232234
<ClInclude Include="..\Include\pystate.h" />
233235
<ClInclude Include="..\Include\pystrcmp.h" />
234-
<ClInclude Include="..\Include\pystrtod.h" />
235236
<ClInclude Include="..\Include\pystrhex.h" />
236-
<ClInclude Include="..\Include\Python-ast.h" />
237-
<ClInclude Include="..\Include\Python.h" />
237+
<ClInclude Include="..\Include\pystrtod.h" />
238238
<ClInclude Include="..\Include\pythonrun.h" />
239239
<ClInclude Include="..\Include\pythread.h" />
240+
<ClInclude Include="..\Include\pytime.h" />
240241
<ClInclude Include="..\Include\rangeobject.h" />
241242
<ClInclude Include="..\Include\setobject.h" />
242243
<ClInclude Include="..\Include\sliceobject.h" />

PCbuild/pythoncore.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@
249249
<ClInclude Include="..\Include\internal\pycore_pyerrors.h">
250250
<Filter>Include</Filter>
251251
</ClInclude>
252+
<ClInclude Include="..\Include\internal\pycore_pyframe.h">
253+
<Filter>Include</Filter>
254+
</ClInclude>
252255
<ClInclude Include="..\Include\internal\pycore_pyhash.h">
253256
<Filter>Include</Filter>
254257
</ClInclude>

0 commit comments

Comments
 (0)