[pydocstyle] Add setting to ignore missing documentation for*args and **kwargs parameters (D417) (#15210)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
InSync 2024-12-31 18:16:55 +07:00 committed by GitHub
parent 3c9021ffcb
commit cfd6093579
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 285 additions and 50 deletions

View file

@ -168,3 +168,12 @@ def select_data(
database:
Which database to connect to ("origin" or "destination").
"""
def f(x, *args, **kwargs):
"""Do something.
Args:
x: the value
*args: var-arguments
"""
return x

View file

@ -37,7 +37,10 @@ mod tests {
let diagnostics = test_path(
Path::new("pydoclint").join(path).as_path(),
&settings::LinterSettings {
pydocstyle: pydocstyle::settings::Settings::new(Some(Convention::Google), [], []),
pydocstyle: pydocstyle::settings::Settings {
convention: Some(Convention::Google),
..pydocstyle::settings::Settings::default()
},
..settings::LinterSettings::for_rule(rule_code)
},
)?;
@ -56,7 +59,10 @@ mod tests {
let diagnostics = test_path(
Path::new("pydoclint").join(path).as_path(),
&settings::LinterSettings {
pydocstyle: pydocstyle::settings::Settings::new(Some(Convention::Numpy), [], []),
pydocstyle: pydocstyle::settings::Settings {
convention: Some(Convention::Numpy),
..pydocstyle::settings::Settings::default()
},
..settings::LinterSettings::for_rule(rule_code)
},
)?;

View file

@ -12,11 +12,10 @@ mod tests {
use crate::registry::Rule;
use super::settings::{Convention, Settings};
use crate::test::test_path;
use crate::{assert_messages, settings};
use super::settings::{Convention, Settings};
#[test_case(Rule::MissingBlankLineAfterLastSection, Path::new("sections.py"))]
#[test_case(Rule::NoBlankLineAfterSection, Path::new("sections.py"))]
#[test_case(Rule::MissingBlankLineAfterLastSection, Path::new("D413.py"))]
@ -100,11 +99,13 @@ mod tests {
let diagnostics = test_path(
Path::new("pydocstyle").join(path).as_path(),
&settings::LinterSettings {
pydocstyle: Settings::new(
None,
["functools.wraps".to_string()],
["gi.repository.GObject.Property".to_string()],
),
pydocstyle: Settings {
ignore_decorators: ["functools.wraps".to_string()].into_iter().collect(),
property_decorators: ["gi.repository.GObject.Property".to_string()]
.into_iter()
.collect(),
..Settings::default()
},
..settings::LinterSettings::for_rule(rule_code)
},
)?;
@ -137,13 +138,46 @@ mod tests {
Ok(())
}
#[test]
fn d417_unspecified_ignore_var_parameters() -> Result<()> {
let diagnostics = test_path(
Path::new("pydocstyle/D417.py"),
&settings::LinterSettings {
pydocstyle: Settings::default(),
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn d417_google() -> Result<()> {
let diagnostics = test_path(
Path::new("pydocstyle/D417.py"),
&settings::LinterSettings {
// With explicit Google convention, we should flag every function.
pydocstyle: Settings::new(Some(Convention::Google), [], []),
pydocstyle: Settings {
convention: Some(Convention::Google),
..Settings::default()
},
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn d417_google_ignore_var_parameters() -> Result<()> {
let diagnostics = test_path(
Path::new("pydocstyle/D417.py"),
&settings::LinterSettings {
pydocstyle: Settings {
convention: Some(Convention::Google),
ignore_var_parameters: true,
..Settings::default()
},
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
},
)?;
@ -157,7 +191,10 @@ mod tests {
Path::new("pydocstyle/D417.py"),
&settings::LinterSettings {
// With explicit numpy convention, we shouldn't flag anything.
pydocstyle: Settings::new(Some(Convention::Numpy), [], []),
pydocstyle: Settings {
convention: Some(Convention::Numpy),
..Settings::default()
},
..settings::LinterSettings::for_rule(Rule::UndocumentedParam)
},
)?;

View file

@ -1215,6 +1215,7 @@ impl AlwaysFixableViolation for MissingSectionNameColon {
///
/// ## Options
/// - `lint.pydocstyle.convention`
/// - `lint.pydocstyle.ignore-var-parameters`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@ -1810,24 +1811,26 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: &
// Check specifically for `vararg` and `kwarg`, which can be prefixed with a
// single or double star, respectively.
if let Some(arg) = function.parameters.vararg.as_ref() {
let arg_name = arg.name.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)
{
missing_arg_names.insert(starred_arg_name);
if !checker.settings.pydocstyle.ignore_var_parameters() {
if let Some(arg) = function.parameters.vararg.as_ref() {
let arg_name = arg.name.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)
{
missing_arg_names.insert(starred_arg_name);
}
}
}
if let Some(arg) = function.parameters.kwarg.as_ref() {
let arg_name = arg.name.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)
{
missing_arg_names.insert(starred_arg_name);
if let Some(arg) = function.parameters.kwarg.as_ref() {
let arg_name = arg.name.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)
{
missing_arg_names.insert(starred_arg_name);
}
}
}

View file

@ -87,25 +87,13 @@ impl fmt::Display for Convention {
#[derive(Debug, Clone, Default, CacheKey)]
pub struct Settings {
convention: Option<Convention>,
ignore_decorators: BTreeSet<String>,
property_decorators: BTreeSet<String>,
pub convention: Option<Convention>,
pub ignore_decorators: BTreeSet<String>,
pub property_decorators: BTreeSet<String>,
pub ignore_var_parameters: bool,
}
impl Settings {
#[must_use]
pub fn new(
convention: Option<Convention>,
ignore_decorators: impl IntoIterator<Item = String>,
property_decorators: impl IntoIterator<Item = String>,
) -> Self {
Self {
convention,
ignore_decorators: ignore_decorators.into_iter().collect(),
property_decorators: property_decorators.into_iter().collect(),
}
}
pub fn convention(&self) -> Option<Convention> {
self.convention
}
@ -117,6 +105,10 @@ impl Settings {
pub fn property_decorators(&self) -> DecoratorIterator {
DecoratorIterator::new(&self.property_decorators)
}
pub fn ignore_var_parameters(&self) -> bool {
self.ignore_var_parameters
}
}
impl fmt::Display for Settings {
@ -127,7 +119,8 @@ impl fmt::Display for Settings {
fields = [
self.convention | optional,
self.ignore_decorators | set,
self.property_decorators | set
self.property_decorators | set,
self.ignore_var_parameters
]
}
Ok(())

View file

@ -72,3 +72,12 @@ D417.py:155:5: D417 Missing argument description in the docstring for `select_da
156 | query: str,
157 | args: tuple,
|
D417.py:172:5: D417 Missing argument description in the docstring for `f`: `**kwargs`
|
170 | """
171 |
172 | def f(x, *args, **kwargs):
| ^ D417
173 | """Do something.
|

View file

@ -0,0 +1,67 @@
---
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
snapshot_kind: text
---
D417.py:1:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
1 | def f(x, y, z):
| ^ D417
2 | """Do something.
|
D417.py:14:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
14 | def f(x, y, z):
| ^ D417
15 | """Do something.
|
D417.py:27:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
27 | def f(x, y, z):
| ^ D417
28 | """Do something.
|
D417.py:39:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
39 | def f(x, y, z):
| ^ D417
40 | """Do something.
|
D417.py:52:5: D417 Missing argument description in the docstring for `f`: `y`
|
52 | def f(x, y, z):
| ^ D417
53 | """Do something.
|
D417.py:65:5: D417 Missing argument description in the docstring for `f`: `y`
|
65 | def f(x, y, z):
| ^ D417
66 | """Do something.
|
D417.py:77:5: D417 Missing argument description in the docstring for `f`: `y`
|
77 | def f(x, y, z):
| ^ D417
78 | """Do something.
|
D417.py:98:5: D417 Missing argument description in the docstring for `f`: `x`
|
98 | def f(x, *args, **kwargs):
| ^ D417
99 | """Do something.
|
D417.py:155:5: D417 Missing argument description in the docstring for `select_data`: `auto_save`
|
155 | def select_data(
| ^^^^^^^^^^^ D417
156 | query: str,
157 | args: tuple,
|

View file

@ -72,3 +72,12 @@ D417.py:155:5: D417 Missing argument description in the docstring for `select_da
156 | query: str,
157 | args: tuple,
|
D417.py:172:5: D417 Missing argument description in the docstring for `f`: `**kwargs`
|
170 | """
171 |
172 | def f(x, *args, **kwargs):
| ^ D417
173 | """Do something.
|

View file

@ -0,0 +1,83 @@
---
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
snapshot_kind: text
---
D417.py:1:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
1 | def f(x, y, z):
| ^ D417
2 | """Do something.
|
D417.py:14:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
14 | def f(x, y, z):
| ^ D417
15 | """Do something.
|
D417.py:27:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
27 | def f(x, y, z):
| ^ D417
28 | """Do something.
|
D417.py:39:5: D417 Missing argument descriptions in the docstring for `f`: `y`, `z`
|
39 | def f(x, y, z):
| ^ D417
40 | """Do something.
|
D417.py:52:5: D417 Missing argument description in the docstring for `f`: `y`
|
52 | def f(x, y, z):
| ^ D417
53 | """Do something.
|
D417.py:65:5: D417 Missing argument description in the docstring for `f`: `y`
|
65 | def f(x, y, z):
| ^ D417
66 | """Do something.
|
D417.py:77:5: D417 Missing argument description in the docstring for `f`: `y`
|
77 | def f(x, y, z):
| ^ D417
78 | """Do something.
|
D417.py:98:5: D417 Missing argument description in the docstring for `f`: `x`
|
98 | def f(x, *args, **kwargs):
| ^ D417
99 | """Do something.
|
D417.py:108:5: D417 Missing argument description in the docstring for `f`: `*args`
|
108 | def f(x, *args, **kwargs):
| ^ D417
109 | """Do something.
|
D417.py:155:5: D417 Missing argument description in the docstring for `select_data`: `auto_save`
|
155 | def select_data(
| ^^^^^^^^^^^ D417
156 | query: str,
157 | args: tuple,
|
D417.py:172:5: D417 Missing argument description in the docstring for `f`: `**kwargs`
|
170 | """
171 |
172 | def f(x, *args, **kwargs):
| ^ D417
173 | """Do something.
|