pyo3-macros-backend: more tests for macro hygiene

This commit is contained in:
David Hewitt 2021-08-27 23:22:09 +01:00
parent 667865e2d7
commit 313610993a
6 changed files with 80 additions and 56 deletions

View File

@ -103,12 +103,12 @@ impl FnType {
} }
FnType::FnClass => { FnType::FnClass => {
quote! { quote! {
let _slf = pyo3::types::PyType::from_type_ptr(_py, _slf as *mut pyo3::ffi::PyTypeObject); let _slf = ::pyo3::types::PyType::from_type_ptr(_py, _slf as *mut ::pyo3::ffi::PyTypeObject);
} }
} }
FnType::FnModule => { FnType::FnModule => {
quote! { quote! {
let _slf = _py.from_borrowed_ptr::<pyo3::types::PyModule>(_slf); let _slf = _py.from_borrowed_ptr::<::pyo3::types::PyModule>(_slf);
} }
} }
} }
@ -455,17 +455,17 @@ impl<'a> FnSpec<'a> {
quote!(#func_name) quote!(#func_name)
}; };
let rust_call = let rust_call =
quote! { pyo3::callback::convert(#py, #rust_name(#self_arg #(#arg_names),*)) }; quote! { ::pyo3::callback::convert(#py, #rust_name(#self_arg #(#arg_names),*)) };
Ok(match self.convention { Ok(match self.convention {
CallingConvention::Noargs => { CallingConvention::Noargs => {
quote! { quote! {
unsafe extern "C" fn #ident ( unsafe extern "C" fn #ident (
_slf: *mut pyo3::ffi::PyObject, _slf: *mut ::pyo3::ffi::PyObject,
_args: *mut pyo3::ffi::PyObject, _args: *mut ::pyo3::ffi::PyObject,
) -> *mut pyo3::ffi::PyObject ) -> *mut ::pyo3::ffi::PyObject
{ {
#deprecations #deprecations
pyo3::callback::handle_panic(|#py| { ::pyo3::callback::handle_panic(|#py| {
#self_conversion #self_conversion
#rust_call #rust_call
}) })
@ -476,23 +476,24 @@ impl<'a> FnSpec<'a> {
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, true)?; let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, true)?;
quote! { quote! {
unsafe extern "C" fn #ident ( unsafe extern "C" fn #ident (
_slf: *mut pyo3::ffi::PyObject, _slf: *mut ::pyo3::ffi::PyObject,
_args: *const *mut pyo3::ffi::PyObject, _args: *const *mut ::pyo3::ffi::PyObject,
_nargs: pyo3::ffi::Py_ssize_t, _nargs: ::pyo3::ffi::Py_ssize_t,
_kwnames: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject _kwnames: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
{ {
#deprecations #deprecations
pyo3::callback::handle_panic(|#py| { ::pyo3::callback::handle_panic(|#py| {
#self_conversion #self_conversion
let _kwnames: Option<&pyo3::types::PyTuple> = #py.from_borrowed_ptr_or_opt(_kwnames); use ::std::option::Option;
let _kwnames: Option<&::pyo3::types::PyTuple> = #py.from_borrowed_ptr_or_opt(_kwnames);
// Safety: &PyAny has the same memory layout as `*mut ffi::PyObject` // Safety: &PyAny has the same memory layout as `*mut ffi::PyObject`
let _args = _args as *const &pyo3::PyAny; let _args = _args as *const &::pyo3::PyAny;
let _kwargs = if let Some(kwnames) = _kwnames { let _kwargs = if let Option::Some(kwnames) = _kwnames {
std::slice::from_raw_parts(_args.offset(_nargs), kwnames.len()) ::std::slice::from_raw_parts(_args.offset(_nargs), kwnames.len())
} else { } else {
&[] &[]
}; };
let _args = std::slice::from_raw_parts(_args, _nargs as usize); let _args = ::std::slice::from_raw_parts(_args, _nargs as usize);
#arg_convert_and_rust_call #arg_convert_and_rust_call
}) })
@ -503,15 +504,15 @@ impl<'a> FnSpec<'a> {
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?; let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?;
quote! { quote! {
unsafe extern "C" fn #ident ( unsafe extern "C" fn #ident (
_slf: *mut pyo3::ffi::PyObject, _slf: *mut ::pyo3::ffi::PyObject,
_args: *mut pyo3::ffi::PyObject, _args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject _kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
{ {
#deprecations #deprecations
pyo3::callback::handle_panic(|#py| { ::pyo3::callback::handle_panic(|#py| {
#self_conversion #self_conversion
let _args = #py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = #py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: ::std::option::Option<&::pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
#arg_convert_and_rust_call #arg_convert_and_rust_call
}) })
@ -523,20 +524,20 @@ impl<'a> FnSpec<'a> {
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?; let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?;
quote! { quote! {
unsafe extern "C" fn #ident ( unsafe extern "C" fn #ident (
subtype: *mut pyo3::ffi::PyTypeObject, subtype: *mut ::pyo3::ffi::PyTypeObject,
_args: *mut pyo3::ffi::PyObject, _args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject _kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
{ {
#deprecations #deprecations
use pyo3::callback::IntoPyCallbackOutput; use ::pyo3::callback::IntoPyCallbackOutput;
pyo3::callback::handle_panic(|#py| { ::pyo3::callback::handle_panic(|#py| {
let _args = #py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = #py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: ::std::option::Option<&::pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
let result = #arg_convert_and_rust_call; let result = #arg_convert_and_rust_call;
let initializer: pyo3::PyClassInitializer::<#cls> = result.convert(#py)?; let initializer: ::pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
let cell = initializer.create_cell_from_subtype(#py, subtype)?; let cell = initializer.create_cell_from_subtype(#py, subtype)?;
Ok(cell as *mut pyo3::ffi::PyObject) Ok(cell as *mut ::pyo3::ffi::PyObject)
}) })
} }
} }
@ -551,23 +552,23 @@ impl<'a> FnSpec<'a> {
let doc = &self.doc; let doc = &self.doc;
match self.convention { match self.convention {
CallingConvention::Noargs => quote! { CallingConvention::Noargs => quote! {
pyo3::class::methods::PyMethodDef::noargs( ::pyo3::class::methods::PyMethodDef::noargs(
#python_name, #python_name,
pyo3::class::methods::PyCFunction(#wrapper), ::pyo3::class::methods::PyCFunction(#wrapper),
#doc, #doc,
) )
}, },
CallingConvention::Fastcall => quote! { CallingConvention::Fastcall => quote! {
pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords( ::pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords(
#python_name, #python_name,
pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper), ::pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper),
#doc, #doc,
) )
}, },
CallingConvention::Varargs => quote! { CallingConvention::Varargs => quote! {
pyo3::class::methods::PyMethodDef::cfunction_with_keywords( ::pyo3::class::methods::PyMethodDef::cfunction_with_keywords(
#python_name, #python_name,
pyo3::class::methods::PyCFunctionWithKeywords(#wrapper), ::pyo3::class::methods::PyCFunctionWithKeywords(#wrapper),
#doc, #doc,
) )
}, },

View File

@ -73,15 +73,15 @@ pub fn py_init(fnname: &Ident, options: PyModuleOptions, doc: syn::LitStr) -> To
#[allow(non_snake_case)] #[allow(non_snake_case)]
/// This autogenerated function is called by the python interpreter when importing /// This autogenerated function is called by the python interpreter when importing
/// the module. /// the module.
pub unsafe extern "C" fn #cb_name() -> *mut pyo3::ffi::PyObject { pub unsafe extern "C" fn #cb_name() -> *mut ::pyo3::ffi::PyObject {
use pyo3::derive_utils::ModuleDef; use ::pyo3::derive_utils::ModuleDef;
static NAME: &str = concat!(stringify!(#name), "\0"); static NAME: &str = concat!(stringify!(#name), "\0");
static DOC: &str = #doc; static DOC: &str = #doc;
static MODULE_DEF: ModuleDef = unsafe { ModuleDef::new(NAME, DOC) }; static MODULE_DEF: ModuleDef = unsafe { ModuleDef::new(NAME, DOC) };
#deprecations #deprecations
pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(_py, #fnname) }) ::pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(_py, #fnname) })
} }
} }
} }

View File

@ -123,9 +123,9 @@ pub fn impl_arg_params(
let (accept_args, accept_kwargs) = accept_args_kwargs(&spec.attrs); let (accept_args, accept_kwargs) = accept_args_kwargs(&spec.attrs);
let cls_name = if let Some(cls) = self_ { let cls_name = if let Some(cls) = self_ {
quote! { Some(<#cls as pyo3::type_object::PyTypeInfo>::NAME) } quote! { ::std::option::Option::Some(<#cls as pyo3::type_object::PyTypeInfo>::NAME) }
} else { } else {
quote! { None } quote! { ::std::option::Option::None }
}; };
let python_name = &spec.python_name; let python_name = &spec.python_name;
@ -134,8 +134,9 @@ pub fn impl_arg_params(
// keyword names of the keyword args in _kwargs // keyword names of the keyword args in _kwargs
( (
// need copied() for &&PyAny -> &PyAny // need copied() for &&PyAny -> &PyAny
quote! { _args.iter().copied() }, quote! { ::std::iter::Iterator::copied(_args.iter()) },
quote! { _kwnames.map(|kwnames| { quote! { _kwnames.map(|kwnames| {
use ::std::iter::Iterator;
kwnames.as_slice().iter().copied().zip(_kwargs.iter().copied()) kwnames.as_slice().iter().copied().zip(_kwargs.iter().copied())
}) }, }) },
) )
@ -149,7 +150,7 @@ pub fn impl_arg_params(
// create array of arguments, and then parse // create array of arguments, and then parse
Ok(quote! {{ Ok(quote! {{
const DESCRIPTION: pyo3::derive_utils::FunctionDescription = pyo3::derive_utils::FunctionDescription { const DESCRIPTION: ::pyo3::derive_utils::FunctionDescription = ::pyo3::derive_utils::FunctionDescription {
cls_name: #cls_name, cls_name: #cls_name,
func_name: stringify!(#python_name), func_name: stringify!(#python_name),
positional_parameter_names: &[#(#positional_parameter_names),*], positional_parameter_names: &[#(#positional_parameter_names),*],
@ -161,7 +162,7 @@ pub fn impl_arg_params(
accept_varkeywords: #accept_kwargs, accept_varkeywords: #accept_kwargs,
}; };
let mut #args_array = [None; #num_params]; let mut #args_array = [::std::option::Option::None; #num_params];
let (_args, _kwargs) = DESCRIPTION.extract_arguments( let (_args, _kwargs) = DESCRIPTION.extract_arguments(
#py, #py,
#args_to_extract, #args_to_extract,
@ -201,7 +202,7 @@ fn impl_arg_param(
let ty = arg.ty; let ty = arg.ty;
let name = arg.name; let name = arg.name;
let transform_error = quote! { let transform_error = quote! {
|e| pyo3::derive_utils::argument_extraction_error(#py, stringify!(#name), e) |e| ::pyo3::derive_utils::argument_extraction_error(#py, stringify!(#name), e)
}; };
if is_args(&spec.attrs, name) { if is_args(&spec.attrs, name) {

View File

@ -433,9 +433,9 @@ pub fn impl_wrap_pyfunction(
let wrapped_pyfunction = quote! { let wrapped_pyfunction = quote! {
#wrapper #wrapper
pub(crate) fn #function_wrapper_ident<'a>( pub(crate) fn #function_wrapper_ident<'a>(
args: impl Into<pyo3::derive_utils::PyFunctionArguments<'a>> args: impl ::std::convert::Into<::pyo3::derive_utils::PyFunctionArguments<'a>>
) -> pyo3::PyResult<&'a pyo3::types::PyCFunction> { ) -> ::pyo3::PyResult<&'a ::pyo3::types::PyCFunction> {
pyo3::types::PyCFunction::internal_new(#methoddef, args.into()) ::pyo3::types::PyCFunction::internal_new(#methoddef, args.into())
} }
}; };
Ok((function_wrapper_ident, wrapped_pyfunction)) Ok((function_wrapper_ident, wrapped_pyfunction))

View File

@ -358,11 +358,13 @@ pub mod proc_macro {
#[macro_export] #[macro_export]
macro_rules! wrap_pyfunction { macro_rules! wrap_pyfunction {
($function_name: ident) => {{ ($function_name: ident) => {{
&|py| pyo3::paste::expr! { [<__pyo3_get_function_ $function_name>] }(py) &|py| $crate::paste::expr! { [<__pyo3_get_function_ $function_name>] }(py)
}}; }};
($function_name: ident, $arg: expr) => { ($function_name: ident, $arg: expr) => {
pyo3::wrap_pyfunction!($function_name)(pyo3::derive_utils::PyFunctionArguments::from($arg)) $crate::wrap_pyfunction!($function_name)(
<$crate::derive_utils::PyFunctionArguments as ::std::convert::From<_>>::from($arg),
)
}; };
} }
@ -372,8 +374,8 @@ macro_rules! wrap_pyfunction {
#[macro_export] #[macro_export]
macro_rules! wrap_pymodule { macro_rules! wrap_pymodule {
($module_name:ident) => {{ ($module_name:ident) => {{
pyo3::paste::expr! { $crate::paste::expr! {
&|py| unsafe { pyo3::PyObject::from_owned_ptr(py, [<PyInit_ $module_name>]()) } &|py| unsafe { $crate::PyObject::from_owned_ptr(py, [<PyInit_ $module_name>]()) }
} }
}}; }};
} }
@ -479,14 +481,15 @@ macro_rules! py_run_impl {
$crate::py_run_impl!($py, *d, $code) $crate::py_run_impl!($py, *d, $code)
}}; }};
($py:expr, *$dict:expr, $code:expr) => {{ ($py:expr, *$dict:expr, $code:expr) => {{
if let Err(e) = $py.run($code, None, Some($dict)) { use ::std::option::Option::*;
if let ::std::result::Result::Err(e) = $py.run($code, None, Some($dict)) {
e.print($py); e.print($py);
// So when this c api function the last line called printed the error to stderr, // So when this c api function the last line called printed the error to stderr,
// the output is only written into a buffer which is never flushed because we // the output is only written into a buffer which is never flushed because we
// panic before flushing. This is where this hack comes into place // panic before flushing. This is where this hack comes into place
$py.run("import sys; sys.stderr.flush()", None, None) $py.run("import sys; sys.stderr.flush()", None, None)
.unwrap(); .unwrap();
panic!("{}", $code) ::std::panic!("{}", $code)
} }
}}; }};
} }

View File

@ -42,3 +42,22 @@ impl ::pyo3::class::gc::PyGCProtocol for Bar {
self.c = ::std::option::Option::None; self.c = ::std::option::Option::None;
} }
} }
#[::pyo3::proc_macro::pyfunction]
fn do_something(x: i32) -> ::pyo3::PyResult<i32> {
::std::result::Result::Ok(x)
}
#[::pyo3::proc_macro::pymodule]
fn my_module(_py: ::pyo3::Python, m: &::pyo3::types::PyModule) -> ::pyo3::PyResult<()> {
m.add_function(::pyo3::wrap_pyfunction!(do_something, m)?)?;
::std::result::Result::Ok(())
}
#[test]
fn invoke_wrap_pyfunction() {
::pyo3::Python::with_gil(|py| {
let func = ::pyo3::wrap_pyfunction!(do_something)(py).unwrap();
::pyo3::py_run!(py, func, r#"func(5)"#);
});
}