From 313610993adb05163c812cd3f354c3c827aabade Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 27 Aug 2021 23:22:09 +0100 Subject: [PATCH] pyo3-macros-backend: more tests for macro hygiene --- pyo3-macros-backend/src/method.rs | 77 ++++++++++++++------------- pyo3-macros-backend/src/module.rs | 6 +-- pyo3-macros-backend/src/params.rs | 13 ++--- pyo3-macros-backend/src/pyfunction.rs | 6 +-- src/lib.rs | 15 +++--- tests/test_proc_macro_hygiene.rs | 19 +++++++ 6 files changed, 80 insertions(+), 56 deletions(-) diff --git a/pyo3-macros-backend/src/method.rs b/pyo3-macros-backend/src/method.rs index 603f8df6..7e27e92e 100644 --- a/pyo3-macros-backend/src/method.rs +++ b/pyo3-macros-backend/src/method.rs @@ -103,12 +103,12 @@ impl FnType { } FnType::FnClass => { 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 => { quote! { - let _slf = _py.from_borrowed_ptr::(_slf); + let _slf = _py.from_borrowed_ptr::<::pyo3::types::PyModule>(_slf); } } } @@ -455,17 +455,17 @@ impl<'a> FnSpec<'a> { quote!(#func_name) }; 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 { CallingConvention::Noargs => { quote! { unsafe extern "C" fn #ident ( - _slf: *mut pyo3::ffi::PyObject, - _args: *mut pyo3::ffi::PyObject, - ) -> *mut pyo3::ffi::PyObject + _slf: *mut ::pyo3::ffi::PyObject, + _args: *mut ::pyo3::ffi::PyObject, + ) -> *mut ::pyo3::ffi::PyObject { #deprecations - pyo3::callback::handle_panic(|#py| { + ::pyo3::callback::handle_panic(|#py| { #self_conversion #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)?; quote! { unsafe extern "C" fn #ident ( - _slf: *mut pyo3::ffi::PyObject, - _args: *const *mut pyo3::ffi::PyObject, - _nargs: pyo3::ffi::Py_ssize_t, - _kwnames: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject + _slf: *mut ::pyo3::ffi::PyObject, + _args: *const *mut ::pyo3::ffi::PyObject, + _nargs: ::pyo3::ffi::Py_ssize_t, + _kwnames: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject { #deprecations - pyo3::callback::handle_panic(|#py| { + ::pyo3::callback::handle_panic(|#py| { #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` - let _args = _args as *const &pyo3::PyAny; - let _kwargs = if let Some(kwnames) = _kwnames { - std::slice::from_raw_parts(_args.offset(_nargs), kwnames.len()) + let _args = _args as *const &::pyo3::PyAny; + let _kwargs = if let Option::Some(kwnames) = _kwnames { + ::std::slice::from_raw_parts(_args.offset(_nargs), kwnames.len()) } 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 }) @@ -503,15 +504,15 @@ impl<'a> FnSpec<'a> { let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?; quote! { unsafe extern "C" fn #ident ( - _slf: *mut pyo3::ffi::PyObject, - _args: *mut pyo3::ffi::PyObject, - _kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject + _slf: *mut ::pyo3::ffi::PyObject, + _args: *mut ::pyo3::ffi::PyObject, + _kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject { #deprecations - pyo3::callback::handle_panic(|#py| { + ::pyo3::callback::handle_panic(|#py| { #self_conversion - let _args = #py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs); + let _args = #py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args); + let _kwargs: ::std::option::Option<&::pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs); #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)?; quote! { unsafe extern "C" fn #ident ( - subtype: *mut pyo3::ffi::PyTypeObject, - _args: *mut pyo3::ffi::PyObject, - _kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject + subtype: *mut ::pyo3::ffi::PyTypeObject, + _args: *mut ::pyo3::ffi::PyObject, + _kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject { #deprecations - use pyo3::callback::IntoPyCallbackOutput; - pyo3::callback::handle_panic(|#py| { - let _args = #py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs); + use ::pyo3::callback::IntoPyCallbackOutput; + ::pyo3::callback::handle_panic(|#py| { + let _args = #py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args); + let _kwargs: ::std::option::Option<&::pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs); 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)?; - 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; match self.convention { CallingConvention::Noargs => quote! { - pyo3::class::methods::PyMethodDef::noargs( + ::pyo3::class::methods::PyMethodDef::noargs( #python_name, - pyo3::class::methods::PyCFunction(#wrapper), + ::pyo3::class::methods::PyCFunction(#wrapper), #doc, ) }, CallingConvention::Fastcall => quote! { - pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords( + ::pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords( #python_name, - pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper), + ::pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper), #doc, ) }, CallingConvention::Varargs => quote! { - pyo3::class::methods::PyMethodDef::cfunction_with_keywords( + ::pyo3::class::methods::PyMethodDef::cfunction_with_keywords( #python_name, - pyo3::class::methods::PyCFunctionWithKeywords(#wrapper), + ::pyo3::class::methods::PyCFunctionWithKeywords(#wrapper), #doc, ) }, diff --git a/pyo3-macros-backend/src/module.rs b/pyo3-macros-backend/src/module.rs index e4efe4fa..e92272ad 100644 --- a/pyo3-macros-backend/src/module.rs +++ b/pyo3-macros-backend/src/module.rs @@ -73,15 +73,15 @@ pub fn py_init(fnname: &Ident, options: PyModuleOptions, doc: syn::LitStr) -> To #[allow(non_snake_case)] /// This autogenerated function is called by the python interpreter when importing /// the module. - pub unsafe extern "C" fn #cb_name() -> *mut pyo3::ffi::PyObject { - use pyo3::derive_utils::ModuleDef; + pub unsafe extern "C" fn #cb_name() -> *mut ::pyo3::ffi::PyObject { + use ::pyo3::derive_utils::ModuleDef; static NAME: &str = concat!(stringify!(#name), "\0"); static DOC: &str = #doc; static MODULE_DEF: ModuleDef = unsafe { ModuleDef::new(NAME, DOC) }; #deprecations - pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(_py, #fnname) }) + ::pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(_py, #fnname) }) } } } diff --git a/pyo3-macros-backend/src/params.rs b/pyo3-macros-backend/src/params.rs index fbc3f000..0d64f183 100644 --- a/pyo3-macros-backend/src/params.rs +++ b/pyo3-macros-backend/src/params.rs @@ -123,9 +123,9 @@ pub fn impl_arg_params( let (accept_args, accept_kwargs) = accept_args_kwargs(&spec.attrs); 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 { - quote! { None } + quote! { ::std::option::Option::None } }; let python_name = &spec.python_name; @@ -134,8 +134,9 @@ pub fn impl_arg_params( // keyword names of the keyword args in _kwargs ( // need copied() for &&PyAny -> &PyAny - quote! { _args.iter().copied() }, + quote! { ::std::iter::Iterator::copied(_args.iter()) }, quote! { _kwnames.map(|kwnames| { + use ::std::iter::Iterator; 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 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, func_name: stringify!(#python_name), positional_parameter_names: &[#(#positional_parameter_names),*], @@ -161,7 +162,7 @@ pub fn impl_arg_params( 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( #py, #args_to_extract, @@ -201,7 +202,7 @@ fn impl_arg_param( let ty = arg.ty; let name = arg.name; 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) { diff --git a/pyo3-macros-backend/src/pyfunction.rs b/pyo3-macros-backend/src/pyfunction.rs index ccc37611..effdd390 100644 --- a/pyo3-macros-backend/src/pyfunction.rs +++ b/pyo3-macros-backend/src/pyfunction.rs @@ -433,9 +433,9 @@ pub fn impl_wrap_pyfunction( let wrapped_pyfunction = quote! { #wrapper pub(crate) fn #function_wrapper_ident<'a>( - args: impl Into> - ) -> pyo3::PyResult<&'a pyo3::types::PyCFunction> { - pyo3::types::PyCFunction::internal_new(#methoddef, args.into()) + args: impl ::std::convert::Into<::pyo3::derive_utils::PyFunctionArguments<'a>> + ) -> ::pyo3::PyResult<&'a ::pyo3::types::PyCFunction> { + ::pyo3::types::PyCFunction::internal_new(#methoddef, args.into()) } }; Ok((function_wrapper_ident, wrapped_pyfunction)) diff --git a/src/lib.rs b/src/lib.rs index 750d31af..df6e8f1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -358,11 +358,13 @@ pub mod proc_macro { #[macro_export] macro_rules! wrap_pyfunction { ($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) => { - 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_rules! wrap_pymodule { ($module_name:ident) => {{ - pyo3::paste::expr! { - &|py| unsafe { pyo3::PyObject::from_owned_ptr(py, []()) } + $crate::paste::expr! { + &|py| unsafe { $crate::PyObject::from_owned_ptr(py, []()) } } }}; } @@ -479,14 +481,15 @@ macro_rules! py_run_impl { $crate::py_run_impl!($py, *d, $code) }}; ($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); // 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 // panic before flushing. This is where this hack comes into place $py.run("import sys; sys.stderr.flush()", None, None) .unwrap(); - panic!("{}", $code) + ::std::panic!("{}", $code) } }}; } diff --git a/tests/test_proc_macro_hygiene.rs b/tests/test_proc_macro_hygiene.rs index 56341285..ac54e557 100644 --- a/tests/test_proc_macro_hygiene.rs +++ b/tests/test_proc_macro_hygiene.rs @@ -42,3 +42,22 @@ impl ::pyo3::class::gc::PyGCProtocol for Bar { self.c = ::std::option::Option::None; } } + +#[::pyo3::proc_macro::pyfunction] +fn do_something(x: i32) -> ::pyo3::PyResult { + ::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)"#); + }); +}