Allow varargs and kwargs to be prefixed with stars (#933)

This commit is contained in:
Charlie Marsh 2022-11-27 22:08:27 -05:00 committed by GitHub
parent 16da183f8e
commit 1a79965aa0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 25 deletions

View file

@ -44,7 +44,7 @@ expectation.expected.add((
@expect("D407: Missing dashed underline after section ('Returns')", @expect("D407: Missing dashed underline after section ('Returns')",
arg_count=3) arg_count=3)
@expect("D413: Missing blank line after last section ('Raises')", arg_count=3) @expect("D413: Missing blank line after last section ('Raises')", arg_count=3)
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): def fetch_bigtable_rows(big_table, keys, other_silly_variable=None, **kwargs):
"""Fetches rows from a Bigtable. """Fetches rows from a Bigtable.
Retrieves rows pertaining to the given keys from the Table instance Retrieves rows pertaining to the given keys from the Table instance
@ -57,6 +57,7 @@ def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
to fetch. to fetch.
other_silly_variable: Another optional variable, that has a much other_silly_variable: Another optional variable, that has a much
longer name than the other args, and which does nothing. longer name than the other args, and which does nothing.
**kwargs: More keyword arguments.
Returns: Returns:
A dict mapping keys to the corresponding table row data A dict mapping keys to the corresponding table row data

View file

@ -73,7 +73,7 @@ expectation.expected.add((
"(found 'A')", arg_count=3) "(found 'A')", arg_count=3)
@expect("D413: Missing blank line after last section ('Examples')", @expect("D413: Missing blank line after last section ('Examples')",
arg_count=3) arg_count=3)
def foo(var1, var2, long_var_name='hi'): def foo(var1, var2, long_var_name='hi', **kwargs):
r"""A one-line summary that does not use variable names. r"""A one-line summary that does not use variable names.
Several sentences providing an extended description. Refer to Several sentences providing an extended description. Refer to
@ -91,6 +91,8 @@ def foo(var1, var2, long_var_name='hi'):
detail, e.g. ``(N,) ndarray`` or ``array_like``. detail, e.g. ``(N,) ndarray`` or ``array_like``.
long_var_name : {'hi', 'ho'}, optional long_var_name : {'hi', 'ho'}, optional
Choices in brackets, default first when optional. Choices in brackets, default first when optional.
**kwargs : int
More keyword arguments.
Returns Returns
------- -------

View file

@ -4,7 +4,7 @@ use itertools::Itertools;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind}; use rustpython_ast::{Constant, ExprKind, Location, StmtKind};
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::ast::whitespace; use crate::ast::whitespace;
@ -1303,8 +1303,9 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args:
args: arguments, .. args: arguments, ..
} = &parent.node } = &parent.node
{ {
// Collect all the arguments into a single vector. // Look for arguments that weren't included in the docstring.
let mut all_arguments: Vec<&Arg> = arguments let mut missing_arg_names: BTreeSet<String> = BTreeSet::default();
for arg in arguments
.args .args
.iter() .iter()
.chain(arguments.posonlyargs.iter()) .chain(arguments.posonlyargs.iter())
@ -1316,33 +1317,38 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args:
&& !is_staticmethod(parent), && !is_staticmethod(parent),
), ),
) )
.collect(); {
let arg_name = arg.node.arg.as_str();
if !arg_name.starts_with('_') && !docstrings_args.contains(&arg_name) {
missing_arg_names.insert(arg_name.to_string());
}
}
// Check specifically for `vararg` and `kwarg`, which can be prefixed with a single or
// double star, respectively.
if let Some(arg) = &arguments.vararg { if let Some(arg) = &arguments.vararg {
all_arguments.push(arg); let arg_name = arg.node.arg.as_str();
let starred_arg_name = format!("*{arg_name}");
if !arg_name.starts_with('_')
&& !docstrings_args.contains(&arg_name)
&& !docstrings_args.contains(&starred_arg_name.as_str())
{
missing_arg_names.insert(starred_arg_name);
}
} }
if let Some(arg) = &arguments.kwarg { if let Some(arg) = &arguments.kwarg {
all_arguments.push(arg);
}
// Look for arguments that weren't included in the docstring.
let mut missing_args: BTreeSet<&str> = BTreeSet::default();
for arg in all_arguments {
let arg_name = arg.node.arg.as_str(); let arg_name = arg.node.arg.as_str();
if arg_name.starts_with('_') { let starred_arg_name = format!("**{arg_name}");
continue; if !arg_name.starts_with('_')
&& !docstrings_args.contains(&arg_name)
&& !docstrings_args.contains(&starred_arg_name.as_str())
{
missing_arg_names.insert(starred_arg_name);
} }
if docstrings_args.contains(&arg_name) {
continue;
}
missing_args.insert(arg_name);
} }
if !missing_args.is_empty() { if !missing_arg_names.is_empty() {
let names = missing_args let names = missing_arg_names.into_iter().sorted().collect();
.into_iter()
.map(String::from)
.sorted()
.collect();
checker.add_check(Check::new( checker.add_check(Check::new(
CheckKind::DocumentAllArguments(names), CheckKind::DocumentAllArguments(names),
Range::from_located(parent), Range::from_located(parent),