Merge pull request #1837 from davidhewitt/more-proc-macro-hygiene
pyo3-macros-backend: more tests for macro hygiene
This commit is contained in:
commit
a6d6367241
|
@ -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::<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)
|
||||
};
|
||||
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::<pyo3::types::PyTuple>(_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::<pyo3::types::PyTuple>(_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,
|
||||
)
|
||||
},
|
||||
|
|
|
@ -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) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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::derive_utils::PyFunctionArguments<'a>>
|
||||
) -> 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))
|
||||
|
|
15
src/lib.rs
15
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, [<PyInit_ $module_name>]()) }
|
||||
$crate::paste::expr! {
|
||||
&|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)
|
||||
}};
|
||||
($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)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -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<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)"#);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue