pyo3-macros-backend: more tests for macro hygiene
This commit is contained in:
parent
667865e2d7
commit
313610993a
|
@ -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,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -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) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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))
|
||||||
|
|
15
src/lib.rs
15
src/lib.rs
|
@ -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)
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)"#);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue