Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,24 @@ jobs:
python-architecture: "x64",
rust-target: "x86_64-unknown-linux-gnu",
}
# Also test Python 3.15 and 3.15t, on ubuntu
# (run for all OSes on build-full)
- rust: stable
python-version: "3.15-dev"
platform:
{
os: "ubuntu-latest",
python-architecture: "x64",
rust-target: "x86_64-unknown-linux-gnu",
}
- rust: stable
python-version: "3.15t-dev"
platform:
{
os: "ubuntu-latest",
python-architecture: "x64",
rust-target: "x86_64-unknown-linux-gnu",
}

build-full:
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
Expand Down
4 changes: 4 additions & 0 deletions newsfragments/6014.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* Added support for Python 3.15.0b1.
* Added FFI bindings for the PEP 820 PySlot C API.
* Added bindings for the critical section API in the limited API on Python 3.15
and newer.
1 change: 1 addition & 0 deletions newsfragments/6014.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Updated FFI bindings and module initialization to use PEP 820 PySlot API.
1 change: 1 addition & 0 deletions pyo3-build-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ fn print_feature_cfg(minor_version_required: u32, cfg: &str) {
/// so this function is unstable.
#[doc(hidden)]
pub fn print_feature_cfgs() {
print_feature_cfg(84, "const_is_null");
print_feature_cfg(85, "fn_ptr_eq");
print_feature_cfg(86, "from_bytes_with_nul_error");
}
Expand Down
16 changes: 16 additions & 0 deletions pyo3-ffi-check/macro/src/lib.rs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's just me, but perhaps we should maintain a PyO3-specific fork of bindgen to output better type names for anonymous unions and other kludges with for_all_fields...

Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ pub fn for_all_fields(input: proc_macro::TokenStream) -> proc_macro::TokenStream
// the field name in the C API is `type`, but that's a keyword in Rust
// so PyO3 picked type_code, bindgen picked type_
Ident::new("type_", Span::call_site())
} else if struct_name == "PySlot" && field_name == "anon1" {
// PySlot has two anonymous unions (since they aren't allowed in Rust,
// PyO3 invented names for them); bindgen names the first one __bindgen_anon_1
Ident::new("__bindgen_anon_1", Span::call_site())
} else if struct_name == "PySlot" && field_name == "anon2" {
// ...and the second one __bindgen_anon_2
Ident::new("__bindgen_anon_2", Span::call_site())
} else {
field_ident.clone()
};
Expand Down Expand Up @@ -352,6 +359,15 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[
("PySet_CheckExact", "not(PyPy)"),
("PySet_GET_SIZE", ""),
("PySlice_Check", ""),
("PySlot_DATA", ""),
("PySlot_END", ""),
("PySlot_FUNC", ""),
("PySlot_INT64", ""),
("PySlot_PTR", ""),
("PySlot_PTR_STATIC", ""),
("PySlot_SIZE", ""),
("PySlot_STATIC_DATA", ""),
("PySlot_UINT64", ""),
("PyStructSequence_GET_ITEM", ""),
("PyStructSequence_SET_ITEM", ""),
("PyTZInfo_Check", "not(PyPy)"),
Expand Down
2 changes: 1 addition & 1 deletion pyo3-ffi/examples/sequential/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ pub unsafe extern "C" fn PyInit_sequential() -> *mut PyObject {
#[cfg(Py_3_15)]
#[allow(non_snake_case, reason = "must be named `PyModExport_<your_module>`")]
#[no_mangle]
pub unsafe extern "C" fn PyModExport_sequential() -> *mut PyModuleDef_Slot {
pub unsafe extern "C" fn PyModExport_sequential() -> *mut PySlot {
(&raw mut SEQUENTIAL_SLOTS).cast()
}
63 changes: 26 additions & 37 deletions pyo3-ffi/examples/sequential/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,44 +20,33 @@ PyABIInfo_VAR!(ABI_INFO);

const SEQUENTIAL_SLOTS_LEN: usize =
2 + cfg!(Py_3_12) as usize + cfg!(Py_GIL_DISABLED) as usize + 7 * (cfg!(Py_3_15) as usize);
#[cfg(Py_3_15)]
pub static mut SEQUENTIAL_SLOTS: [PySlot; SEQUENTIAL_SLOTS_LEN] = [
PySlot_STATIC_DATA(Py_mod_abi, (&raw mut ABI_INFO).cast()),
PySlot_STATIC_DATA(Py_mod_name, c"sequential".as_ptr() as *mut c_void),
PySlot_STATIC_DATA(
Py_mod_doc,
c"A library for generating sequential ids, written in Rust.".as_ptr() as *mut c_void,
),
PySlot_SIZE(
Py_mod_state_size,
mem::size_of::<sequential_state>() as Py_ssize_t,
),
// safety: all these function pointers are non-null by construction
unsafe { PySlot_FUNC(Py_mod_state_traverse, sequential_traverse as *mut c_void) },
unsafe { PySlot_FUNC(Py_mod_state_clear, sequential_clear as *mut c_void) },
unsafe { PySlot_FUNC(Py_mod_state_free, sequential_free as *mut c_void) },
unsafe { PySlot_FUNC(Py_mod_exec, sequential_exec as *mut c_void) },
PySlot_DATA(
Py_mod_multiple_interpreters,
Py_MOD_PER_INTERPRETER_GIL_SUPPORTED,
),
#[cfg(Py_GIL_DISABLED)]
PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
PySlot_END(),
];
#[cfg(not(Py_3_15))]
pub static mut SEQUENTIAL_SLOTS: [PyModuleDef_Slot; SEQUENTIAL_SLOTS_LEN] = [
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_abi,
value: (&raw mut ABI_INFO).cast(),
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_name,
// safety: Python does not write to this field
value: c"sequential".as_ptr() as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_doc,
// safety: Python does not write to this field
value: c"A library for generating sequential ids, written in Rust.".as_ptr() as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_state_size,
value: mem::size_of::<sequential_state>() as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_state_traverse,
value: sequential_traverse as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_state_clear,
value: sequential_clear as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_state_free,
value: sequential_free as *mut c_void,
},
PyModuleDef_Slot {
slot: Py_mod_exec,
value: sequential_exec as *mut c_void,
Expand Down
44 changes: 20 additions & 24 deletions pyo3-ffi/examples/string-sum/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#[cfg(Py_3_15)]
use std::ffi::c_void;
use std::ffi::{c_char, c_long};
use std::ptr;

use pyo3_ffi::*;

Expand Down Expand Up @@ -36,29 +35,26 @@ PyABIInfo_VAR!(ABI_INFO);

const SLOTS_LEN: usize =
1 + cfg!(Py_3_12) as usize + cfg!(Py_GIL_DISABLED) as usize + 4 * (cfg!(Py_3_15) as usize);
#[cfg(Py_3_15)]
static mut SLOTS: [PySlot; SLOTS_LEN] = [
PySlot_STATIC_DATA(Py_mod_abi, (&raw mut ABI_INFO).cast()),
// safety: Python does not write to these static fields
PySlot_STATIC_DATA(Py_mod_name, c"string_sum".as_ptr() as *mut c_void),
PySlot_STATIC_DATA(
Py_mod_doc,
c"A Python module written in Rust.".as_ptr() as *mut c_void,
),
PySlot_STATIC_DATA(Py_mod_methods, (&raw mut METHODS).cast()),
PySlot_DATA(
Py_mod_multiple_interpreters,
Py_MOD_PER_INTERPRETER_GIL_SUPPORTED,
),
#[cfg(Py_GIL_DISABLED)]
PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
PySlot_END(),
];
#[cfg(not(Py_3_15))]
static mut SLOTS: [PyModuleDef_Slot; SLOTS_LEN] = [
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_abi,
value: (&raw mut ABI_INFO).cast(),
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_name,
// safety: Python does not write to this field
value: c"string_sum".as_ptr() as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_doc,
// safety: Python does not write to this field
value: c"A Python module written in Rust.".as_ptr() as *mut c_void,
},
#[cfg(Py_3_15)]
PyModuleDef_Slot {
slot: Py_mod_methods,
value: (&raw mut METHODS).cast(),
},
#[cfg(Py_3_12)]
PyModuleDef_Slot {
slot: Py_mod_multiple_interpreters,
Expand All @@ -71,7 +67,7 @@ static mut SLOTS: [PyModuleDef_Slot; SLOTS_LEN] = [
},
PyModuleDef_Slot {
slot: 0,
value: ptr::null_mut(),
value: std::ptr::null_mut(),
},
];

Expand Down
29 changes: 1 addition & 28 deletions pyo3-ffi/src/cpython/critical_section.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,11 @@
#[cfg(any(Py_3_14, Py_GIL_DISABLED))]
use crate::PyMutex;
use crate::PyObject;

#[repr(C)]
#[cfg(Py_GIL_DISABLED)]
pub struct PyCriticalSection {
_cs_prev: usize,
_cs_mutex: *mut PyMutex,
}

#[repr(C)]
#[cfg(Py_GIL_DISABLED)]
pub struct PyCriticalSection2 {
_cs_base: PyCriticalSection,
_cs_mutex2: *mut PyMutex,
}

#[cfg(not(Py_GIL_DISABLED))]
opaque_struct!(pub PyCriticalSection);

#[cfg(not(Py_GIL_DISABLED))]
opaque_struct!(pub PyCriticalSection2);
use crate::{PyCriticalSection, PyCriticalSection2};

extern_libpython! {
pub fn PyCriticalSection_Begin(c: *mut PyCriticalSection, op: *mut PyObject);
#[cfg(Py_3_14)]
pub fn PyCriticalSection_BeginMutex(c: *mut PyCriticalSection, m: *mut PyMutex);
pub fn PyCriticalSection_End(c: *mut PyCriticalSection);
pub fn PyCriticalSection2_Begin(c: *mut PyCriticalSection2, a: *mut PyObject, b: *mut PyObject);
#[cfg(Py_3_14)]
pub fn PyCriticalSection2_BeginMutex(
c: *mut PyCriticalSection2,
m1: *mut PyMutex,
m2: *mut PyMutex,
);
pub fn PyCriticalSection2_End(c: *mut PyCriticalSection2);
}
6 changes: 3 additions & 3 deletions pyo3-ffi/src/cpython/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub(crate) mod ceval;
pub(crate) mod code;
pub(crate) mod compile;
pub(crate) mod complexobject;
#[cfg(Py_3_13)]
#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
pub(crate) mod critical_section;
pub(crate) mod descrobject;
pub(crate) mod dictobject;
Expand Down Expand Up @@ -56,8 +56,8 @@ pub use self::ceval::*;
pub use self::code::*;
pub use self::compile::*;
pub use self::complexobject::*;
#[cfg(Py_3_13)]
pub use self::critical_section::*;
#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
pub use self::critical_section::{PyCriticalSection2_BeginMutex, PyCriticalSection_BeginMutex};
pub use self::descrobject::*;
pub use self::dictobject::*;
pub use self::floatobject::*;
Expand Down
3 changes: 3 additions & 0 deletions pyo3-ffi/src/cpython/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::mem;
// skipped private _Py_NewReference
// skipped private _Py_NewReferenceNoTotal
// skipped private _Py_ResurrectReference
// skipped private _Py_ForgetReference

// skipped private _Py_GetGlobalRefTotal
// skipped private _Py_GetRefTotal
Expand Down Expand Up @@ -277,6 +278,8 @@ pub struct PyTypeObject {
pub tp_next: *mut PyTypeObject,
#[cfg(Py_3_13)]
pub tp_versions_used: u16,
#[cfg(Py_3_15)]
pub _tp_iteritem: Option<object::_Py_iteritemfunc>,
}

#[cfg(Py_3_11)]
Expand Down
34 changes: 34 additions & 0 deletions pyo3-ffi/src/critical_section.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#[cfg(any(all(Py_GIL_DISABLED, Py_3_13, not(Py_LIMITED_API)), Py_3_15,))]
use crate::PyMutex;
#[cfg(any(all(Py_GIL_DISABLED, Py_3_13), Py_3_15))]
use crate::PyObject;

#[cfg(all(Py_LIMITED_API, Py_3_13, not(Py_3_15)))]
opaque_struct!(pub PyMutex);

#[cfg(any(all(Py_GIL_DISABLED, Py_3_13, not(Py_LIMITED_API)), Py_3_15,))]
#[repr(C)]
pub struct PyCriticalSection {
_cs_prev: usize,
_cs_mutex: *mut PyMutex,
}

#[cfg(any(all(Py_GIL_DISABLED, Py_3_13, not(Py_LIMITED_API)), Py_3_15,))]
#[repr(C)]
pub struct PyCriticalSection2 {
_cs_base: PyCriticalSection,
_cs_mutex2: *mut PyMutex,
}

#[cfg(all(not(Py_GIL_DISABLED), Py_3_13, not(Py_3_15), not(Py_LIMITED_API)))]
opaque_struct!(pub PyCriticalSection);
#[cfg(all(not(Py_GIL_DISABLED), Py_3_13, not(Py_3_15), not(Py_LIMITED_API)))]
opaque_struct!(pub PyCriticalSection2);

#[cfg(any(all(Py_GIL_DISABLED, Py_3_13), Py_3_15))]
extern_libpython! {
pub fn PyCriticalSection_Begin(c: *mut PyCriticalSection, op: *mut PyObject);
pub fn PyCriticalSection_End(c: *mut PyCriticalSection);
pub fn PyCriticalSection2_Begin(c: *mut PyCriticalSection2, a: *mut PyObject, b: *mut PyObject);
pub fn PyCriticalSection2_End(c: *mut PyCriticalSection2);
}
Loading
Loading