Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Compatibility workaround to match 3.11a6 API
  • Loading branch information
ncoghlan committed Mar 20, 2022
commit b2759999e3751c37e77bb4dafc1e5d6ef6bfee49
30 changes: 30 additions & 0 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,36 @@ typedef struct _Py_frame {
PyObject *localsplus[1];
} _Py_frame;

#if !defined(_PY_FRAME_API_DISABLE_INTERIM_COMPAT_3_11a6)
/* Interim compatibility for the internal frame API as shipped in 3.11a6
* Some projects (Cython, gevent, greenlet) are known to access the private
* frame API in CPython. This API has already changed twice for 3.11 (first
* with the structural split, then with the full object structure becoming
* opaque and internal struct gaining the `_Py` prefix). The recommended
* resolution is expected to change again once a proper public API for the
* required frame operations is defined (as discussed in
* https://github.com/faster-cpython/ideas/issues/309).
*
* This interim compatibility workaround enables the bpo-44800 struct and field
* name changes for CPython maintainability without forcing yet another interim
* code update on the affected projects. Since the workaround affects symbols
* without the `Py` or `_Py` prefix, a preprocessor symbol can be declared to
* disable the workaround: _PY_FRAME_API_DISABLE_INTERIM_COMPAT_3_11a6
*/
// Renamed frame data struct and fields
typedef _Py_frame _PyInterpreterFrame;
#define f_func func
#define f_globals globals
#define f_builtins builtins
#define f_locals locals
#define f_code code
#define f_lasti lasti
#define f_state state
// Renamed frame object fields
#define f_frame f_fdata
#define _f_frame_data _f_owned_fdata
#endif // End internal frame API compatibilty workaround

static inline int _PyFrame_IsRunnable(_Py_frame *f) {
return f->state < FRAME_EXECUTING;
}
Expand Down
17 changes: 17 additions & 0 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ static PyMemberDef frame_memberlist[] = {
{NULL} /* Sentinel */
};

// Compile time check of interim Python 3.11a6 API compatibility aliases
// Can be removed once the aliases are removed
static_assert(OFF(f_fdata) == OFF(f_frame), "Incorrect alias for f_frame");
static_assert(OFF(_f_owned_fdata) == OFF(_f_frame_data), "Incorrect alias for _f_frame_data");

#define INTERIM_FRAME_DATA_ALIAS_CHECK(new_field) \
static_assert(offsetof(_Py_frame, new_field) == offsetof(_PyInterpreterFrame, f_##new_field), \
"Incorrect alias for f_" #new_field )

INTERIM_FRAME_DATA_ALIAS_CHECK(func);
INTERIM_FRAME_DATA_ALIAS_CHECK(builtins);
INTERIM_FRAME_DATA_ALIAS_CHECK(globals);
INTERIM_FRAME_DATA_ALIAS_CHECK(locals);
INTERIM_FRAME_DATA_ALIAS_CHECK(code);
INTERIM_FRAME_DATA_ALIAS_CHECK(lasti);
INTERIM_FRAME_DATA_ALIAS_CHECK(state);
// End compatiblity alias check

static PyObject *
frame_getlocals(PyFrameObject *f, void *closure)
Expand Down