diff --git a/guide/src/migration.md b/guide/src/migration.md index 6b3d2b1265d..921d186fc8d 100644 --- a/guide/src/migration.md +++ b/guide/src/migration.md @@ -59,6 +59,17 @@ let _: Bound<'_, PyNone> = unsafe { Bound::from_owned_ptr(py, raw_ptr).cast_into # }) ``` +### Internal change to use multi-phase initialization + +[PEP 489](https://peps.python.org/pep-0489/) introduced "multi-phase initialization" for extension modules which provides ways to allocate and clean up per-module state. +This is a necessary step towards supporting Python "subinterpreters" which run on their own copy of state. + +Starting in PyO3 0.28, the `#[pymodule]` macro machinery has been reworked to use multi-phase initialization. +The possibility of creating and consuming per-module state (and supporting subinterpreters) is left for a future PyO3 version. +This should not require migration, nor is there expected to be breakage caused by the change. + +Nevertheless, this affects the order of initialization so seemed worth noting in this guide. + ## from 0.26.* to 0.27 ### `FromPyObject` reworked for flexibility and efficiency diff --git a/pyo3-ffi/README.md b/pyo3-ffi/README.md index 41b9546ac50..389ea2c4cc2 100644 --- a/pyo3-ffi/README.md +++ b/pyo3-ffi/README.md @@ -77,7 +77,7 @@ static mut MODULE_DEF: PyModuleDef = PyModuleDef { m_doc: c"A Python module written in Rust.".as_ptr(), m_size: 0, m_methods: std::ptr::addr_of_mut!(METHODS).cast(), - m_slots: unsafe { SLOTS as *const [PyModuleDef_Slot] as *mut PyModuleDef_Slot }, + m_slots: std::ptr::addr_of_mut!(SLOTS).cast(), m_traverse: None, m_clear: None, m_free: None, @@ -96,7 +96,8 @@ static mut METHODS: [PyMethodDef; 2] = [ PyMethodDef::zeroed(), ]; -static mut SLOTS: &[PyModuleDef_Slot] = &[ +const SLOTS_LEN: usize = 1 + if cfg!(Py_3_12) { 1 } else { 0 } + if cfg!(Py_GIL_DISABLED) { 1 } else { 0 }; +static mut SLOTS: [PyModuleDef_Slot; SLOTS_LEN] = [ // NB: only include this slot if the module does not store any global state in `static` variables // or other data which could cross between subinterpreters #[cfg(Py_3_12)] diff --git a/pyo3-ffi/examples/sequential/src/module.rs b/pyo3-ffi/examples/sequential/src/module.rs index c8d506c5568..99b573d4154 100644 --- a/pyo3-ffi/examples/sequential/src/module.rs +++ b/pyo3-ffi/examples/sequential/src/module.rs @@ -14,7 +14,8 @@ pub static mut MODULE_DEF: PyModuleDef = PyModuleDef { m_free: Some(sequential_free), }; -const SEQUENTIAL_SLOTS_LEN: usize = 3 + if cfg!(Py_GIL_DISABLED) { 1 } else { 0 }; +const SEQUENTIAL_SLOTS_LEN: usize = + 2 + if cfg!(Py_3_12) { 1 } else { 0 } + if cfg!(Py_GIL_DISABLED) { 1 } else { 0 }; static mut SEQUENTIAL_SLOTS: [PyModuleDef_Slot; SEQUENTIAL_SLOTS_LEN] = [ PyModuleDef_Slot { slot: Py_mod_exec, diff --git a/pyo3-ffi/examples/string-sum/src/lib.rs b/pyo3-ffi/examples/string-sum/src/lib.rs index e772b792e17..658b798c523 100644 --- a/pyo3-ffi/examples/string-sum/src/lib.rs +++ b/pyo3-ffi/examples/string-sum/src/lib.rs @@ -9,7 +9,7 @@ static mut MODULE_DEF: PyModuleDef = PyModuleDef { m_doc: c"A Python module written in Rust.".as_ptr(), m_size: 0, m_methods: std::ptr::addr_of_mut!(METHODS).cast(), - m_slots: unsafe { SLOTS as *const [PyModuleDef_Slot] as *mut PyModuleDef_Slot }, + m_slots: std::ptr::addr_of_mut!(SLOTS).cast(), m_traverse: None, m_clear: None, m_free: None, @@ -28,7 +28,9 @@ static mut METHODS: [PyMethodDef; 2] = [ PyMethodDef::zeroed(), ]; -static mut SLOTS: &[PyModuleDef_Slot] = &[ +const SLOTS_LEN: usize = + 1 + if cfg!(Py_3_12) { 1 } else { 0 } + if cfg!(Py_GIL_DISABLED) { 1 } else { 0 }; +static mut SLOTS: [PyModuleDef_Slot; SLOTS_LEN] = [ #[cfg(Py_3_12)] PyModuleDef_Slot { slot: Py_mod_multiple_interpreters,