Skip to content

Commit

Permalink
[DO NOT MERGE] [PyO3#2361]Add macro append_to_inittab
Browse files Browse the repository at this point in the history
Sometimes we need to debug in a real environment with our module installed. `append_to_inittab` will be a wrapper for PyImport_AppendInittab (https://docs.python.org/3/c-api/import.html#c.PyImport_AppendInittab) and help us to do this
  • Loading branch information
herquan committed May 9, 2022
1 parent c57e509 commit a734b33
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 3 deletions.
2 changes: 1 addition & 1 deletion pyo3-ffi/src/import.rs
Expand Up @@ -76,6 +76,6 @@ extern "C" {

pub fn PyImport_AppendInittab(
name: *const c_char,
initfunc: Option<extern "C" fn() -> *mut PyObject>,
initfunc: Option<unsafe extern "C" fn() -> *mut PyObject>,
) -> c_int;
}
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/lib.rs
Expand Up @@ -29,7 +29,7 @@ mod pyproto;
mod wrap;

pub use frompyobject::build_derive_from_pyobject;
pub use module::{process_functions_in_module, pymodule_impl, PyModuleOptions};
pub use module::{process_functions_in_module, pymodule_impl, PyModuleOptions, append_to_inittab_impl};
pub use pyclass::{build_py_class, build_py_enum, PyClassArgs};
pub use pyfunction::{build_py_function, PyFunctionOptions};
pub use pyimpl::{build_py_methods, PyClassMethodsType};
Expand Down
17 changes: 17 additions & 0 deletions pyo3-macros-backend/src/module.rs
Expand Up @@ -90,6 +90,23 @@ pub fn pymodule_impl(
}
}

pub fn append_to_inittab_impl(fnname: &Ident) -> TokenStream {
let name = fnname.unraw();
let cb_name = Ident::new(&format!("PyInit_{}", name), Span::call_site());
quote! {
unsafe{
use pyo3::ffi::PyImport_AppendInittab;
assert_eq!(
pyo3::ffi::Py_IsInitialized(),
0,
"called `append_to_inittab_impl` but a Python interpreter is already running."
);
// TODO: How to pass in pyo3?
pyo3::ffi::PyImport_AppendInittab(concat!(stringify!(#name), "\0").as_ptr() as *const std::os::raw::c_char, Option::Some(#cb_name));
}
}
}

/// Finds and takes care of the #[pyfn(...)] in `#[pymodule]`
pub fn process_functions_in_module(func: &mut syn::ItemFn) -> syn::Result<()> {
let mut stmts: Vec<syn::Stmt> = Vec::new();
Expand Down
11 changes: 10 additions & 1 deletion pyo3-macros/src/lib.rs
Expand Up @@ -9,7 +9,7 @@ use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use pyo3_macros_backend::{
build_derive_from_pyobject, build_py_class, build_py_enum, build_py_function, build_py_methods,
get_doc, process_functions_in_module, pymodule_impl, wrap_pyfunction_impl, wrap_pymodule_impl,
get_doc, process_functions_in_module, pymodule_impl, append_to_inittab_impl,wrap_pyfunction_impl, wrap_pymodule_impl,
PyClassArgs, PyClassMethodsType, PyFunctionOptions, PyModuleOptions, WrapPyFunctionArgs,
};
use quote::quote;
Expand Down Expand Up @@ -213,6 +213,15 @@ pub fn wrap_pymodule(input: TokenStream) -> TokenStream {
wrap_pymodule_impl(path).unwrap_or_compile_error().into()
}

/// Add current module to the existing table of built-in modules.
///
/// Use before `prepare_freethreaded_python()`
#[proc_macro]
pub fn append_to_inittab(input: TokenStream) -> TokenStream {
let fnname = parse_macro_input!(input as syn::Ident);
append_to_inittab_impl(&fnname).into()
}

fn pyclass_impl(
attrs: TokenStream,
mut ast: syn::ItemStruct,
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Expand Up @@ -407,6 +407,7 @@ pub use pyo3_macros::pyproto;
#[cfg(feature = "macros")]
pub use pyo3_macros::{
pyclass, pyfunction, pymethods, pymodule, wrap_pyfunction, wrap_pymodule, FromPyObject,
append_to_inittab
};

#[cfg(feature = "macros")]
Expand Down
12 changes: 12 additions & 0 deletions tests/test_module.rs
Expand Up @@ -4,6 +4,7 @@ use pyo3::prelude::*;

use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyDict, PyTuple};
use pyo3_macros::append_to_inittab;
mod common;

#[pyclass]
Expand Down Expand Up @@ -443,3 +444,14 @@ fn test_module_doc_hidden() {
py_assert!(py, m, "m.__doc__ == ''");
})
}

#[test]
fn test_module_append_to_inittab(){
append_to_inittab!(module_with_functions);
Python::with_gil(|py| {
py.run(r#"
import module_with_functions
assert module_with_functions.double(3)==6
"#,None,None).map_err(|e| e.print(py)).unwrap();
})
}

0 comments on commit a734b33

Please sign in to comment.