From ea9da80ab181a30651db77eaf456544ddc002c67 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 20 Nov 2022 08:48:47 +0100 Subject: [PATCH] macros: fix the check for applying `METH_NOARGS` to only consider the Python argument list. Fixes #2750 --- newsfragments/2760.fixed.md | 2 ++ pyo3-macros-backend/src/method.rs | 9 +++++++-- pyo3-macros-backend/src/pyfunction/signature.rs | 9 +++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 newsfragments/2760.fixed.md diff --git a/newsfragments/2760.fixed.md b/newsfragments/2760.fixed.md new file mode 100644 index 00000000..65f543e6 --- /dev/null +++ b/newsfragments/2760.fixed.md @@ -0,0 +1,2 @@ +Also apply the `NOARGS` argument convention to methods that have a single +`py: Python` argument. diff --git a/pyo3-macros-backend/src/method.rs b/pyo3-macros-backend/src/method.rs index 742f50d4..32df7e6c 100644 --- a/pyo3-macros-backend/src/method.rs +++ b/pyo3-macros-backend/src/method.rs @@ -200,7 +200,7 @@ impl CallingConvention { /// Different other slots (tp_call, tp_new) can have other requirements /// and are set manually (see `parse_fn_type` below). pub fn from_signature(signature: &FunctionSignature<'_>) -> Self { - if signature.arguments.is_empty() { + if signature.python_signature.has_no_args() { Self::Noargs } else if signature.python_signature.accepts_kwargs { // for functions that accept **kwargs, always prefer varargs @@ -457,7 +457,12 @@ impl<'a> FnSpec<'a> { Ok(match self.convention { CallingConvention::Noargs => { - let call = rust_call(vec![]); + let call = if !self.signature.arguments.is_empty() { + // Only `py` arg can be here + rust_call(vec![quote!(#py)]) + } else { + rust_call(vec![]) + }; quote! { unsafe fn #ident<'py>( #py: _pyo3::Python<'py>, diff --git a/pyo3-macros-backend/src/pyfunction/signature.rs b/pyo3-macros-backend/src/pyfunction/signature.rs index e66f14bc..df73fe12 100644 --- a/pyo3-macros-backend/src/pyfunction/signature.rs +++ b/pyo3-macros-backend/src/pyfunction/signature.rs @@ -211,6 +211,15 @@ pub struct PythonSignature { pub accepts_kwargs: bool, } +impl PythonSignature { + pub fn has_no_args(&self) -> bool { + self.positional_parameters.is_empty() + && self.keyword_only_parameters.is_empty() + && !self.accepts_varargs + && !self.accepts_kwargs + } +} + pub struct FunctionSignature<'a> { pub arguments: Vec>, pub python_signature: PythonSignature,