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
11 changes: 11 additions & 0 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions pyo3-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)]
Expand Down
3 changes: 2 additions & 1 deletion pyo3-ffi/examples/sequential/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions pyo3-ffi/examples/string-sum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
Loading