Skip to content
Open
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
1 change: 1 addition & 0 deletions newsfragments/5753.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Module initialization uses the PyModExport and PyABIInfo APIs on python 3.15 and newer.
31 changes: 28 additions & 3 deletions pyo3-macros-backend/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ fn module_initialization(
) -> TokenStream {
let Ctx { pyo3_path, .. } = ctx;
let pyinit_symbol = format!("PyInit_{name}");
let pymodexport_symbol = format!("PyModExport_{name}");
let pyo3_name = LitCStr::new(&CString::new(full_name).unwrap(), Span::call_site());

let mut result = quote! {
Expand All @@ -531,23 +532,47 @@ fn module_initialization(
#pyo3_path::impl_::trampoline::module_exec(module, #module_exec)
}

static SLOTS: impl_::PyModuleSlots<4> = impl_::PyModuleSlotsBuilder::new()
// The full slots, used for the PyModExport initializaiton
static SLOTS: impl_::PyModuleSlots = impl_::PyModuleSlotsBuilder::new()
.with_mod_exec(__pyo3_module_exec)
.with_abi_info()
.with_gil_used(#gil_used)
.with_name(__PYO3_NAME)
.with_doc(#doc)
.build();
Comment on lines 535 to 542
Copy link
Member

Choose a reason for hiding this comment

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

This already makes me want slots reuse from PEP 820 😂


impl_::ModuleDef::new(__PYO3_NAME, #doc, &SLOTS)
// Used for old-style PyModuleDef initialization
// CPython doesn't allow specifying slots like the name and docstring that
// can be defined in PyModuleDef, so we skip those slots
static SLOTS_MINIMAL: impl_::PyModuleSlots = impl_::PyModuleSlotsBuilder::new()
.with_mod_exec(__pyo3_module_exec)
.with_abi_info()
.with_gil_used(#gil_used)
.build();

// Since the macros need to be written agnostic to the Python version
// we need to explicitly pass the name and docstring for PyModuleDef
// initializaiton.
impl_::ModuleDef::new(__PYO3_NAME, #doc, &SLOTS, &SLOTS_MINIMAL)
};
};
if !is_submodule {
result.extend(quote! {
/// This autogenerated function is called by the python interpreter when importing
/// the module.
/// the module on Python 3.14 and older.
#[doc(hidden)]
#[export_name = #pyinit_symbol]
pub unsafe extern "C" fn __pyo3_init() -> *mut #pyo3_path::ffi::PyObject {
_PYO3_DEF.init_multi_phase()
}

/// This autogenerated function is called by the python interpreter when importing
/// the module on Python 3.15 and newer.
#[doc(hidden)]
#[export_name = #pymodexport_symbol]
pub unsafe extern "C" fn __pyo3_export() -> *mut #pyo3_path::ffi::PyModuleDef_Slot {
_PYO3_DEF.get_slots()
}
});
}
result
Expand Down
Loading
Loading