Argument parsing: use VARARGS for *any* function taking **kwds

This commit is contained in:
Georg Brandl 2021-06-05 19:39:32 +02:00
parent a290971759
commit f12c1a4005
2 changed files with 20 additions and 19 deletions

View File

@ -1,7 +1,7 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::attributes::TextSignatureAttribute;
use crate::params::{impl_arg_params, is_forwarded_args};
use crate::params::{accept_args_kwargs, impl_arg_params};
use crate::pyfunction::PyFunctionOptions;
use crate::pyfunction::{PyFunctionArgPyO3Attributes, PyFunctionSignature};
use crate::utils;
@ -171,10 +171,11 @@ 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_args(args: &[FnArg<'_>], attrs: &[Argument]) -> Self {
let (_, accept_kwargs) = accept_args_kwargs(attrs);
if args.is_empty() {
Self::Noargs
} else if is_forwarded_args(args, attrs) {
// for f(*args, **kwds), always prefer varargs
} else if accept_kwargs {
// for functions that accept **kwargs, always prefer varargs
Self::Varargs
} else if cfg!(all(Py_3_7, not(Py_LIMITED_API))) {
Self::Fastcall
@ -221,21 +222,6 @@ pub fn parse_method_receiver(arg: &syn::FnArg) -> Result<SelfType> {
}
impl<'a> FnSpec<'a> {
/// Determine if the function gets passed a *args tuple or **kwargs dict.
pub fn accept_args_kwargs(&self) -> (bool, bool) {
let (mut accept_args, mut accept_kwargs) = (false, false);
for s in &self.attrs {
match s {
Argument::VarArgs(_) => accept_args = true,
Argument::KeywordArgs(_) => accept_kwargs = true,
_ => continue,
}
}
(accept_args, accept_kwargs)
}
/// Parser function signature and function attributes
pub fn parse(
sig: &'a mut syn::Signature,

View File

@ -11,6 +11,21 @@ use syn::ext::IdentExt;
use syn::spanned::Spanned;
use syn::Result;
/// Determine if the function gets passed a *args tuple or **kwargs dict.
pub fn accept_args_kwargs(attrs: &[Argument]) -> (bool, bool) {
let (mut accept_args, mut accept_kwargs) = (false, false);
for s in attrs {
match s {
Argument::VarArgs(_) => accept_args = true,
Argument::KeywordArgs(_) => accept_kwargs = true,
_ => continue,
}
}
(accept_args, accept_kwargs)
}
/// Return true if the argument list is simply (*args, **kwds).
pub fn is_forwarded_args(args: &[FnArg<'_>], attrs: &[Argument]) -> bool {
args.len() == 2 && is_args(attrs, &args[0].name) && is_kwargs(attrs, &args[1].name)
@ -112,7 +127,7 @@ pub fn impl_arg_params(
)?);
}
let (accept_args, accept_kwargs) = spec.accept_args_kwargs();
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) }