From f9525a3b85253228420d92f0ef44de86ac666e13 Mon Sep 17 00:00:00 2001 From: "adam.gerhant" Date: Tue, 7 Jul 2026 12:03:34 -0700 Subject: [PATCH 1/3] Add eval frame FFI bindings --- pyo3-ffi/src/cpython/pystate.rs | 34 +++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/pyo3-ffi/src/cpython/pystate.rs b/pyo3-ffi/src/cpython/pystate.rs index 52e15224cc2..e7d728d934a 100644 --- a/pyo3-ffi/src/cpython/pystate.rs +++ b/pyo3-ffi/src/cpython/pystate.rs @@ -1,3 +1,5 @@ +#[cfg(all(Py_3_11, not(PyPy)))] +use crate::cpython::pyframe::_PyInterpreterFrame; use crate::PyThreadState; use crate::{PyFrameObject, PyInterpreterState, PyObject}; use core::ffi::c_int; @@ -12,6 +14,20 @@ pub type Py_tracefunc = unsafe extern "C" fn( arg: *mut PyObject, ) -> c_int; +#[cfg(all(not(Py_3_11), not(PyPy)))] +pub type _PyFrameEvalFunction = unsafe extern "C" fn( + tstate: *mut PyThreadState, + frame: *mut PyFrameObject, + throwflag: c_int, +) -> *mut PyObject; + +#[cfg(all(Py_3_11, not(PyPy)))] +pub type _PyFrameEvalFunction = unsafe extern "C" fn( + tstate: *mut PyThreadState, + frame: *mut _PyInterpreterFrame, + throwflag: c_int, +) -> *mut PyObject; + pub const PyTrace_CALL: c_int = 0; pub const PyTrace_EXCEPTION: c_int = 1; pub const PyTrace_LINE: c_int = 2; @@ -78,8 +94,18 @@ extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyThreadState_DeleteCurrent")] pub fn PyThreadState_DeleteCurrent(); -} -// skipped private _PyFrameEvalFunction -// skipped private _PyInterpreterState_GetEvalFrameFunc -// skipped private _PyInterpreterState_SetEvalFrameFunc + #[cfg(all(not(Py_3_11), not(PyPy)))] + pub fn _PyInterpreterState_GetEvalFrameFunc( + interp: *mut PyInterpreterState, + ) -> Option<_PyFrameEvalFunction>; + #[cfg(all(Py_3_11, not(PyPy)))] + pub fn _PyInterpreterState_GetEvalFrameFunc( + interp: *mut PyInterpreterState, + ) -> _PyFrameEvalFunction; + #[cfg(not(PyPy))] + pub fn _PyInterpreterState_SetEvalFrameFunc( + interp: *mut PyInterpreterState, + eval_frame: Option<_PyFrameEvalFunction>, + ); +} From 4034e43edaaea2aef3d0706cc294ba2907c40171 Mon Sep 17 00:00:00 2001 From: "adam.gerhant" Date: Tue, 7 Jul 2026 13:33:47 -0700 Subject: [PATCH 2/3] Add eval frame FFI bindings --- newsfragments/6195.added.md | 1 + pyo3-ffi/src/impl_/macros.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 newsfragments/6195.added.md diff --git a/newsfragments/6195.added.md b/newsfragments/6195.added.md new file mode 100644 index 00000000000..92b32e3fad8 --- /dev/null +++ b/newsfragments/6195.added.md @@ -0,0 +1 @@ +Added FFI bindings for CPython eval-frame get/set API diff --git a/pyo3-ffi/src/impl_/macros.rs b/pyo3-ffi/src/impl_/macros.rs index 5b2fd448876..7dc7c5c564e 100644 --- a/pyo3-ffi/src/impl_/macros.rs +++ b/pyo3-ffi/src/impl_/macros.rs @@ -86,6 +86,18 @@ macro_rules! extern_libpython_maybe_private_fn { ) => { extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } }; + ( + [_PyInterpreterState_GetEvalFrameFunc] + $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? + ) => { + extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } + }; + ( + [_PyInterpreterState_SetEvalFrameFunc] + $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? + ) => { + extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } + }; ( [_PyObject_GC_New] $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? From 4b1449531d83ad3bdf1157a6bc155f8914c5a713 Mon Sep 17 00:00:00 2001 From: "adam.gerhant" Date: Thu, 9 Jul 2026 20:43:31 -0700 Subject: [PATCH 3/3] Fix eval code extra index link name --- newsfragments/6195.fixed.md | 1 + pyo3-ffi/src/cpython/ceval.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 newsfragments/6195.fixed.md diff --git a/newsfragments/6195.fixed.md b/newsfragments/6195.fixed.md new file mode 100644 index 00000000000..836c5e711a5 --- /dev/null +++ b/newsfragments/6195.fixed.md @@ -0,0 +1 @@ +Fix the PyUnstable_Eval_RequestCodeExtraIndex FFI binding to link to the private CPython symbol on Python versions before 3.12. diff --git a/pyo3-ffi/src/cpython/ceval.rs b/pyo3-ffi/src/cpython/ceval.rs index ea12ccfc338..54f96149cf4 100644 --- a/pyo3-ffi/src/cpython/ceval.rs +++ b/pyo3-ffi/src/cpython/ceval.rs @@ -14,8 +14,8 @@ extern_libpython! { // skipped private _PyEval_EvalFrameDefault - // was moved to the unstable API tier on Py_3_12, use link_name for older versions - #[cfg_attr(Py_3_12, link_name = "_PyEval_RequestCodeExtraIndex")] + // Was moved to the unstable API tier on Py_3_12; older versions export the private name. + #[cfg_attr(not(Py_3_12), link_name = "_PyEval_RequestCodeExtraIndex")] pub fn PyUnstable_Eval_RequestCodeExtraIndex(func: freefunc) -> Py_ssize_t; }