Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pydoclint] Allow ignoring one line docstrings for DOC rules #13302

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions crates/ruff_linter/src/rules/pydoclint/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Rules from [pydoclint](https://pypi.org/project/pydoclint/).
pub(crate) mod rules;
pub mod settings;

#[cfg(test)]
mod tests {
Expand All @@ -15,6 +16,8 @@ mod tests {
use crate::test::test_path;
use crate::{assert_messages, settings};

use super::settings::Settings;

#[test_case(Rule::DocstringMissingException, Path::new("DOC501.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
Expand Down Expand Up @@ -63,4 +66,27 @@ mod tests {
assert_messages!(snapshot, diagnostics);
Ok(())
}

#[test_case(Rule::DocstringMissingReturns, Path::new("DOC201_google.py"))]
#[test_case(Rule::DocstringMissingYields, Path::new("DOC402_google.py"))]
#[test_case(Rule::DocstringMissingException, Path::new("DOC501_google.py"))]
fn rules_google_style_ignore_one_line(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"{}_{}_ignore_one_line",
rule_code.as_ref(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pydoclint").join(path).as_path(),
&settings::LinterSettings {
pydoclint: Settings {
ignore_one_line_docstrings: true,
},
pydocstyle: pydocstyle::settings::Settings::new(Some(Convention::Google), [], []),
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}
18 changes: 18 additions & 0 deletions crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::{self as ast, visitor, Expr, Stmt};
use ruff_python_semantic::analyze::{function_type, visibility};
use ruff_python_semantic::{Definition, SemanticModel};
use ruff_source_file::NewlineWithTrailingNewline;
use ruff_text_size::{Ranged, TextRange};

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -827,6 +828,19 @@ fn is_generator_function_annotated_as_returning_none(
.is_some_and(GeneratorOrIteratorArguments::indicates_none_returned)
}

fn is_one_line(docstring: &Docstring) -> bool {
let mut non_empty_line_count = 0;
for line in NewlineWithTrailingNewline::from(docstring.body().as_str()) {
if !line.trim().is_empty() {
non_empty_line_count += 1;
}
if non_empty_line_count > 1 {
return false;
}
}
true
}

/// DOC201, DOC202, DOC402, DOC403, DOC501, DOC502
pub(crate) fn check_docstring(
checker: &mut Checker,
Expand All @@ -842,6 +856,10 @@ pub(crate) fn check_docstring(
return;
};

if checker.settings.pydoclint.ignore_one_line_docstrings && is_one_line(docstring) {
return;
}

let semantic = checker.semantic();

// Ignore stubs.
Expand Down
21 changes: 21 additions & 0 deletions crates/ruff_linter/src/rules/pydoclint/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Settings for the `pydoclint` plugin.

use crate::display_settings;
use ruff_macros::CacheKey;
use std::fmt::{Display, Formatter};

#[derive(Debug, Clone, Default, CacheKey)]
pub struct Settings {
pub ignore_one_line_docstrings: bool,
}

impl Display for Settings {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
display_settings! {
formatter = f,
namespace = "linter.pydoclint",
fields = [self.ignore_one_line_docstrings]
}
Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
source: crates/ruff_linter/src/rules/pydoclint/mod.rs
---
DOC501_google.py:46:15: DOC501 Raised exception `FasterThanLightError` missing from docstring
|
44 | return distance / time
45 | except ZeroDivisionError as exc:
46 | raise FasterThanLightError from exc
| ^^^^^^^^^^^^^^^^^^^^ DOC501
|
= help: Add `FasterThanLightError` to the docstring

DOC501_google.py:63:15: DOC501 Raised exception `FasterThanLightError` missing from docstring
|
61 | return distance / time
62 | except ZeroDivisionError as exc:
63 | raise FasterThanLightError from exc
| ^^^^^^^^^^^^^^^^^^^^ DOC501
64 | except:
65 | raise ValueError
|
= help: Add `FasterThanLightError` to the docstring

DOC501_google.py:65:15: DOC501 Raised exception `ValueError` missing from docstring
|
63 | raise FasterThanLightError from exc
64 | except:
65 | raise ValueError
| ^^^^^^^^^^ DOC501
|
= help: Add `ValueError` to the docstring

DOC501_google.py:115:11: DOC501 Raised exception `AnotherError` missing from docstring
|
113 | Speed as distance divided by time.
114 | """
115 | raise AnotherError
| ^^^^^^^^^^^^ DOC501
|
= help: Add `AnotherError` to the docstring

DOC501_google.py:129:11: DOC501 Raised exception `AnotherError` missing from docstring
|
127 | Speed as distance divided by time.
128 | """
129 | raise AnotherError()
| ^^^^^^^^^^^^^^ DOC501
|
= help: Add `AnotherError` to the docstring

DOC501_google.py:139:11: DOC501 Raised exception `SomeError` missing from docstring
|
137 | bar: Bar.
138 | """
139 | raise something.SomeError
| ^^^^^^^^^^^^^^^^^^^ DOC501
|
= help: Add `SomeError` to the docstring

DOC501_google.py:213:9: DOC501 Raised exception `ZeroDivisionError` missing from docstring
|
211 | except ZeroDivisionError:
212 | print("Oh no, why would you divide something by zero?")
213 | raise
| ^^^^^ DOC501
214 | except TypeError:
215 | print("Not a number? Shame on you!")
|
= help: Add `ZeroDivisionError` to the docstring

DOC501_google.py:244:15: DOC501 Raised exception `TypeError` missing from docstring
|
242 | """
243 | if True:
244 | raise TypeError # DOC501
| ^^^^^^^^^ DOC501
245 | else:
246 | raise TypeError # no DOC501 here because we already emitted a diagnostic for the earlier `raise TypeError`
|
= help: Add `TypeError` to the docstring

DOC501_google.py:247:11: DOC501 Raised exception `ValueError` missing from docstring
|
245 | else:
246 | raise TypeError # no DOC501 here because we already emitted a diagnostic for the earlier `raise TypeError`
247 | raise ValueError # DOC501
| ^^^^^^^^^^ DOC501
248 | return 42
|
= help: Add `ValueError` to the docstring
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
source: crates/ruff_linter/src/rules/pydoclint/mod.rs
---
DOC201_google.py:9:5: DOC201 `return` is not documented in docstring
|
7 | num (int): A number
8 | """
9 | return 'test'
| ^^^^^^^^^^^^^ DOC201
|
= help: Add a "Returns" section to the docstring

DOC201_google.py:50:9: DOC201 `return` is not documented in docstring
|
48 | num (int): A number
49 | """
50 | return 'test'
| ^^^^^^^^^^^^^ DOC201
|
= help: Add a "Returns" section to the docstring

DOC201_google.py:184:9: DOC201 `return` is not documented in docstring
|
182 | """
183 | if x < 0:
184 | return None
| ^^^^^^^^^^^ DOC201
185 | else:
186 | return x
|
= help: Add a "Returns" section to the docstring

DOC201_google.py:197:9: DOC201 `return` is not documented in docstring
|
195 | """
196 | if x < 0:
197 | return None
| ^^^^^^^^^^^ DOC201
198 | else:
199 | return x
|
= help: Add a "Returns" section to the docstring

DOC201_google.py:209:5: DOC201 `return` is not documented in docstring
|
207 | s (str): A string.
208 | """
209 | return None
| ^^^^^^^^^^^ DOC201
|
= help: Add a "Returns" section to the docstring
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: crates/ruff_linter/src/rules/pydoclint/mod.rs
---
DOC402_google.py:9:5: DOC402 `yield` is not documented in docstring
|
7 | num (int): A number
8 | """
9 | yield 'test'
| ^^^^^^^^^^^^ DOC402
|
= help: Add a "Yields" section to the docstring

DOC402_google.py:50:9: DOC402 `yield` is not documented in docstring
|
48 | num (int): A number
49 | """
50 | yield 'test'
| ^^^^^^^^^^^^ DOC402
|
= help: Add a "Yields" section to the docstring
4 changes: 3 additions & 1 deletion crates/ruff_linter/src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::rules::{
flake8_comprehensions, flake8_copyright, flake8_errmsg, flake8_gettext,
flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes,
flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe,
pep8_naming, pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade, ruff,
pep8_naming, pycodestyle, pydoclint, pydocstyle, pyflakes, pylint, pyupgrade, ruff,
};
use crate::settings::types::{
CompiledPerFileIgnoreList, ExtensionMapping, FilePatternSet, PythonVersion,
Expand Down Expand Up @@ -261,6 +261,7 @@ pub struct LinterSettings {
pub mccabe: mccabe::settings::Settings,
pub pep8_naming: pep8_naming::settings::Settings,
pub pycodestyle: pycodestyle::settings::Settings,
pub pydoclint: pydoclint::settings::Settings,
pub pydocstyle: pydocstyle::settings::Settings,
pub pyflakes: pyflakes::settings::Settings,
pub pylint: pylint::settings::Settings,
Expand Down Expand Up @@ -426,6 +427,7 @@ impl LinterSettings {
mccabe: mccabe::settings::Settings::default(),
pep8_naming: pep8_naming::settings::Settings::default(),
pycodestyle: pycodestyle::settings::Settings::default(),
pydoclint: pydoclint::settings::Settings::default(),
pydocstyle: pydocstyle::settings::Settings::default(),
pyflakes: pyflakes::settings::Settings::default(),
pylint: pylint::settings::Settings::default(),
Expand Down
14 changes: 13 additions & 1 deletion crates/ruff_workspace/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use crate::options::{
Flake8SelfOptions, Flake8TidyImportsOptions, Flake8TypeCheckingOptions,
Flake8UnusedArgumentsOptions, FormatOptions, IsortOptions, LintCommonOptions, LintOptions,
McCabeOptions, Options, Pep8NamingOptions, PyUpgradeOptions, PycodestyleOptions,
PydocstyleOptions, PyflakesOptions, PylintOptions, RuffOptions,
PydoclintOptions, PydocstyleOptions, PyflakesOptions, PylintOptions, RuffOptions,
};
use crate::settings::{
FileResolverSettings, FormatterSettings, LineEnding, Settings, EXCLUDE, INCLUDE,
Expand Down Expand Up @@ -378,6 +378,10 @@ impl Configuration {
..pycodestyle::settings::Settings::default()
}
},
pydoclint: lint
.pydoclint
.map(PydoclintOptions::into_settings)
.unwrap_or_default(),
pydocstyle: lint
.pydocstyle
.map(PydocstyleOptions::into_settings)
Expand Down Expand Up @@ -623,6 +627,7 @@ pub struct LintConfiguration {
pub mccabe: Option<McCabeOptions>,
pub pep8_naming: Option<Pep8NamingOptions>,
pub pycodestyle: Option<PycodestyleOptions>,
pub pydoclint: Option<PydoclintOptions>,
pub pydocstyle: Option<PydocstyleOptions>,
pub pyflakes: Option<PyflakesOptions>,
pub pylint: Option<PylintOptions>,
Expand Down Expand Up @@ -734,6 +739,7 @@ impl LintConfiguration {
mccabe: options.common.mccabe,
pep8_naming: options.common.pep8_naming,
pycodestyle: options.common.pycodestyle,
pydoclint: options.common.pydoclint,
pydocstyle: options.common.pydocstyle,
pyflakes: options.common.pyflakes,
pylint: options.common.pylint,
Expand Down Expand Up @@ -1112,6 +1118,7 @@ impl LintConfiguration {
mccabe: self.mccabe.combine(config.mccabe),
pep8_naming: self.pep8_naming.combine(config.pep8_naming),
pycodestyle: self.pycodestyle.combine(config.pycodestyle),
pydoclint: self.pydoclint.combine(config.pydoclint),
pydocstyle: self.pydocstyle.combine(config.pydocstyle),
pyflakes: self.pyflakes.combine(config.pyflakes),
pylint: self.pylint.combine(config.pylint),
Expand Down Expand Up @@ -1272,6 +1279,7 @@ fn warn_about_deprecated_top_level_lint_options(
mccabe,
pep8_naming,
pycodestyle,
pydoclint,
pydocstyle,
pyflakes,
pylint,
Expand Down Expand Up @@ -1437,6 +1445,10 @@ fn warn_about_deprecated_top_level_lint_options(
used_options.push("pycodestyle");
}

if pydoclint.is_some() {
used_options.push("pydoclint");
}

if pydocstyle.is_some() {
used_options.push("pydocstyle");
}
Expand Down
Loading
Loading