mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 23:25:14 +00:00
Rename ruff
crate to ruff_linter
(#7529)
This commit is contained in:
parent
dcbd8eacd8
commit
5849a75223
4397 changed files with 93921 additions and 93915 deletions
73
crates/ruff_linter/src/rules/pydocstyle/helpers.rs
Normal file
73
crates/ruff_linter/src/rules/pydocstyle/helpers.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use ruff_python_ast::call_path::from_qualified_name;
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_python_semantic::{Definition, SemanticModel};
|
||||
use ruff_source_file::UniversalNewlines;
|
||||
|
||||
/// Return the index of the first logical line in a string.
|
||||
pub(super) fn logical_line(content: &str) -> Option<usize> {
|
||||
// Find the first logical line.
|
||||
let mut logical_line = None;
|
||||
for (i, line) in content.universal_newlines().enumerate() {
|
||||
if line.trim().is_empty() {
|
||||
// Empty line. If this is the line _after_ the first logical line, stop.
|
||||
if logical_line.is_some() {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Non-empty line. Store the index.
|
||||
logical_line = Some(i);
|
||||
}
|
||||
}
|
||||
logical_line
|
||||
}
|
||||
|
||||
/// Normalize a word by removing all non-alphanumeric characters
|
||||
/// and converting it to lowercase.
|
||||
pub(super) fn normalize_word(first_word: &str) -> String {
|
||||
first_word
|
||||
.replace(|c: char| !c.is_alphanumeric(), "")
|
||||
.to_lowercase()
|
||||
}
|
||||
|
||||
/// Return true if a line ends with an odd number of backslashes (i.e., ends with an escape).
|
||||
pub(super) fn ends_with_backslash(line: &str) -> bool {
|
||||
line.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1
|
||||
}
|
||||
|
||||
/// Check decorator list to see if function should be ignored.
|
||||
pub(crate) fn should_ignore_definition(
|
||||
definition: &Definition,
|
||||
ignore_decorators: &BTreeSet<String>,
|
||||
semantic: &SemanticModel,
|
||||
) -> bool {
|
||||
if ignore_decorators.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(function) = definition.as_function_def() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
function.decorator_list.iter().any(|decorator| {
|
||||
semantic
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.is_some_and(|call_path| {
|
||||
ignore_decorators
|
||||
.iter()
|
||||
.any(|decorator| from_qualified_name(decorator) == call_path)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if a docstring should be ignored.
|
||||
pub(crate) fn should_ignore_docstring(docstring: &Expr) -> bool {
|
||||
// Avoid analyzing docstrings that contain implicit string concatenations.
|
||||
// Python does consider these docstrings, but they're almost certainly a
|
||||
// user error, and supporting them "properly" is extremely difficult.
|
||||
docstring
|
||||
.as_constant_expr()
|
||||
.is_some_and(|constant| constant.value.is_implicit_concatenated())
|
||||
}
|
201
crates/ruff_linter/src/rules/pydocstyle/mod.rs
Normal file
201
crates/ruff_linter/src/rules/pydocstyle/mod.rs
Normal file
|
@ -0,0 +1,201 @@
|
|||
//! Rules from [pydocstyle](https://pypi.org/project/pydocstyle/).
|
||||
pub(crate) mod helpers;
|
||||
pub(crate) mod rules;
|
||||
pub mod settings;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::test::test_path;
|
||||
use crate::{assert_messages, settings};
|
||||
|
||||
use super::settings::{Convention, Settings};
|
||||
|
||||
#[test_case(Rule::BlankLineAfterLastSection, Path::new("sections.py"))]
|
||||
#[test_case(Rule::NoBlankLineAfterSection, Path::new("sections.py"))]
|
||||
#[test_case(Rule::BlankLineAfterSummary, Path::new("D.py"))]
|
||||
#[test_case(Rule::NoBlankLineBeforeSection, Path::new("sections.py"))]
|
||||
#[test_case(Rule::CapitalizeSectionName, Path::new("sections.py"))]
|
||||
#[test_case(Rule::DashedUnderlineAfterSection, Path::new("sections.py"))]
|
||||
#[test_case(Rule::UndocumentedParam, Path::new("canonical_google_examples.py"))]
|
||||
#[test_case(Rule::UndocumentedParam, Path::new("canonical_numpy_examples.py"))]
|
||||
#[test_case(Rule::UndocumentedParam, Path::new("sections.py"))]
|
||||
#[test_case(Rule::EndsInPeriod, Path::new("D.py"))]
|
||||
#[test_case(Rule::EndsInPeriod, Path::new("D400.py"))]
|
||||
#[test_case(Rule::EndsInPunctuation, Path::new("D.py"))]
|
||||
#[test_case(Rule::FirstLineCapitalized, Path::new("D.py"))]
|
||||
#[test_case(Rule::FirstLineCapitalized, Path::new("D403.py"))]
|
||||
#[test_case(Rule::FitsOnOneLine, Path::new("D.py"))]
|
||||
#[test_case(Rule::IndentWithSpaces, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedMagicMethod, Path::new("D.py"))]
|
||||
#[test_case(Rule::MultiLineSummaryFirstLine, Path::new("D.py"))]
|
||||
#[test_case(Rule::MultiLineSummarySecondLine, Path::new("D.py"))]
|
||||
#[test_case(Rule::NewLineAfterLastParagraph, Path::new("D.py"))]
|
||||
#[test_case(Rule::NewLineAfterSectionName, Path::new("sections.py"))]
|
||||
#[test_case(Rule::NoBlankLineAfterFunction, Path::new("D.py"))]
|
||||
#[test_case(Rule::FitsOnOneLine, Path::new("D200.py"))]
|
||||
#[test_case(Rule::NoBlankLineAfterFunction, Path::new("D202.py"))]
|
||||
#[test_case(Rule::BlankLineBeforeClass, Path::new("D.py"))]
|
||||
#[test_case(Rule::NoBlankLineBeforeFunction, Path::new("D.py"))]
|
||||
#[test_case(Rule::BlankLinesBetweenHeaderAndContent, Path::new("sections.py"))]
|
||||
#[test_case(Rule::OverIndentation, Path::new("D.py"))]
|
||||
#[test_case(Rule::NoSignature, Path::new("D.py"))]
|
||||
#[test_case(Rule::SurroundingWhitespace, Path::new("D.py"))]
|
||||
#[test_case(Rule::DocstringStartsWithThis, Path::new("D.py"))]
|
||||
#[test_case(Rule::UnderIndentation, Path::new("D.py"))]
|
||||
#[test_case(Rule::EmptyDocstring, Path::new("D.py"))]
|
||||
#[test_case(Rule::EmptyDocstringSection, Path::new("sections.py"))]
|
||||
#[test_case(Rule::NonImperativeMood, Path::new("D401.py"))]
|
||||
#[test_case(Rule::NoBlankLineAfterSection, Path::new("D410.py"))]
|
||||
#[test_case(Rule::OneBlankLineAfterClass, Path::new("D.py"))]
|
||||
#[test_case(Rule::OneBlankLineBeforeClass, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicClass, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicFunction, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicInit, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicMethod, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicMethod, Path::new("setter.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicModule, Path::new("D.py"))]
|
||||
#[test_case(
|
||||
Rule::UndocumentedPublicModule,
|
||||
Path::new("_unrelated/pkg/D100_pub.py")
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::UndocumentedPublicModule,
|
||||
Path::new("_unrelated/pkg/_priv/no_D100_priv.py")
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::UndocumentedPublicModule,
|
||||
Path::new("_unrelated/_no_pkg_priv.py")
|
||||
)]
|
||||
#[test_case(Rule::UndocumentedPublicNestedClass, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicPackage, Path::new("D.py"))]
|
||||
#[test_case(Rule::UndocumentedPublicPackage, Path::new("D104/__init__.py"))]
|
||||
#[test_case(Rule::SectionNameEndsInColon, Path::new("D.py"))]
|
||||
#[test_case(Rule::SectionNotOverIndented, Path::new("sections.py"))]
|
||||
#[test_case(Rule::SectionNotOverIndented, Path::new("D214_module.py"))]
|
||||
#[test_case(Rule::SectionUnderlineAfterName, Path::new("sections.py"))]
|
||||
#[test_case(Rule::SectionUnderlineMatchesSectionLength, Path::new("sections.py"))]
|
||||
#[test_case(Rule::SectionUnderlineNotOverIndented, Path::new("sections.py"))]
|
||||
#[test_case(Rule::OverloadWithDocstring, Path::new("D.py"))]
|
||||
#[test_case(Rule::EscapeSequenceInDocstring, Path::new("D.py"))]
|
||||
#[test_case(Rule::EscapeSequenceInDocstring, Path::new("D301.py"))]
|
||||
#[test_case(Rule::TripleSingleQuotes, Path::new("D.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle").join(path).as_path(),
|
||||
&settings::Settings {
|
||||
pydocstyle: Settings {
|
||||
convention: None,
|
||||
ignore_decorators: BTreeSet::from_iter(["functools.wraps".to_string()]),
|
||||
property_decorators: BTreeSet::from_iter([
|
||||
"gi.repository.GObject.Property".to_string()
|
||||
]),
|
||||
},
|
||||
..settings::Settings::for_rule(rule_code)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bom() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/bom.py"),
|
||||
&settings::Settings::for_rule(Rule::TripleSingleQuotes),
|
||||
)?;
|
||||
assert_messages!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn d417_unspecified() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/D417.py"),
|
||||
&settings::Settings {
|
||||
// When inferring the convention, we'll see a few false negatives.
|
||||
// See: https://github.com/PyCQA/pydocstyle/issues/459.
|
||||
pydocstyle: Settings {
|
||||
convention: None,
|
||||
ignore_decorators: BTreeSet::new(),
|
||||
property_decorators: BTreeSet::new(),
|
||||
},
|
||||
..settings::Settings::for_rule(Rule::UndocumentedParam)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn d417_google() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/D417.py"),
|
||||
&settings::Settings {
|
||||
// With explicit Google convention, we should flag every function.
|
||||
pydocstyle: Settings {
|
||||
convention: Some(Convention::Google),
|
||||
ignore_decorators: BTreeSet::new(),
|
||||
property_decorators: BTreeSet::new(),
|
||||
},
|
||||
..settings::Settings::for_rule(Rule::UndocumentedParam)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn d417_numpy() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/D417.py"),
|
||||
&settings::Settings {
|
||||
// With explicit Google convention, we shouldn't flag anything.
|
||||
pydocstyle: Settings {
|
||||
convention: Some(Convention::Numpy),
|
||||
ignore_decorators: BTreeSet::new(),
|
||||
property_decorators: BTreeSet::new(),
|
||||
},
|
||||
..settings::Settings::for_rule(Rule::UndocumentedParam)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn d209_d400() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/D209_D400.py"),
|
||||
&settings::Settings::for_rules([Rule::NewLineAfterLastParagraph, Rule::EndsInPeriod]),
|
||||
)?;
|
||||
assert_messages!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/all.py"),
|
||||
&settings::Settings::for_rules([
|
||||
Rule::UndocumentedPublicModule,
|
||||
Rule::UndocumentedPublicClass,
|
||||
Rule::UndocumentedPublicMethod,
|
||||
Rule::UndocumentedPublicFunction,
|
||||
Rule::UndocumentedPublicPackage,
|
||||
Rule::UndocumentedMagicMethod,
|
||||
Rule::UndocumentedPublicNestedClass,
|
||||
Rule::UndocumentedPublicInit,
|
||||
]),
|
||||
)?;
|
||||
assert_messages!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
77
crates/ruff_linter/src/rules/pydocstyle/rules/backslashes.rs
Normal file
77
crates/ruff_linter/src/rules/pydocstyle/rules/backslashes.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use memchr::memchr_iter;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings that include backslashes, but are not defined as
|
||||
/// raw string literals.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// In Python, backslashes are typically used to escape characters in strings.
|
||||
/// In raw strings (those prefixed with an `r`), however, backslashes are
|
||||
/// treated as literal characters.
|
||||
///
|
||||
/// [PEP 257](https://peps.python.org/pep-0257/#what-is-a-docstring) recommends
|
||||
/// the use of raw strings (i.e., `r"""raw triple double quotes"""`) for
|
||||
/// docstrings that include backslashes. The use of a raw string ensures that
|
||||
/// any backslashes are treated as literal characters, and not as escape
|
||||
/// sequences, which avoids confusion.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foobar():
|
||||
/// """Docstring for foo\bar."""
|
||||
///
|
||||
///
|
||||
/// foobar.__doc__ # "Docstring for foar."
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foobar():
|
||||
/// r"""Docstring for foo\bar."""
|
||||
///
|
||||
///
|
||||
/// foobar.__doc__ # "Docstring for foo\bar."
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [Python documentation: String and Bytes literals](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)
|
||||
#[violation]
|
||||
pub struct EscapeSequenceInDocstring;
|
||||
|
||||
impl Violation for EscapeSequenceInDocstring {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(r#"Use `r"""` if any backslashes in a docstring"#)
|
||||
}
|
||||
}
|
||||
|
||||
/// D301
|
||||
pub(crate) fn backslashes(checker: &mut Checker, docstring: &Docstring) {
|
||||
// Docstring is already raw.
|
||||
let contents = docstring.contents;
|
||||
if contents.starts_with('r') || contents.starts_with("ur") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Docstring contains at least one backslash.
|
||||
let body = docstring.body();
|
||||
let bytes = body.as_bytes();
|
||||
if memchr_iter(b'\\', bytes).any(|position| {
|
||||
let escaped_char = bytes.get(position.saturating_add(1));
|
||||
// Allow continuations (backslashes followed by newlines) and Unicode escapes.
|
||||
!matches!(escaped_char, Some(b'\r' | b'\n' | b'u' | b'N'))
|
||||
}) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
EscapeSequenceInDocstring,
|
||||
docstring.range(),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstring summary lines that are not separated from the docstring
|
||||
/// description by one blank line.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that multi-line docstrings consist of "a summary line
|
||||
/// just like a one-line docstring, followed by a blank line, followed by a
|
||||
/// more elaborate description."
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
/// Sort the list in ascending order and return a copy of the
|
||||
/// result using the bubble sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the
|
||||
/// result using the bubble sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct BlankLineAfterSummary {
|
||||
num_lines: usize,
|
||||
}
|
||||
|
||||
impl Violation for BlankLineAfterSummary {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let BlankLineAfterSummary { num_lines } = self;
|
||||
if *num_lines == 0 {
|
||||
format!("1 blank line required between summary line and description")
|
||||
} else {
|
||||
format!(
|
||||
"1 blank line required between summary line and description (found {num_lines})"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some("Insert single blank line".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// D205
|
||||
pub(crate) fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body();
|
||||
|
||||
if !docstring.triple_quoted() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut lines_count: usize = 1;
|
||||
let mut blanks_count = 0;
|
||||
for line in body.trim().universal_newlines().skip(1) {
|
||||
lines_count += 1;
|
||||
if line.trim().is_empty() {
|
||||
blanks_count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if lines_count > 1 && blanks_count != 1 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
BlankLineAfterSummary {
|
||||
num_lines: blanks_count,
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
if blanks_count > 1 {
|
||||
let mut lines = UniversalNewlineIterator::with_offset(&body, body.start());
|
||||
let mut summary_end = body.start();
|
||||
|
||||
// Find the "summary" line (defined as the first non-blank line).
|
||||
for line in lines.by_ref() {
|
||||
if !line.trim().is_empty() {
|
||||
summary_end = line.full_end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last blank line
|
||||
let mut blank_end = summary_end;
|
||||
for line in lines {
|
||||
if !line.trim().is_empty() {
|
||||
blank_end = line.start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert one blank line after the summary (replacing any existing lines).
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
checker.stylist().line_ending().to_string(),
|
||||
summary_end,
|
||||
blank_end,
|
||||
)));
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_trivia::{indentation_at_offset, PythonWhitespace};
|
||||
use ruff_source_file::{Line, UniversalNewlineIterator};
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings on class definitions that are not preceded by a
|
||||
/// blank line.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Use a blank line to separate the docstring from the class definition, for
|
||||
/// consistency.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is disabled when using the `google`,
|
||||
/// `numpy`, and `pep257` conventions.
|
||||
///
|
||||
/// For an alternative, see [D211].
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class PhotoMetadata:
|
||||
/// """Metadata about a photo."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class PhotoMetadata:
|
||||
///
|
||||
/// """Metadata about a photo."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// [D211]: https://docs.astral.sh/ruff/rules/blank-line-before-class
|
||||
#[violation]
|
||||
pub struct OneBlankLineBeforeClass;
|
||||
|
||||
impl AlwaysAutofixableViolation for OneBlankLineBeforeClass {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("1 blank line required before class docstring")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Insert 1 blank line before class docstring".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for class methods that are not separated from the class's docstring
|
||||
/// by a blank line.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends the use of a blank line to separate a class's
|
||||
/// docstring its methods.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `google`
|
||||
/// convention, and disabled when using the `numpy` and `pep257` conventions.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class PhotoMetadata:
|
||||
/// """Metadata about a photo."""
|
||||
/// def __init__(self, file: Path):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class PhotoMetadata:
|
||||
/// """Metadata about a photo."""
|
||||
///
|
||||
/// def __init__(self, file: Path):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct OneBlankLineAfterClass;
|
||||
|
||||
impl AlwaysAutofixableViolation for OneBlankLineAfterClass {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("1 blank line required after class docstring")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Insert 1 blank line after class docstring".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings on class definitions that are preceded by a blank
|
||||
/// line.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Avoid introducing any blank lines between a class definition and its
|
||||
/// docstring, for consistency.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `google`,
|
||||
/// `numpy`, and `pep257` conventions.
|
||||
///
|
||||
/// For an alternative, see [D203].
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class PhotoMetadata:
|
||||
///
|
||||
/// """Metadata about a photo."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class PhotoMetadata:
|
||||
/// """Metadata about a photo."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// [D203]: https://docs.astral.sh/ruff/rules/one-blank-line-before-class
|
||||
#[violation]
|
||||
pub struct BlankLineBeforeClass;
|
||||
|
||||
impl AlwaysAutofixableViolation for BlankLineBeforeClass {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("No blank lines allowed before class docstring")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove blank line(s) before class docstring".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// D203, D204, D211
|
||||
pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
|
||||
let Some(class) = docstring.definition.as_class_def() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Special-case: the docstring is on the same line as the class. For example:
|
||||
// ```python
|
||||
// class PhotoMetadata: """Metadata about a photo."""
|
||||
// ```
|
||||
let between_range = TextRange::new(class.start(), docstring.start());
|
||||
if !checker.locator().contains_line_break(between_range) {
|
||||
return;
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::OneBlankLineBeforeClass) || checker.enabled(Rule::BlankLineBeforeClass)
|
||||
{
|
||||
let mut lines = UniversalNewlineIterator::with_offset(
|
||||
checker.locator().slice(between_range),
|
||||
between_range.start(),
|
||||
)
|
||||
.rev();
|
||||
|
||||
let mut blank_lines_before = 0usize;
|
||||
let mut blank_lines_start = lines.next().map(|line| line.start()).unwrap_or_default();
|
||||
|
||||
for line in lines {
|
||||
if line.trim().is_empty() {
|
||||
blank_lines_before += 1;
|
||||
blank_lines_start = line.start();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::BlankLineBeforeClass) {
|
||||
if blank_lines_before != 0 {
|
||||
let mut diagnostic = Diagnostic::new(BlankLineBeforeClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Delete the blank line before the class.
|
||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||
blank_lines_start,
|
||||
docstring.start() - docstring.indentation.text_len(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::OneBlankLineBeforeClass) {
|
||||
if blank_lines_before != 1 {
|
||||
let mut diagnostic = Diagnostic::new(OneBlankLineBeforeClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Insert one blank line before the class.
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
checker.stylist().line_ending().to_string(),
|
||||
blank_lines_start,
|
||||
docstring.start() - docstring.indentation.text_len(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::OneBlankLineAfterClass) {
|
||||
let class_after_docstring_range = TextRange::new(docstring.end(), class.end());
|
||||
let class_after_docstring = checker.locator().slice(class_after_docstring_range);
|
||||
let mut lines = UniversalNewlineIterator::with_offset(
|
||||
class_after_docstring,
|
||||
class_after_docstring_range.start(),
|
||||
);
|
||||
|
||||
// If the class is empty except for comments, we don't need to insert a newline between
|
||||
// docstring and no content
|
||||
let all_blank_after = lines.clone().all(|line| {
|
||||
line.trim_whitespace().is_empty() || line.trim_whitespace_start().starts_with('#')
|
||||
});
|
||||
if all_blank_after {
|
||||
return;
|
||||
}
|
||||
|
||||
let first_line = lines.next();
|
||||
let mut replacement_start = first_line.as_ref().map(Line::start).unwrap_or_default();
|
||||
|
||||
// Edge case: There is trailing end-of-line content after the docstring, either a statement
|
||||
// separated by a semicolon or a comment.
|
||||
if let Some(first_line) = &first_line {
|
||||
let trailing = first_line.as_str().trim_whitespace_start();
|
||||
if let Some(next_statement) = trailing.strip_prefix(';') {
|
||||
let indentation = indentation_at_offset(docstring.start(), checker.locator())
|
||||
.expect("Own line docstring must have indentation");
|
||||
let mut diagnostic = Diagnostic::new(OneBlankLineAfterClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
let line_ending = checker.stylist().line_ending().as_str();
|
||||
// We have to trim the whitespace twice, once before the semicolon above and
|
||||
// once after the semicolon here, or we get invalid indents:
|
||||
// ```rust
|
||||
// class Priority:
|
||||
// """Has priorities""" ; priorities=1
|
||||
// ```
|
||||
let next_statement = next_statement.trim_whitespace_start();
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
line_ending.to_string() + line_ending + indentation + next_statement,
|
||||
replacement_start,
|
||||
first_line.end(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
return;
|
||||
} else if trailing.starts_with('#') {
|
||||
// Keep the end-of-line comment, start counting empty lines after it
|
||||
replacement_start = first_line.end();
|
||||
}
|
||||
}
|
||||
|
||||
let mut blank_lines_after = 0usize;
|
||||
let mut blank_lines_end = first_line.as_ref().map_or(docstring.end(), Line::end);
|
||||
|
||||
for line in lines {
|
||||
if line.trim_whitespace().is_empty() {
|
||||
blank_lines_end = line.end();
|
||||
blank_lines_after += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if blank_lines_after != 1 {
|
||||
let mut diagnostic = Diagnostic::new(OneBlankLineAfterClass, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Insert a blank line before the class (replacing any existing lines).
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
checker.stylist().line_ending().to_string(),
|
||||
replacement_start,
|
||||
blank_lines_end,
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_trivia::PythonWhitespace;
|
||||
use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines};
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings on functions that are separated by one or more blank
|
||||
/// lines from the function definition.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Remove any blank lines between the function definition and its docstring,
|
||||
/// for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
///
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct NoBlankLineBeforeFunction {
|
||||
num_lines: usize,
|
||||
}
|
||||
|
||||
impl AlwaysAutofixableViolation for NoBlankLineBeforeFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let NoBlankLineBeforeFunction { num_lines } = self;
|
||||
format!("No blank lines allowed before function docstring (found {num_lines})")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove blank line(s) before function docstring".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings on functions that are separated by one or more blank
|
||||
/// lines from the function body.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Remove any blank lines between the function body and the function
|
||||
/// docstring, for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
///
|
||||
/// return sum(values) / len(values)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// return sum(values) / len(values)
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct NoBlankLineAfterFunction {
|
||||
num_lines: usize,
|
||||
}
|
||||
|
||||
impl AlwaysAutofixableViolation for NoBlankLineAfterFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let NoBlankLineAfterFunction { num_lines } = self;
|
||||
format!("No blank lines allowed after function docstring (found {num_lines})")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove blank line(s) after function docstring".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
static INNER_FUNCTION_OR_CLASS_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^\s+(?:(?:class|def|async def)\s|@)").unwrap());
|
||||
|
||||
/// D201, D202
|
||||
pub(crate) fn blank_before_after_function(checker: &mut Checker, docstring: &Docstring) {
|
||||
let Some(function) = docstring.definition.as_function_def() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if checker.enabled(Rule::NoBlankLineBeforeFunction) {
|
||||
let before = checker
|
||||
.locator()
|
||||
.slice(TextRange::new(function.start(), docstring.start()));
|
||||
|
||||
let mut lines = UniversalNewlineIterator::with_offset(before, function.start()).rev();
|
||||
let mut blank_lines_before = 0usize;
|
||||
let mut blank_lines_start = lines.next().map(|l| l.end()).unwrap_or_default();
|
||||
|
||||
for line in lines {
|
||||
if line.trim().is_empty() {
|
||||
blank_lines_before += 1;
|
||||
blank_lines_start = line.start();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if blank_lines_before != 0 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
NoBlankLineBeforeFunction {
|
||||
num_lines: blank_lines_before,
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Delete the blank line before the docstring.
|
||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||
blank_lines_start,
|
||||
docstring.start() - docstring.indentation.text_len(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::NoBlankLineAfterFunction) {
|
||||
let after = checker
|
||||
.locator()
|
||||
.slice(TextRange::new(docstring.end(), function.end()));
|
||||
|
||||
// If the docstring is only followed by blank and commented lines, abort.
|
||||
let all_blank_after = after.universal_newlines().skip(1).all(|line| {
|
||||
line.trim_whitespace().is_empty() || line.trim_whitespace_start().starts_with('#')
|
||||
});
|
||||
if all_blank_after {
|
||||
return;
|
||||
}
|
||||
|
||||
// Count the number of blank lines after the docstring.
|
||||
let mut blank_lines_after = 0usize;
|
||||
let mut lines = UniversalNewlineIterator::with_offset(after, docstring.end()).peekable();
|
||||
let first_line_end = lines.next().map(|l| l.end()).unwrap_or_default();
|
||||
let mut blank_lines_end = first_line_end;
|
||||
|
||||
while let Some(line) = lines.peek() {
|
||||
if line.trim().is_empty() {
|
||||
blank_lines_after += 1;
|
||||
blank_lines_end = line.end();
|
||||
lines.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid violations for blank lines followed by inner functions or classes.
|
||||
if blank_lines_after == 1
|
||||
&& lines
|
||||
.find(|line| !line.trim_whitespace_start().starts_with('#'))
|
||||
.is_some_and(|line| INNER_FUNCTION_OR_CLASS_REGEX.is_match(&line))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if blank_lines_after != 0 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
NoBlankLineAfterFunction {
|
||||
num_lines: blank_lines_after,
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Delete the blank line after the docstring.
|
||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||
first_line_end,
|
||||
blank_lines_end,
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
101
crates/ruff_linter/src/rules/pydocstyle/rules/capitalized.rs
Normal file
101
crates/ruff_linter/src/rules/pydocstyle/rules/capitalized.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings that do not start with a capital letter.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// The first character in a docstring should be capitalized for, grammatical
|
||||
/// correctness and consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct FirstLineCapitalized {
|
||||
first_word: String,
|
||||
capitalized_word: String,
|
||||
}
|
||||
|
||||
impl AlwaysAutofixableViolation for FirstLineCapitalized {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
"First word of the first line should be capitalized: `{}` -> `{}`",
|
||||
self.first_word, self.capitalized_word
|
||||
)
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
format!(
|
||||
"Capitalize `{}` to `{}`",
|
||||
self.first_word, self.capitalized_word
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// D403
|
||||
pub(crate) fn capitalized(checker: &mut Checker, docstring: &Docstring) {
|
||||
if docstring.definition.as_function_def().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let body = docstring.body();
|
||||
let Some(first_word) = body.split(' ').next() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Like pydocstyle, we only support ASCII for now.
|
||||
for char in first_word.chars() {
|
||||
if !char.is_ascii_alphabetic() && char != '\'' {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut first_word_chars = first_word.chars();
|
||||
let Some(first_char) = first_word_chars.next() else {
|
||||
return;
|
||||
};
|
||||
let uppercase_first_char = first_char.to_ascii_uppercase();
|
||||
if first_char == uppercase_first_char {
|
||||
return;
|
||||
}
|
||||
|
||||
let capitalized_word = uppercase_first_char.to_string() + first_word_chars.as_str();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
FirstLineCapitalized {
|
||||
first_word: first_word.to_string(),
|
||||
capitalized_word: capitalized_word.to_string(),
|
||||
},
|
||||
docstring.expr.range(),
|
||||
);
|
||||
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||
capitalized_word,
|
||||
TextRange::at(body.start(), first_word.text_len()),
|
||||
)));
|
||||
}
|
||||
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
use ruff_text_size::TextLen;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::sections::SectionKind;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::pydocstyle::helpers::logical_line;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings in which the first line does not end in a period.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that the first line of a docstring is written in the
|
||||
/// form of a command, ending in a period.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `numpy` and
|
||||
/// `pep257` conventions, and disabled when using the `google` convention.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values"""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct EndsInPeriod;
|
||||
|
||||
impl AlwaysAutofixableViolation for EndsInPeriod {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("First line should end with a period")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Add period".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// D400
|
||||
pub(crate) fn ends_with_period(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body();
|
||||
|
||||
if let Some(first_line) = body.trim().universal_newlines().next() {
|
||||
let trimmed = first_line.trim();
|
||||
|
||||
// Avoid false-positives: `:param`, etc.
|
||||
for prefix in [":param", ":type", ":raises", ":return", ":rtype"] {
|
||||
if trimmed.starts_with(prefix) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid false-positives: `Args:`, etc.
|
||||
for section_kind in SectionKind::iter() {
|
||||
if let Some(suffix) = trimmed.strip_suffix(section_kind.as_str()) {
|
||||
if suffix.is_empty() {
|
||||
return;
|
||||
}
|
||||
if suffix == ":" {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index) = logical_line(body.as_str()) {
|
||||
let mut lines = UniversalNewlineIterator::with_offset(&body, body.start());
|
||||
let line = lines.nth(index).unwrap();
|
||||
let trimmed = line.trim_end();
|
||||
|
||||
if trimmed.ends_with('\\') {
|
||||
// Ignore the edge case whether a single quoted string is multiple lines through an
|
||||
// escape (https://github.com/astral-sh/ruff/issues/7139). Single quote docstrings are
|
||||
// flagged by D300.
|
||||
// ```python
|
||||
// "\
|
||||
// "
|
||||
// ```
|
||||
return;
|
||||
}
|
||||
|
||||
if !trimmed.ends_with('.') {
|
||||
let mut diagnostic = Diagnostic::new(EndsInPeriod, docstring.range());
|
||||
// Best-effort autofix: avoid adding a period after other punctuation marks.
|
||||
if checker.patch(diagnostic.kind.rule()) && !trimmed.ends_with([':', ';']) {
|
||||
diagnostic.set_fix(Fix::suggested(Edit::insertion(
|
||||
".".to_string(),
|
||||
line.start() + trimmed.text_len(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
use ruff_text_size::TextLen;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::sections::SectionKind;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::pydocstyle::helpers::logical_line;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings in which the first line does not end in a punctuation
|
||||
/// mark, such as a period, question mark, or exclamation point.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// The first line of a docstring should end with a period, question mark, or
|
||||
/// exclamation point, for grammatical correctness and consistency.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `google`
|
||||
/// convention, and disabled when using the `numpy` and `pep257` conventions.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values"""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct EndsInPunctuation;
|
||||
|
||||
impl AlwaysAutofixableViolation for EndsInPunctuation {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("First line should end with a period, question mark, or exclamation point")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Add closing punctuation".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// D415
|
||||
pub(crate) fn ends_with_punctuation(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body();
|
||||
|
||||
if let Some(first_line) = body.trim().universal_newlines().next() {
|
||||
let trimmed = first_line.trim();
|
||||
|
||||
// Avoid false-positives: `:param`, etc.
|
||||
for prefix in [":param", ":type", ":raises", ":return", ":rtype"] {
|
||||
if trimmed.starts_with(prefix) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid false-positives: `Args:`, etc.
|
||||
for section_kind in SectionKind::iter() {
|
||||
if let Some(suffix) = trimmed.strip_suffix(section_kind.as_str()) {
|
||||
if suffix.is_empty() {
|
||||
return;
|
||||
}
|
||||
if suffix == ":" {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index) = logical_line(body.as_str()) {
|
||||
let mut lines = UniversalNewlineIterator::with_offset(&body, body.start()).skip(index);
|
||||
let line = lines.next().unwrap();
|
||||
let trimmed = line.trim_end();
|
||||
|
||||
if trimmed.ends_with('\\') {
|
||||
// Ignore the edge case whether a single quoted string is multiple lines through an
|
||||
// escape (https://github.com/astral-sh/ruff/issues/7139). Single quote docstrings are
|
||||
// flagged by D300.
|
||||
// ```python
|
||||
// "\
|
||||
// "
|
||||
// ```
|
||||
return;
|
||||
}
|
||||
|
||||
if !trimmed.ends_with(['.', '!', '?']) {
|
||||
let mut diagnostic = Diagnostic::new(EndsInPunctuation, docstring.range());
|
||||
// Best-effort autofix: avoid adding a period after other punctuation marks.
|
||||
if checker.patch(diagnostic.kind.rule()) && !trimmed.ends_with([':', ';']) {
|
||||
diagnostic.set_fix(Fix::suggested(Edit::insertion(
|
||||
".".to_string(),
|
||||
line.start() + trimmed.text_len(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
};
|
||||
}
|
||||
}
|
90
crates/ruff_linter/src/rules/pydocstyle/rules/if_needed.rs
Normal file
90
crates/ruff_linter/src/rules/pydocstyle/rules/if_needed.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::identifier::Identifier;
|
||||
use ruff_python_semantic::analyze::visibility::is_overload;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `@overload` function definitions that contain a docstring.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// The `@overload` decorator is used to define multiple compatible signatures
|
||||
/// for a given function, to support type-checking. A series of `@overload`
|
||||
/// definitions should be followed by a single non-decorated definition that
|
||||
/// contains the implementation of the function.
|
||||
///
|
||||
/// `@overload` function definitions should not contain a docstring; instead,
|
||||
/// the docstring should be placed on the non-decorated definition that contains
|
||||
/// the implementation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// from typing import overload
|
||||
///
|
||||
///
|
||||
/// @overload
|
||||
/// def factorial(n: int) -> int:
|
||||
/// """Return the factorial of n."""
|
||||
///
|
||||
///
|
||||
/// @overload
|
||||
/// def factorial(n: float) -> float:
|
||||
/// """Return the factorial of n."""
|
||||
///
|
||||
///
|
||||
/// def factorial(n):
|
||||
/// """Return the factorial of n."""
|
||||
///
|
||||
///
|
||||
/// factorial.__doc__ # "Return the factorial of n."
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// from typing import overload
|
||||
///
|
||||
///
|
||||
/// @overload
|
||||
/// def factorial(n: int) -> int:
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
/// @overload
|
||||
/// def factorial(n: float) -> float:
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
/// def factorial(n):
|
||||
/// """Return the factorial of n."""
|
||||
///
|
||||
///
|
||||
/// factorial.__doc__ # "Return the factorial of n."
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [Python documentation: `typing.overload`](https://docs.python.org/3/library/typing.html#typing.overload)
|
||||
#[violation]
|
||||
pub struct OverloadWithDocstring;
|
||||
|
||||
impl Violation for OverloadWithDocstring {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Function decorated with `@overload` shouldn't contain a docstring")
|
||||
}
|
||||
}
|
||||
|
||||
/// D418
|
||||
pub(crate) fn if_needed(checker: &mut Checker, docstring: &Docstring) {
|
||||
let Some(function) = docstring.definition.as_function_def() else {
|
||||
return;
|
||||
};
|
||||
if is_overload(&function.decorator_list, checker.semantic()) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
OverloadWithDocstring,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
}
|
265
crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs
Normal file
265
crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs
Normal file
|
@ -0,0 +1,265 @@
|
|||
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::docstrings::{clean_space, leading_space};
|
||||
use ruff_source_file::NewlineWithTrailingNewline;
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings that are indented with tabs.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 8](https://peps.python.org/pep-0008/#tabs-or-spaces) recommends using
|
||||
/// spaces over tabs for indentation.
|
||||
///
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct IndentWithSpaces;
|
||||
|
||||
impl Violation for IndentWithSpaces {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Docstring should be indented with spaces, not tabs")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for under-indented docstrings.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that docstrings be indented to the same level as their
|
||||
/// opening quotes. Avoid under-indenting docstrings, for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble sort
|
||||
/// algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct UnderIndentation;
|
||||
|
||||
impl AlwaysAutofixableViolation for UnderIndentation {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Docstring is under-indented")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Increase indentation".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for over-indented docstrings.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that docstrings be indented to the same level as their
|
||||
/// opening quotes. Avoid over-indenting docstrings, for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the
|
||||
/// bubble sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct OverIndentation;
|
||||
|
||||
impl AlwaysAutofixableViolation for OverIndentation {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Docstring is over-indented")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove over-indentation".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// D206, D207, D208
|
||||
pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body();
|
||||
|
||||
// Split the docstring into lines.
|
||||
let lines: Vec<_> = NewlineWithTrailingNewline::with_offset(&body, body.start()).collect();
|
||||
if lines.len() <= 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut has_seen_tab = docstring.indentation.contains('\t');
|
||||
let mut is_over_indented = true;
|
||||
let mut over_indented_lines = vec![];
|
||||
|
||||
for i in 0..lines.len() {
|
||||
// First lines and continuations doesn't need any indentation.
|
||||
if i == 0 || lines[i - 1].ends_with('\\') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line = &lines[i];
|
||||
// Omit empty lines, except for the last line, which is non-empty by way of
|
||||
// containing the closing quotation marks.
|
||||
let is_blank = line.trim().is_empty();
|
||||
if i < lines.len() - 1 && is_blank {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line_indent = leading_space(line);
|
||||
|
||||
// We only report tab indentation once, so only check if we haven't seen a tab
|
||||
// yet.
|
||||
has_seen_tab = has_seen_tab || line_indent.contains('\t');
|
||||
|
||||
if checker.enabled(Rule::UnderIndentation) {
|
||||
// We report under-indentation on every line. This isn't great, but enables
|
||||
// autofix.
|
||||
if (i == lines.len() - 1 || !is_blank)
|
||||
&& line_indent.len() < docstring.indentation.len()
|
||||
{
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(UnderIndentation, TextRange::empty(line.start()));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||
clean_space(docstring.indentation),
|
||||
TextRange::at(line.start(), line_indent.text_len()),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
// Like pydocstyle, we only report over-indentation if either: (1) every line
|
||||
// (except, optionally, the last line) is over-indented, or (2) the last line
|
||||
// (which contains the closing quotation marks) is
|
||||
// over-indented. We can't know if we've achieved that condition
|
||||
// until we've viewed all the lines, so for now, just track
|
||||
// the over-indentation status of every line.
|
||||
if i < lines.len() - 1 {
|
||||
if line_indent.len() > docstring.indentation.len() {
|
||||
over_indented_lines.push(TextRange::at(line.start(), line_indent.text_len()));
|
||||
} else {
|
||||
is_over_indented = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::IndentWithSpaces) {
|
||||
if has_seen_tab {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(IndentWithSpaces, docstring.range()));
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::OverIndentation) {
|
||||
// If every line (except the last) is over-indented...
|
||||
if is_over_indented {
|
||||
for over_indented in over_indented_lines {
|
||||
// We report over-indentation on every line. This isn't great, but
|
||||
// enables autofix.
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(OverIndentation, TextRange::empty(over_indented.start()));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
let indent = clean_space(docstring.indentation);
|
||||
let edit = if indent.is_empty() {
|
||||
Edit::range_deletion(over_indented)
|
||||
} else {
|
||||
Edit::range_replacement(indent, over_indented)
|
||||
};
|
||||
diagnostic.set_fix(Fix::automatic(edit));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
// If the last line is over-indented...
|
||||
if let Some(last) = lines.last() {
|
||||
let line_indent = leading_space(last);
|
||||
if line_indent.len() > docstring.indentation.len() {
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(OverIndentation, TextRange::empty(last.start()));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
let indent = clean_space(docstring.indentation);
|
||||
let range = TextRange::at(last.start(), line_indent.text_len());
|
||||
let edit = if indent.is_empty() {
|
||||
Edit::range_deletion(range)
|
||||
} else {
|
||||
Edit::range_replacement(indent, range)
|
||||
};
|
||||
diagnostic.set_fix(Fix::automatic(edit));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
crates/ruff_linter/src/rules/pydocstyle/rules/mod.rs
Normal file
41
crates/ruff_linter/src/rules/pydocstyle/rules/mod.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
pub(crate) use backslashes::*;
|
||||
pub(crate) use blank_after_summary::*;
|
||||
pub(crate) use blank_before_after_class::*;
|
||||
pub(crate) use blank_before_after_function::*;
|
||||
pub(crate) use capitalized::*;
|
||||
pub(crate) use ends_with_period::*;
|
||||
pub(crate) use ends_with_punctuation::*;
|
||||
pub(crate) use if_needed::*;
|
||||
pub(crate) use indent::*;
|
||||
pub(crate) use multi_line_summary_start::*;
|
||||
pub(crate) use newline_after_last_paragraph::*;
|
||||
pub(crate) use no_signature::*;
|
||||
pub(crate) use no_surrounding_whitespace::*;
|
||||
pub(crate) use non_imperative_mood::*;
|
||||
pub(crate) use not_empty::*;
|
||||
pub(crate) use not_missing::*;
|
||||
pub(crate) use one_liner::*;
|
||||
pub(crate) use sections::*;
|
||||
pub(crate) use starts_with_this::*;
|
||||
pub(crate) use triple_quotes::*;
|
||||
|
||||
mod backslashes;
|
||||
mod blank_after_summary;
|
||||
mod blank_before_after_class;
|
||||
mod blank_before_after_function;
|
||||
mod capitalized;
|
||||
mod ends_with_period;
|
||||
mod ends_with_punctuation;
|
||||
mod if_needed;
|
||||
mod indent;
|
||||
mod multi_line_summary_start;
|
||||
mod newline_after_last_paragraph;
|
||||
mod no_signature;
|
||||
mod no_surrounding_whitespace;
|
||||
mod non_imperative_mood;
|
||||
mod not_empty;
|
||||
mod not_missing;
|
||||
mod one_liner;
|
||||
mod sections;
|
||||
mod starts_with_this;
|
||||
mod triple_quotes;
|
|
@ -0,0 +1,210 @@
|
|||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::str::{is_triple_quote, leading_quote};
|
||||
use ruff_python_semantic::Definition;
|
||||
use ruff_source_file::{NewlineWithTrailingNewline, UniversalNewlineIterator};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstring summary lines that are not positioned on the first
|
||||
/// physical line of the docstring.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that multi-line docstrings consist of "a summary line
|
||||
/// just like a one-line docstring, followed by a blank line, followed by a
|
||||
/// more elaborate description."
|
||||
///
|
||||
/// The summary line should be located on the first physical line of the
|
||||
/// docstring, immediately after the opening quotes.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `google`
|
||||
/// convention, and disabled when using the `numpy` and `pep257` conventions.
|
||||
///
|
||||
/// For an alternative, see [D213].
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """
|
||||
/// Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the
|
||||
/// bubble sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// [D213]: https://docs.astral.sh/ruff/rules/multi-line-summary-second-line
|
||||
#[violation]
|
||||
pub struct MultiLineSummaryFirstLine;
|
||||
|
||||
impl AlwaysAutofixableViolation for MultiLineSummaryFirstLine {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Multi-line docstring summary should start at the first line")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove whitespace after opening quotes".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstring summary lines that are not positioned on the second
|
||||
/// physical line of the docstring.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that multi-line docstrings consist of "a summary line
|
||||
/// just like a one-line docstring, followed by a blank line, followed by a
|
||||
/// more elaborate description."
|
||||
///
|
||||
/// The summary line should be located on the second physical line of the
|
||||
/// docstring, immediately after the opening quotes and the blank line.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is disabled when using the `google`,
|
||||
/// `numpy`, and `pep257` conventions.
|
||||
///
|
||||
/// For an alternative, see [D212].
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the
|
||||
/// bubble sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: list[int]) -> list[int]:
|
||||
/// """
|
||||
/// Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// [D212]: https://docs.astral.sh/ruff/rules/multi-line-summary-first-line
|
||||
#[violation]
|
||||
pub struct MultiLineSummarySecondLine;
|
||||
|
||||
impl AlwaysAutofixableViolation for MultiLineSummarySecondLine {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Multi-line docstring summary should start at the second line")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Insert line break and indentation after opening quotes".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// D212, D213
|
||||
pub(crate) fn multi_line_summary_start(checker: &mut Checker, docstring: &Docstring) {
|
||||
let contents = docstring.contents;
|
||||
let body = docstring.body();
|
||||
|
||||
if NewlineWithTrailingNewline::from(body.as_str())
|
||||
.nth(1)
|
||||
.is_none()
|
||||
{
|
||||
return;
|
||||
};
|
||||
let mut content_lines = UniversalNewlineIterator::with_offset(contents, docstring.start());
|
||||
|
||||
let Some(first_line) = content_lines.next() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if is_triple_quote(&first_line) {
|
||||
if checker.enabled(Rule::MultiLineSummaryFirstLine) {
|
||||
let mut diagnostic = Diagnostic::new(MultiLineSummaryFirstLine, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Delete until first non-whitespace char.
|
||||
for line in content_lines {
|
||||
if let Some(end_column) = line.find(|c: char| !c.is_whitespace()) {
|
||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||
first_line.end(),
|
||||
line.start() + TextSize::try_from(end_column).unwrap(),
|
||||
)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
} else if first_line.as_str().ends_with('\\') {
|
||||
// Ignore the edge case whether a single quoted string is multiple lines through an
|
||||
// escape (https://github.com/astral-sh/ruff/issues/7139). Single quote docstrings are
|
||||
// flagged by D300.
|
||||
// ```python
|
||||
// "\
|
||||
// "
|
||||
// ```
|
||||
return;
|
||||
} else {
|
||||
if checker.enabled(Rule::MultiLineSummarySecondLine) {
|
||||
let mut diagnostic = Diagnostic::new(MultiLineSummarySecondLine, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
let mut indentation = String::from(docstring.indentation);
|
||||
let mut fixable = true;
|
||||
if !indentation.chars().all(char::is_whitespace) {
|
||||
fixable = false;
|
||||
|
||||
// If the docstring isn't on its own line, look at the statement indentation,
|
||||
// and add the default indentation to get the "right" level.
|
||||
if let Definition::Member(member) = &docstring.definition {
|
||||
let stmt_line_start = checker.locator().line_start(member.start());
|
||||
let stmt_indentation = checker
|
||||
.locator()
|
||||
.slice(TextRange::new(stmt_line_start, member.start()));
|
||||
|
||||
if stmt_indentation.chars().all(char::is_whitespace) {
|
||||
indentation.clear();
|
||||
indentation.push_str(stmt_indentation);
|
||||
indentation.push_str(checker.stylist().indentation());
|
||||
fixable = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if fixable {
|
||||
let prefix = leading_quote(contents).unwrap();
|
||||
// Use replacement instead of insert to trim possible whitespace between leading
|
||||
// quote and text.
|
||||
let repl = format!(
|
||||
"{}{}{}",
|
||||
checker.stylist().line_ending().as_str(),
|
||||
indentation,
|
||||
first_line.strip_prefix(prefix).unwrap().trim_start()
|
||||
);
|
||||
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
repl,
|
||||
body.start(),
|
||||
first_line.end(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
use ruff_text_size::{TextLen, TextSize};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::docstrings::clean_space;
|
||||
use ruff_source_file::{NewlineWithTrailingNewline, UniversalNewlines};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for multi-line docstrings whose closing quotes are not on their
|
||||
/// own line.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that the closing quotes of a multi-line docstring be
|
||||
/// on their own line, for consistency and compatibility with documentation
|
||||
/// tools that may need to parse the docstring.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def sort_list(l: List[int]) -> List[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the
|
||||
/// bubble sort algorithm."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def sort_list(l: List[int]) -> List[int]:
|
||||
/// """Return a sorted copy of the list.
|
||||
///
|
||||
/// Sort the list in ascending order and return a copy of the result using the bubble
|
||||
/// sort algorithm.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct NewLineAfterLastParagraph;
|
||||
|
||||
impl AlwaysAutofixableViolation for NewLineAfterLastParagraph {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Multi-line docstring closing quotes should be on a separate line")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Move closing quotes to new line".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// D209
|
||||
pub(crate) fn newline_after_last_paragraph(checker: &mut Checker, docstring: &Docstring) {
|
||||
let contents = docstring.contents;
|
||||
let body = docstring.body();
|
||||
|
||||
if !docstring.triple_quoted() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut line_count = 0;
|
||||
for line in NewlineWithTrailingNewline::from(body.as_str()) {
|
||||
if !line.trim().is_empty() {
|
||||
line_count += 1;
|
||||
}
|
||||
if line_count > 1 {
|
||||
if let Some(last_line) = contents
|
||||
.universal_newlines()
|
||||
.last()
|
||||
.map(|l| l.as_str().trim())
|
||||
{
|
||||
if last_line != "\"\"\"" && last_line != "'''" {
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(NewLineAfterLastParagraph, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Insert a newline just before the end-quote(s).
|
||||
let num_trailing_quotes = "'''".text_len();
|
||||
let num_trailing_spaces: TextSize = last_line
|
||||
.chars()
|
||||
.rev()
|
||||
.skip(usize::from(num_trailing_quotes))
|
||||
.take_while(|c| c.is_whitespace())
|
||||
.map(TextLen::text_len)
|
||||
.sum();
|
||||
let content = format!(
|
||||
"{}{}",
|
||||
checker.stylist().line_ending().as_str(),
|
||||
clean_space(docstring.indentation)
|
||||
);
|
||||
diagnostic.set_fix(Fix::automatic(Edit::replacement(
|
||||
content,
|
||||
docstring.expr.end() - num_trailing_quotes - num_trailing_spaces,
|
||||
docstring.expr.end() - num_trailing_quotes,
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_source_file::UniversalNewlines;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for function docstrings that include the function's signature in
|
||||
/// the summary line.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends against including a function's signature in its
|
||||
/// docstring. Instead, consider using type annotations as a form of
|
||||
/// documentation for the function's parameters and return value.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `google` and
|
||||
/// `pep257` conventions, and disabled when using the `numpy` convention.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(a, b):
|
||||
/// """foo(a: int, b: int) -> list[int]"""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(a: int, b: int) -> list[int]:
|
||||
/// """Return a list of a and b."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct NoSignature;
|
||||
|
||||
impl Violation for NoSignature {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("First line should not be the function's signature")
|
||||
}
|
||||
}
|
||||
|
||||
/// D402
|
||||
pub(crate) fn no_signature(checker: &mut Checker, docstring: &Docstring) {
|
||||
let Some(function) = docstring.definition.as_function_def() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let body = docstring.body();
|
||||
|
||||
let Some(first_line) = body.trim().universal_newlines().next() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Search for occurrences of the function name followed by an open parenthesis (e.g., `foo(` for
|
||||
// a function named `foo`).
|
||||
if first_line
|
||||
.match_indices(function.name.as_str())
|
||||
.any(|(index, _)| first_line[index + function.name.len()..].starts_with('('))
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(NoSignature, docstring.range()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_source_file::NewlineWithTrailingNewline;
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::pydocstyle::helpers::ends_with_backslash;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for surrounding whitespace in docstrings.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Remove surrounding whitespace from the docstring, for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def factorial(n: int) -> int:
|
||||
/// """ Return the factorial of n. """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def factorial(n: int) -> int:
|
||||
/// """Return the factorial of n."""
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct SurroundingWhitespace;
|
||||
|
||||
impl Violation for SurroundingWhitespace {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("No whitespaces allowed surrounding docstring text")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some("Trim surrounding whitespace".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// D210
|
||||
pub(crate) fn no_surrounding_whitespace(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body();
|
||||
|
||||
let mut lines = NewlineWithTrailingNewline::from(body.as_str());
|
||||
let Some(line) = lines.next() else {
|
||||
return;
|
||||
};
|
||||
let trimmed = line.trim();
|
||||
if trimmed.is_empty() {
|
||||
return;
|
||||
}
|
||||
if line == trimmed {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(SurroundingWhitespace, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
let quote = docstring.contents.chars().last().unwrap();
|
||||
// If removing whitespace would lead to an invalid string of quote
|
||||
// characters, avoid applying the fix.
|
||||
if !trimmed.ends_with(quote) && !trimmed.starts_with(quote) && !ends_with_backslash(trimmed)
|
||||
{
|
||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||
trimmed.to_string(),
|
||||
TextRange::at(body.start(), line.text_len()),
|
||||
)));
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use imperative::Mood;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::{from_qualified_name, CallPath};
|
||||
use ruff_python_semantic::analyze::visibility::{is_property, is_test};
|
||||
use ruff_source_file::UniversalNewlines;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::rules::pydocstyle::helpers::normalize_word;
|
||||
|
||||
static MOOD: Lazy<Mood> = Lazy::new(Mood::new);
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstring first lines that are not in an imperative mood.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that the first line of a docstring be written in the
|
||||
/// imperative mood, for consistency.
|
||||
///
|
||||
/// Hint: to rewrite the docstring in the imperative, phrase the first line as
|
||||
/// if it were a command.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `numpy` and
|
||||
/// `pep257` conventions, and disabled when using the `google` conventions.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Returns the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct NonImperativeMood {
|
||||
first_line: String,
|
||||
}
|
||||
|
||||
impl Violation for NonImperativeMood {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let NonImperativeMood { first_line } = self;
|
||||
format!("First line of docstring should be in imperative mood: \"{first_line}\"")
|
||||
}
|
||||
}
|
||||
|
||||
/// D401
|
||||
pub(crate) fn non_imperative_mood(
|
||||
checker: &mut Checker,
|
||||
docstring: &Docstring,
|
||||
property_decorators: &BTreeSet<String>,
|
||||
) {
|
||||
let Some(function) = docstring.definition.as_function_def() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let property_decorators = property_decorators
|
||||
.iter()
|
||||
.map(|decorator| from_qualified_name(decorator))
|
||||
.collect::<Vec<CallPath>>();
|
||||
|
||||
if is_test(&function.name)
|
||||
|| is_property(
|
||||
&function.decorator_list,
|
||||
&property_decorators,
|
||||
checker.semantic(),
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let body = docstring.body();
|
||||
|
||||
// Find first line, disregarding whitespace.
|
||||
let first_line = match body.trim().universal_newlines().next() {
|
||||
Some(line) => line.as_str().trim(),
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Find the first word on that line and normalize it to lower-case.
|
||||
let first_word_norm = match first_line.split_whitespace().next() {
|
||||
Some(word) => normalize_word(word),
|
||||
None => return,
|
||||
};
|
||||
if first_word_norm.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(MOOD.is_imperative(&first_word_norm), Some(false)) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
NonImperativeMood {
|
||||
first_line: first_line.to_string(),
|
||||
},
|
||||
docstring.range(),
|
||||
));
|
||||
}
|
||||
}
|
54
crates/ruff_linter/src/rules/pydocstyle/rules/not_empty.rs
Normal file
54
crates/ruff_linter/src/rules/pydocstyle/rules/not_empty.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::Rule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for empty docstrings.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// An empty docstring is indicative of incomplete documentation. It should either
|
||||
/// be removed or replaced with a meaningful docstring.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """"""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct EmptyDocstring;
|
||||
|
||||
impl Violation for EmptyDocstring {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Docstring is empty")
|
||||
}
|
||||
}
|
||||
|
||||
/// D419
|
||||
pub(crate) fn not_empty(checker: &mut Checker, docstring: &Docstring) -> bool {
|
||||
if !docstring.body().trim().is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::EmptyDocstring) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(EmptyDocstring, docstring.range()));
|
||||
}
|
||||
false
|
||||
}
|
639
crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs
Normal file
639
crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs
Normal file
|
@ -0,0 +1,639 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::identifier::Identifier;
|
||||
use ruff_python_semantic::analyze::visibility::{
|
||||
is_call, is_init, is_magic, is_new, is_overload, is_override, Visibility,
|
||||
};
|
||||
use ruff_python_semantic::{Definition, Member, MemberKind, Module, ModuleKind};
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented public module definitions.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public modules should be documented via docstrings to outline their purpose
|
||||
/// and contents.
|
||||
///
|
||||
/// Generally, module docstrings should describe the purpose of the module and
|
||||
/// list the classes, exceptions, functions, and other objects that are exported
|
||||
/// by the module, alongside a one-line summary of each.
|
||||
///
|
||||
/// If the module is a script, the docstring should be usable as its "usage"
|
||||
/// message.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for module docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class FasterThanLightError(ZeroDivisionError):
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
/// def calculate_speed(distance: float, time: float) -> float:
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// """Utility functions and classes for calculating speed.
|
||||
///
|
||||
/// This module provides:
|
||||
/// - FasterThanLightError: exception when FTL speed is calculated;
|
||||
/// - calculate_speed: calculate speed given distance and time.
|
||||
/// """
|
||||
///
|
||||
///
|
||||
/// class FasterThanLightError(ZeroDivisionError):
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
/// def calculate_speed(distance: float, time: float) -> float:
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicModule;
|
||||
|
||||
impl Violation for UndocumentedPublicModule {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in public module")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented public class definitions.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public classes should be documented via docstrings to outline their purpose
|
||||
/// and behavior.
|
||||
///
|
||||
/// Generally, a class docstring should describe the class's purpose and list
|
||||
/// its public attributes and methods.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for class docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Player:
|
||||
/// def __init__(self, name: str, points: int = 0) -> None:
|
||||
/// self.name: str = name
|
||||
/// self.points: int = points
|
||||
///
|
||||
/// def add_points(self, points: int) -> None:
|
||||
/// self.points += points
|
||||
/// ```
|
||||
///
|
||||
/// Use instead (in the NumPy docstring format):
|
||||
/// ```python
|
||||
/// class Player:
|
||||
/// """A player in the game.
|
||||
///
|
||||
/// Attributes
|
||||
/// ----------
|
||||
/// name : str
|
||||
/// The name of the player.
|
||||
/// points : int
|
||||
/// The number of points the player has.
|
||||
///
|
||||
/// Methods
|
||||
/// -------
|
||||
/// add_points(points: int) -> None
|
||||
/// Add points to the player's score.
|
||||
/// """
|
||||
///
|
||||
/// def __init__(self, name: str, points: int = 0) -> None:
|
||||
/// self.name: str = name
|
||||
/// self.points: int = points
|
||||
///
|
||||
/// def add_points(self, points: int) -> None:
|
||||
/// self.points += points
|
||||
/// ```
|
||||
///
|
||||
/// Or (in the Google docstring format):
|
||||
/// ```python
|
||||
/// class Player:
|
||||
/// """A player in the game.
|
||||
///
|
||||
/// Attributes:
|
||||
/// name: The name of the player.
|
||||
/// points: The number of points the player has.
|
||||
/// """
|
||||
///
|
||||
/// def __init__(self, name: str, points: int = 0) -> None:
|
||||
/// self.name: str = name
|
||||
/// self.points: int = points
|
||||
///
|
||||
/// def add_points(self, points: int) -> None:
|
||||
/// self.points += points
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicClass;
|
||||
|
||||
impl Violation for UndocumentedPublicClass {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in public class")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented public method definitions.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public methods should be documented via docstrings to outline their purpose
|
||||
/// and behavior.
|
||||
///
|
||||
/// Generally, a method docstring should describe the method's behavior,
|
||||
/// arguments, side effects, exceptions, return values, and any other
|
||||
/// information that may be relevant to the user.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for method docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Cat(Animal):
|
||||
/// def greet(self, happy: bool = True):
|
||||
/// if happy:
|
||||
/// print("Meow!")
|
||||
/// else:
|
||||
/// raise ValueError("Tried to greet an unhappy cat.")
|
||||
/// ```
|
||||
///
|
||||
/// Use instead (in the NumPy docstring format):
|
||||
/// ```python
|
||||
/// class Cat(Animal):
|
||||
/// def greet(self, happy: bool = True):
|
||||
/// """Print a greeting from the cat.
|
||||
///
|
||||
/// Parameters
|
||||
/// ----------
|
||||
/// happy : bool, optional
|
||||
/// Whether the cat is happy, is True by default.
|
||||
///
|
||||
/// Raises
|
||||
/// ------
|
||||
/// ValueError
|
||||
/// If the cat is not happy.
|
||||
/// """
|
||||
/// if happy:
|
||||
/// print("Meow!")
|
||||
/// else:
|
||||
/// raise ValueError("Tried to greet an unhappy cat.")
|
||||
/// ```
|
||||
///
|
||||
/// Or (in the Google docstring format):
|
||||
/// ```python
|
||||
/// class Cat(Animal):
|
||||
/// def greet(self, happy: bool = True):
|
||||
/// """Print a greeting from the cat.
|
||||
///
|
||||
/// Args:
|
||||
/// happy: Whether the cat is happy, is True by default.
|
||||
///
|
||||
/// Raises:
|
||||
/// ValueError: If the cat is not happy.
|
||||
/// """
|
||||
/// if happy:
|
||||
/// print("Meow!")
|
||||
/// else:
|
||||
/// raise ValueError("Tried to greet an unhappy cat.")
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicMethod;
|
||||
|
||||
impl Violation for UndocumentedPublicMethod {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in public method")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented public function definitions.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public functions should be documented via docstrings to outline their
|
||||
/// purpose and behavior.
|
||||
///
|
||||
/// Generally, a function docstring should describe the function's behavior,
|
||||
/// arguments, side effects, exceptions, return values, and any other
|
||||
/// information that may be relevant to the user.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for function docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def calculate_speed(distance: float, time: float) -> float:
|
||||
/// try:
|
||||
/// return distance / time
|
||||
/// except ZeroDivisionError as exc:
|
||||
/// raise FasterThanLightError from exc
|
||||
/// ```
|
||||
///
|
||||
/// Use instead (using the NumPy docstring format):
|
||||
/// ```python
|
||||
/// def calculate_speed(distance: float, time: float) -> float:
|
||||
/// """Calculate speed as distance divided by time.
|
||||
///
|
||||
/// Parameters
|
||||
/// ----------
|
||||
/// distance : float
|
||||
/// Distance traveled.
|
||||
/// time : float
|
||||
/// Time spent traveling.
|
||||
///
|
||||
/// Returns
|
||||
/// -------
|
||||
/// float
|
||||
/// Speed as distance divided by time.
|
||||
///
|
||||
/// Raises
|
||||
/// ------
|
||||
/// FasterThanLightError
|
||||
/// If speed is greater than the speed of light.
|
||||
/// """
|
||||
/// try:
|
||||
/// return distance / time
|
||||
/// except ZeroDivisionError as exc:
|
||||
/// raise FasterThanLightError from exc
|
||||
/// ```
|
||||
///
|
||||
/// Or, using the Google docstring format:
|
||||
/// ```python
|
||||
/// def calculate_speed(distance: float, time: float) -> float:
|
||||
/// """Calculate speed as distance divided by time.
|
||||
///
|
||||
/// Args:
|
||||
/// distance: Distance traveled.
|
||||
/// time: Time spent traveling.
|
||||
///
|
||||
/// Returns:
|
||||
/// Speed as distance divided by time.
|
||||
///
|
||||
/// Raises:
|
||||
/// FasterThanLightError: If speed is greater than the speed of light.
|
||||
/// """
|
||||
/// try:
|
||||
/// return distance / time
|
||||
/// except ZeroDivisionError as exc:
|
||||
/// raise FasterThanLightError from exc
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Style Python Docstrings](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicFunction;
|
||||
|
||||
impl Violation for UndocumentedPublicFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in public function")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented public package definitions.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public packages should be documented via docstrings to outline their
|
||||
/// purpose and contents.
|
||||
///
|
||||
/// Generally, package docstrings should list the modules and subpackages that
|
||||
/// are exported by the package.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for package docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// __all__ = ["Player", "Game"]
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// """Game and player management package.
|
||||
///
|
||||
/// This package provides classes for managing players and games.
|
||||
/// """
|
||||
///
|
||||
/// __all__ = ["player", "game"]
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Style Python Docstrings](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicPackage;
|
||||
|
||||
impl Violation for UndocumentedPublicPackage {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in public package")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented magic method definitions.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Magic methods (methods with names that start and end with double
|
||||
/// underscores) are used to implement operator overloading and other special
|
||||
/// behavior. Such methods should should be documented via docstrings to
|
||||
/// outline their behavior.
|
||||
///
|
||||
/// Generally, magic method docstrings should describe the method's behavior,
|
||||
/// arguments, side effects, exceptions, return values, and any other
|
||||
/// information that may be relevant to the user.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for method docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Cat(Animal):
|
||||
/// def __str__(self) -> str:
|
||||
/// return f"Cat: {self.name}"
|
||||
///
|
||||
///
|
||||
/// cat = Cat("Dusty")
|
||||
/// print(cat) # "Cat: Dusty"
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Cat(Animal):
|
||||
/// def __str__(self) -> str:
|
||||
/// """Return a string representation of the cat."""
|
||||
/// return f"Cat: {self.name}"
|
||||
///
|
||||
///
|
||||
/// cat = Cat("Dusty")
|
||||
/// print(cat) # "Cat: Dusty"
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Style Python Docstrings](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedMagicMethod;
|
||||
|
||||
impl Violation for UndocumentedMagicMethod {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in magic method")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for undocumented public class definitions, for nested classes.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public classes should be documented via docstrings to outline their
|
||||
/// purpose and behavior.
|
||||
///
|
||||
/// Nested classes do not inherit the docstring of their enclosing class, so
|
||||
/// they should have their own docstrings.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for class docstrings, follow
|
||||
/// that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// """Class Foo."""
|
||||
///
|
||||
/// class Bar:
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
/// bar = Foo.Bar()
|
||||
/// bar.__doc__ # None
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// """Class Foo."""
|
||||
///
|
||||
/// class Bar:
|
||||
/// """Class Bar."""
|
||||
///
|
||||
///
|
||||
/// bar = Foo.Bar()
|
||||
/// bar.__doc__ # "Class Bar."
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Style Python Docstrings](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicNestedClass;
|
||||
|
||||
impl Violation for UndocumentedPublicNestedClass {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in public nested class")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for public `__init__` method definitions that are missing
|
||||
/// docstrings.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Public `__init__` methods are used to initialize objects. `__init__`
|
||||
/// methods should be documented via docstrings to describe the method's
|
||||
/// behavior, arguments, side effects, exceptions, and any other information
|
||||
/// that may be relevant to the user.
|
||||
///
|
||||
/// If the codebase adheres to a standard format for `__init__` method docstrings,
|
||||
/// follow that format for consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class City:
|
||||
/// def __init__(self, name: str, population: int) -> None:
|
||||
/// self.name: str = name
|
||||
/// self.population: int = population
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class City:
|
||||
/// def __init__(self, name: str, population: int) -> None:
|
||||
/// """Initialize a city with a name and population."""
|
||||
/// self.name: str = name
|
||||
/// self.population: int = population
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Style Python Docstrings](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct UndocumentedPublicInit;
|
||||
|
||||
impl Violation for UndocumentedPublicInit {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Missing docstring in `__init__`")
|
||||
}
|
||||
}
|
||||
|
||||
/// D100, D101, D102, D103, D104, D105, D106, D107
|
||||
pub(crate) fn not_missing(
|
||||
checker: &mut Checker,
|
||||
definition: &Definition,
|
||||
visibility: Visibility,
|
||||
) -> bool {
|
||||
if checker.source_type.is_stub() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if visibility.is_private() {
|
||||
return true;
|
||||
}
|
||||
|
||||
match definition {
|
||||
Definition::Module(Module {
|
||||
kind: ModuleKind::Module,
|
||||
..
|
||||
}) => {
|
||||
if checker.enabled(Rule::UndocumentedPublicModule) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicModule,
|
||||
TextRange::default(),
|
||||
));
|
||||
}
|
||||
false
|
||||
}
|
||||
Definition::Module(Module {
|
||||
kind: ModuleKind::Package,
|
||||
..
|
||||
}) => {
|
||||
if checker.enabled(Rule::UndocumentedPublicPackage) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicPackage,
|
||||
TextRange::default(),
|
||||
));
|
||||
}
|
||||
false
|
||||
}
|
||||
Definition::Member(Member {
|
||||
kind: MemberKind::Class(class),
|
||||
..
|
||||
}) => {
|
||||
if checker.enabled(Rule::UndocumentedPublicClass) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(UndocumentedPublicClass, class.identifier()));
|
||||
}
|
||||
false
|
||||
}
|
||||
Definition::Member(Member {
|
||||
kind: MemberKind::NestedClass(function),
|
||||
..
|
||||
}) => {
|
||||
if checker.enabled(Rule::UndocumentedPublicNestedClass) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicNestedClass,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
false
|
||||
}
|
||||
Definition::Member(Member {
|
||||
kind: MemberKind::Function(function) | MemberKind::NestedFunction(function),
|
||||
..
|
||||
}) => {
|
||||
if is_overload(&function.decorator_list, checker.semantic()) {
|
||||
true
|
||||
} else {
|
||||
if checker.enabled(Rule::UndocumentedPublicFunction) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicFunction,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
Definition::Member(Member {
|
||||
kind: MemberKind::Method(function),
|
||||
..
|
||||
}) => {
|
||||
if is_overload(&function.decorator_list, checker.semantic())
|
||||
|| is_override(&function.decorator_list, checker.semantic())
|
||||
{
|
||||
true
|
||||
} else if is_init(&function.name) {
|
||||
if checker.enabled(Rule::UndocumentedPublicInit) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicInit,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
true
|
||||
} else if is_new(&function.name) || is_call(&function.name) {
|
||||
if checker.enabled(Rule::UndocumentedPublicMethod) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicMethod,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
true
|
||||
} else if is_magic(&function.name) {
|
||||
if checker.enabled(Rule::UndocumentedMagicMethod) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedMagicMethod,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
true
|
||||
} else {
|
||||
if checker.enabled(Rule::UndocumentedPublicMethod) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UndocumentedPublicMethod,
|
||||
function.identifier(),
|
||||
));
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
crates/ruff_linter/src/rules/pydocstyle/rules/one_liner.rs
Normal file
90
crates/ruff_linter/src/rules/pydocstyle/rules/one_liner.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::str::{leading_quote, trailing_quote};
|
||||
use ruff_source_file::NewlineWithTrailingNewline;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for single-line docstrings that are broken across multiple lines.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that docstrings that _can_ fit on one line should be
|
||||
/// formatted on a single line, for consistency and readability.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """
|
||||
/// Return the mean of the given values.
|
||||
/// """
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct FitsOnOneLine;
|
||||
|
||||
impl Violation for FitsOnOneLine {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("One-line docstring should fit on one line")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some("Reformat to one line".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// D200
|
||||
pub(crate) fn one_liner(checker: &mut Checker, docstring: &Docstring) {
|
||||
let mut line_count = 0;
|
||||
let mut non_empty_line_count = 0;
|
||||
for line in NewlineWithTrailingNewline::from(docstring.body().as_str()) {
|
||||
line_count += 1;
|
||||
if !line.trim().is_empty() {
|
||||
non_empty_line_count += 1;
|
||||
}
|
||||
if non_empty_line_count > 1 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if non_empty_line_count == 1 && line_count > 1 {
|
||||
let mut diagnostic = Diagnostic::new(FitsOnOneLine, docstring.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
if let (Some(leading), Some(trailing)) = (
|
||||
leading_quote(docstring.contents),
|
||||
trailing_quote(docstring.contents),
|
||||
) {
|
||||
// If removing whitespace would lead to an invalid string of quote
|
||||
// characters, avoid applying the fix.
|
||||
let body = docstring.body();
|
||||
let trimmed = body.trim();
|
||||
if trimmed.chars().rev().take_while(|c| *c == '\\').count() % 2 == 0
|
||||
&& !trimmed.ends_with(trailing.chars().last().unwrap())
|
||||
&& !trimmed.starts_with(leading.chars().last().unwrap())
|
||||
{
|
||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||
format!("{leading}{trimmed}{trailing}"),
|
||||
docstring.range(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
1999
crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs
Normal file
1999
crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,70 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
use crate::rules::pydocstyle::helpers::normalize_word;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings that start with `This`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257] recommends that the first line of a docstring be written in the
|
||||
/// imperative mood, for consistency.
|
||||
///
|
||||
/// Hint: to rewrite the docstring in the imperative, phrase the first line as
|
||||
/// if it were a command.
|
||||
///
|
||||
/// This rule may not apply to all projects; its applicability is a matter of
|
||||
/// convention. By default, this rule is enabled when using the `numpy`
|
||||
/// convention,, and disabled when using the `google` and `pep257` conventions.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """This function returns the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def average(values: list[float]) -> float:
|
||||
/// """Return the mean of the given values."""
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `pydocstyle.convention`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
///
|
||||
/// [PEP 257]: https://peps.python.org/pep-0257/
|
||||
#[violation]
|
||||
pub struct DocstringStartsWithThis;
|
||||
|
||||
impl Violation for DocstringStartsWithThis {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(r#"First word of the docstring should not be "This""#)
|
||||
}
|
||||
}
|
||||
|
||||
/// D404
|
||||
pub(crate) fn starts_with_this(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body();
|
||||
|
||||
let trimmed = body.trim();
|
||||
if trimmed.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(first_word) = trimmed.split(' ').next() else {
|
||||
return;
|
||||
};
|
||||
if normalize_word(first_word) != "this" {
|
||||
return;
|
||||
}
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(DocstringStartsWithThis, docstring.range()));
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_codegen::Quote;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::Docstring;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for docstrings that use `'''triple single quotes'''` instead of
|
||||
/// `"""triple double quotes"""`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// [PEP 257](https://peps.python.org/pep-0257/#what-is-a-docstring) recommends
|
||||
/// the use of `"""triple double quotes"""` for docstrings, to ensure
|
||||
/// consistency.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def kos_root():
|
||||
/// '''Return the pathname of the KOS root directory.'''
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def kos_root():
|
||||
/// """Return the pathname of the KOS root directory."""
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
|
||||
/// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)
|
||||
/// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
#[violation]
|
||||
pub struct TripleSingleQuotes {
|
||||
expected_quote: Quote,
|
||||
}
|
||||
|
||||
impl Violation for TripleSingleQuotes {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let TripleSingleQuotes { expected_quote } = self;
|
||||
match expected_quote {
|
||||
Quote::Double => format!(r#"Use triple double quotes `"""`"#),
|
||||
Quote::Single => format!(r#"Use triple single quotes `'''`"#),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// D300
|
||||
pub(crate) fn triple_quotes(checker: &mut Checker, docstring: &Docstring) {
|
||||
let leading_quote = docstring.leading_quote();
|
||||
|
||||
let expected_quote = if docstring.body().contains("\"\"\"") {
|
||||
Quote::Single
|
||||
} else {
|
||||
Quote::Double
|
||||
};
|
||||
|
||||
match expected_quote {
|
||||
Quote::Single => {
|
||||
if !leading_quote.ends_with("'''") {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
TripleSingleQuotes { expected_quote },
|
||||
docstring.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Quote::Double => {
|
||||
if !leading_quote.ends_with("\"\"\"") {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
TripleSingleQuotes { expected_quote },
|
||||
docstring.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
crates/ruff_linter/src/rules/pydocstyle/settings.rs
Normal file
79
crates/ruff_linter/src/rules/pydocstyle/settings.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
//! Settings for the `pydocstyle` plugin.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_macros::CacheKey;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, CacheKey)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum Convention {
|
||||
/// Use Google-style docstrings.
|
||||
Google,
|
||||
/// Use NumPy-style docstrings.
|
||||
Numpy,
|
||||
/// Use PEP257-style docstrings.
|
||||
Pep257,
|
||||
}
|
||||
|
||||
impl Convention {
|
||||
pub const fn rules_to_be_ignored(self) -> &'static [Rule] {
|
||||
match self {
|
||||
Convention::Google => &[
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
Rule::OneBlankLineAfterClass,
|
||||
Rule::MultiLineSummarySecondLine,
|
||||
Rule::SectionUnderlineNotOverIndented,
|
||||
Rule::EndsInPeriod,
|
||||
Rule::NonImperativeMood,
|
||||
Rule::DocstringStartsWithThis,
|
||||
Rule::NewLineAfterSectionName,
|
||||
Rule::DashedUnderlineAfterSection,
|
||||
Rule::SectionUnderlineAfterName,
|
||||
Rule::SectionUnderlineMatchesSectionLength,
|
||||
Rule::BlankLineAfterLastSection,
|
||||
],
|
||||
Convention::Numpy => &[
|
||||
Rule::UndocumentedPublicInit,
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
Rule::MultiLineSummaryFirstLine,
|
||||
Rule::MultiLineSummarySecondLine,
|
||||
Rule::NoSignature,
|
||||
Rule::BlankLineAfterLastSection,
|
||||
Rule::EndsInPunctuation,
|
||||
Rule::SectionNameEndsInColon,
|
||||
Rule::UndocumentedParam,
|
||||
],
|
||||
Convention::Pep257 => &[
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
Rule::MultiLineSummaryFirstLine,
|
||||
Rule::MultiLineSummarySecondLine,
|
||||
Rule::SectionNotOverIndented,
|
||||
Rule::SectionUnderlineNotOverIndented,
|
||||
Rule::DocstringStartsWithThis,
|
||||
Rule::CapitalizeSectionName,
|
||||
Rule::NewLineAfterSectionName,
|
||||
Rule::DashedUnderlineAfterSection,
|
||||
Rule::SectionUnderlineAfterName,
|
||||
Rule::SectionUnderlineMatchesSectionLength,
|
||||
Rule::NoBlankLineAfterSection,
|
||||
Rule::NoBlankLineBeforeSection,
|
||||
Rule::BlankLineAfterLastSection,
|
||||
Rule::EndsInPunctuation,
|
||||
Rule::SectionNameEndsInColon,
|
||||
Rule::UndocumentedParam,
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub convention: Option<Convention>,
|
||||
pub ignore_decorators: BTreeSet<String>,
|
||||
pub property_decorators: BTreeSet<String>,
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:1:1: D100 Missing docstring in public module
|
||||
|
|
||||
1 | # No docstring, so we can test D100
|
||||
| D100
|
||||
2 | from functools import wraps
|
||||
3 | import os
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D100_pub.py:1:1: D100 Missing docstring in public module
|
||||
|
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:15:7: D101 Missing docstring in public class
|
||||
|
|
||||
15 | class class_:
|
||||
| ^^^^^^ D101
|
||||
16 |
|
||||
17 | expect('meta', 'D419: Docstring is empty')
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:23:9: D102 Missing docstring in public method
|
||||
|
|
||||
22 | @expect('D102: Missing docstring in public method')
|
||||
23 | def method(self=None):
|
||||
| ^^^^^^ D102
|
||||
24 | pass
|
||||
|
|
||||
|
||||
D.py:56:9: D102 Missing docstring in public method
|
||||
|
|
||||
55 | @expect('D102: Missing docstring in public method')
|
||||
56 | def __new__(self=None):
|
||||
| ^^^^^^^ D102
|
||||
57 | pass
|
||||
|
|
||||
|
||||
D.py:68:9: D102 Missing docstring in public method
|
||||
|
|
||||
67 | @expect('D102: Missing docstring in public method')
|
||||
68 | def __call__(self=None, x=None, y=None, z=None):
|
||||
| ^^^^^^^^ D102
|
||||
69 | pass
|
||||
|
|
||||
|
||||
D.py:650:9: D102 Missing docstring in public method
|
||||
|
|
||||
648 | class StatementOnSameLineAsDocstring:
|
||||
649 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
|
||||
650 | def sort_services(self):
|
||||
| ^^^^^^^^^^^^^ D102
|
||||
651 | pass
|
||||
|
|
||||
|
||||
D.py:659:9: D102 Missing docstring in public method
|
||||
|
|
||||
657 | class CommentAfterDocstring:
|
||||
658 | "After this docstring there's a comment." # priorities=1
|
||||
659 | def sort_services(self):
|
||||
| ^^^^^^^^^^^^^ D102
|
||||
660 | pass
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
setter.py:16:9: D102 Missing docstring in public method
|
||||
|
|
||||
15 | @foo
|
||||
16 | def foo(self, value: str) -> None:
|
||||
| ^^^ D102
|
||||
17 | pass
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:400:5: D103 Missing docstring in public function
|
||||
|
|
||||
399 | @expect("D103: Missing docstring in public function")
|
||||
400 | def oneliner_d102(): return
|
||||
| ^^^^^^^^^^^^^ D103
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
__init__.py:1:1: D104 Missing docstring in public package
|
||||
|
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:64:9: D105 Missing docstring in magic method
|
||||
|
|
||||
63 | @expect('D105: Missing docstring in magic method')
|
||||
64 | def __str__(self=None):
|
||||
| ^^^^^^^ D105
|
||||
65 | pass
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:60:9: D107 Missing docstring in `__init__`
|
||||
|
|
||||
59 | @expect('D107: Missing docstring in __init__')
|
||||
60 | def __init__(self=None):
|
||||
| ^^^^^^^^ D107
|
||||
61 | pass
|
||||
|
|
||||
|
||||
D.py:534:9: D107 Missing docstring in `__init__`
|
||||
|
|
||||
532 | """
|
||||
533 |
|
||||
534 | def __init__(self, x):
|
||||
| ^^^^^^^^ D107
|
||||
535 | pass
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:129:5: D200 [*] One-line docstring should fit on one line
|
||||
|
|
||||
127 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
128 | def asdlkfasd():
|
||||
129 | """
|
||||
| _____^
|
||||
130 | | Wrong.
|
||||
131 | | """
|
||||
| |_______^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
ℹ Suggested fix
|
||||
126 126 | '(found 3)')
|
||||
127 127 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
128 128 | def asdlkfasd():
|
||||
129 |- """
|
||||
130 |- Wrong.
|
||||
131 |- """
|
||||
129 |+ """Wrong."""
|
||||
132 130 |
|
||||
133 131 |
|
||||
134 132 | @expect('D201: No blank lines allowed before function docstring (found 1)')
|
||||
|
||||
D.py:597:5: D200 [*] One-line docstring should fit on one line
|
||||
|
|
||||
595 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
596 | def one_liner():
|
||||
597 | """
|
||||
| _____^
|
||||
598 | |
|
||||
599 | | Wrong."""
|
||||
| |_____________^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
ℹ Suggested fix
|
||||
594 594 | '(found 3)')
|
||||
595 595 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
596 596 | def one_liner():
|
||||
597 |- """
|
||||
598 |-
|
||||
599 |- Wrong."""
|
||||
597 |+ """Wrong."""
|
||||
600 598 |
|
||||
601 599 |
|
||||
602 600 | @expect('D200: One-line docstring should fit on one line with quotes '
|
||||
|
||||
D.py:606:5: D200 [*] One-line docstring should fit on one line
|
||||
|
|
||||
604 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
605 | def one_liner():
|
||||
606 | r"""Wrong.
|
||||
| _____^
|
||||
607 | |
|
||||
608 | | """
|
||||
| |_______^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
ℹ Suggested fix
|
||||
603 603 | '(found 3)')
|
||||
604 604 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
605 605 | def one_liner():
|
||||
606 |- r"""Wrong.
|
||||
607 |-
|
||||
608 |- """
|
||||
606 |+ r"""Wrong."""
|
||||
609 607 |
|
||||
610 608 |
|
||||
611 609 | @expect('D200: One-line docstring should fit on one line with quotes '
|
||||
|
||||
D.py:615:5: D200 One-line docstring should fit on one line
|
||||
|
|
||||
613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 | def one_liner():
|
||||
615 | """Wrong."
|
||||
| _____^
|
||||
616 | |
|
||||
617 | | """
|
||||
| |_______^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
D.py:624:5: D200 One-line docstring should fit on one line
|
||||
|
|
||||
622 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
623 | def one_liner():
|
||||
624 | """
|
||||
| _____^
|
||||
625 | |
|
||||
626 | | "Wrong."""
|
||||
| |______________^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
D.py:645:5: D200 One-line docstring should fit on one line
|
||||
|
|
||||
644 | def single_line_docstring_with_an_escaped_backslash():
|
||||
645 | "\
|
||||
| _____^
|
||||
646 | | "
|
||||
| |_____^ D200
|
||||
647 |
|
||||
648 | class StatementOnSameLineAsDocstring:
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D200.py:2:5: D200 One-line docstring should fit on one line
|
||||
|
|
||||
1 | def func():
|
||||
2 | """\
|
||||
| _____^
|
||||
3 | | """
|
||||
| |_______^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
D200.py:7:5: D200 [*] One-line docstring should fit on one line
|
||||
|
|
||||
6 | def func():
|
||||
7 | """\\
|
||||
| _____^
|
||||
8 | | """
|
||||
| |_______^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
ℹ Suggested fix
|
||||
4 4 |
|
||||
5 5 |
|
||||
6 6 | def func():
|
||||
7 |- """\\
|
||||
8 |- """
|
||||
7 |+ """\\"""
|
||||
9 8 |
|
||||
10 9 |
|
||||
11 10 | def func():
|
||||
|
||||
D200.py:12:5: D200 One-line docstring should fit on one line
|
||||
|
|
||||
11 | def func():
|
||||
12 | """\ \
|
||||
| _____^
|
||||
13 | | """
|
||||
| |_______^ D200
|
||||
|
|
||||
= help: Reformat to one line
|
||||
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:137:5: D201 [*] No blank lines allowed before function docstring (found 1)
|
||||
|
|
||||
135 | def leading_space():
|
||||
136 |
|
||||
137 | """Leading space."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D201
|
||||
|
|
||||
= help: Remove blank line(s) before function docstring
|
||||
|
||||
ℹ Fix
|
||||
133 133 |
|
||||
134 134 | @expect('D201: No blank lines allowed before function docstring (found 1)')
|
||||
135 135 | def leading_space():
|
||||
136 |-
|
||||
137 136 | """Leading space."""
|
||||
138 137 |
|
||||
139 138 |
|
||||
|
||||
D.py:151:5: D201 [*] No blank lines allowed before function docstring (found 1)
|
||||
|
|
||||
149 | def trailing_and_leading_space():
|
||||
150 |
|
||||
151 | """Trailing and leading space."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D201
|
||||
152 |
|
||||
153 | pass
|
||||
|
|
||||
= help: Remove blank line(s) before function docstring
|
||||
|
||||
ℹ Fix
|
||||
147 147 | @expect('D201: No blank lines allowed before function docstring (found 1)')
|
||||
148 148 | @expect('D202: No blank lines allowed after function docstring (found 1)')
|
||||
149 149 | def trailing_and_leading_space():
|
||||
150 |-
|
||||
151 150 | """Trailing and leading space."""
|
||||
152 151 |
|
||||
153 152 | pass
|
||||
|
||||
D.py:546:5: D201 [*] No blank lines allowed before function docstring (found 1)
|
||||
|
|
||||
544 | def multiline_leading_space():
|
||||
545 |
|
||||
546 | """Leading space.
|
||||
| _____^
|
||||
547 | |
|
||||
548 | | More content.
|
||||
549 | | """
|
||||
| |_______^ D201
|
||||
|
|
||||
= help: Remove blank line(s) before function docstring
|
||||
|
||||
ℹ Fix
|
||||
542 542 | @expect('D201: No blank lines allowed before function docstring (found 1)')
|
||||
543 543 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
544 544 | def multiline_leading_space():
|
||||
545 |-
|
||||
546 545 | """Leading space.
|
||||
547 546 |
|
||||
548 547 | More content.
|
||||
|
||||
D.py:568:5: D201 [*] No blank lines allowed before function docstring (found 1)
|
||||
|
|
||||
566 | def multiline_trailing_and_leading_space():
|
||||
567 |
|
||||
568 | """Trailing and leading space.
|
||||
| _____^
|
||||
569 | |
|
||||
570 | | More content.
|
||||
571 | | """
|
||||
| |_______^ D201
|
||||
572 |
|
||||
573 | pass
|
||||
|
|
||||
= help: Remove blank line(s) before function docstring
|
||||
|
||||
ℹ Fix
|
||||
564 564 | @expect('D202: No blank lines allowed after function docstring (found 1)')
|
||||
565 565 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
566 566 | def multiline_trailing_and_leading_space():
|
||||
567 |-
|
||||
568 567 | """Trailing and leading space.
|
||||
569 568 |
|
||||
570 569 | More content.
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:142:5: D202 [*] No blank lines allowed after function docstring (found 1)
|
||||
|
|
||||
140 | @expect('D202: No blank lines allowed after function docstring (found 1)')
|
||||
141 | def trailing_space():
|
||||
142 | """Leading space."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D202
|
||||
143 |
|
||||
144 | pass
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
140 140 | @expect('D202: No blank lines allowed after function docstring (found 1)')
|
||||
141 141 | def trailing_space():
|
||||
142 142 | """Leading space."""
|
||||
143 |-
|
||||
144 143 | pass
|
||||
145 144 |
|
||||
146 145 |
|
||||
|
||||
D.py:151:5: D202 [*] No blank lines allowed after function docstring (found 1)
|
||||
|
|
||||
149 | def trailing_and_leading_space():
|
||||
150 |
|
||||
151 | """Trailing and leading space."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D202
|
||||
152 |
|
||||
153 | pass
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
149 149 | def trailing_and_leading_space():
|
||||
150 150 |
|
||||
151 151 | """Trailing and leading space."""
|
||||
152 |-
|
||||
153 152 | pass
|
||||
154 153 |
|
||||
155 154 |
|
||||
|
||||
D.py:555:5: D202 [*] No blank lines allowed after function docstring (found 1)
|
||||
|
|
||||
553 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
554 | def multiline_trailing_space():
|
||||
555 | """Leading space.
|
||||
| _____^
|
||||
556 | |
|
||||
557 | | More content.
|
||||
558 | | """
|
||||
| |_______^ D202
|
||||
559 |
|
||||
560 | pass
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
556 556 |
|
||||
557 557 | More content.
|
||||
558 558 | """
|
||||
559 |-
|
||||
560 559 | pass
|
||||
561 560 |
|
||||
562 561 |
|
||||
|
||||
D.py:568:5: D202 [*] No blank lines allowed after function docstring (found 1)
|
||||
|
|
||||
566 | def multiline_trailing_and_leading_space():
|
||||
567 |
|
||||
568 | """Trailing and leading space.
|
||||
| _____^
|
||||
569 | |
|
||||
570 | | More content.
|
||||
571 | | """
|
||||
| |_______^ D202
|
||||
572 |
|
||||
573 | pass
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
569 569 |
|
||||
570 570 | More content.
|
||||
571 571 | """
|
||||
572 |-
|
||||
573 572 | pass
|
||||
574 573 |
|
||||
575 574 |
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D202.py:57:5: D202 [*] No blank lines allowed after function docstring (found 2)
|
||||
|
|
||||
55 | # D202
|
||||
56 | def outer():
|
||||
57 | """This is a docstring."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ D202
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
55 55 | # D202
|
||||
56 56 | def outer():
|
||||
57 57 | """This is a docstring."""
|
||||
58 |-
|
||||
59 |-
|
||||
60 58 | def inner():
|
||||
61 59 | return
|
||||
62 60 |
|
||||
|
||||
D202.py:68:5: D202 [*] No blank lines allowed after function docstring (found 2)
|
||||
|
|
||||
66 | # D202
|
||||
67 | def outer():
|
||||
68 | """This is a docstring."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ D202
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
66 66 | # D202
|
||||
67 67 | def outer():
|
||||
68 68 | """This is a docstring."""
|
||||
69 |-
|
||||
70 |-
|
||||
71 69 | # This is a comment.
|
||||
72 70 | def inner():
|
||||
73 71 | return
|
||||
|
||||
D202.py:80:5: D202 [*] No blank lines allowed after function docstring (found 1)
|
||||
|
|
||||
78 | # D202
|
||||
79 | def outer():
|
||||
80 | """This is a docstring."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ D202
|
||||
81 |
|
||||
82 | # This is a comment.
|
||||
|
|
||||
= help: Remove blank line(s) after function docstring
|
||||
|
||||
ℹ Fix
|
||||
78 78 | # D202
|
||||
79 79 | def outer():
|
||||
80 80 | """This is a docstring."""
|
||||
81 |-
|
||||
82 81 | # This is a comment.
|
||||
83 82 |
|
||||
84 83 | def inner():
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:161:5: D203 [*] 1 blank line required before class docstring
|
||||
|
|
||||
160 | class LeadingSpaceMissing:
|
||||
161 | """Leading space missing."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D203
|
||||
|
|
||||
= help: Insert 1 blank line before class docstring
|
||||
|
||||
ℹ Fix
|
||||
158 158 |
|
||||
159 159 |
|
||||
160 160 | class LeadingSpaceMissing:
|
||||
161 |+
|
||||
161 162 | """Leading space missing."""
|
||||
162 163 |
|
||||
163 164 |
|
||||
|
||||
D.py:192:5: D203 [*] 1 blank line required before class docstring
|
||||
|
|
||||
191 | class LeadingAndTrailingSpaceMissing:
|
||||
192 | """Leading and trailing space missing."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D203
|
||||
193 | pass
|
||||
|
|
||||
= help: Insert 1 blank line before class docstring
|
||||
|
||||
ℹ Fix
|
||||
189 189 |
|
||||
190 190 |
|
||||
191 191 | class LeadingAndTrailingSpaceMissing:
|
||||
192 |+
|
||||
192 193 | """Leading and trailing space missing."""
|
||||
193 194 | pass
|
||||
194 195 |
|
||||
|
||||
D.py:526:5: D203 [*] 1 blank line required before class docstring
|
||||
|
|
||||
524 | # parameters as functions for Google / Numpy conventions.
|
||||
525 | class Blah: # noqa: D203,D213
|
||||
526 | """A Blah.
|
||||
| _____^
|
||||
527 | |
|
||||
528 | | Parameters
|
||||
529 | | ----------
|
||||
530 | | x : int
|
||||
531 | |
|
||||
532 | | """
|
||||
| |_______^ D203
|
||||
533 |
|
||||
534 | def __init__(self, x):
|
||||
|
|
||||
= help: Insert 1 blank line before class docstring
|
||||
|
||||
ℹ Fix
|
||||
523 523 | # This is reproducing a bug where AttributeError is raised when parsing class
|
||||
524 524 | # parameters as functions for Google / Numpy conventions.
|
||||
525 525 | class Blah: # noqa: D203,D213
|
||||
526 |+
|
||||
526 527 | """A Blah.
|
||||
527 528 |
|
||||
528 529 | Parameters
|
||||
|
||||
D.py:649:5: D203 [*] 1 blank line required before class docstring
|
||||
|
|
||||
648 | class StatementOnSameLineAsDocstring:
|
||||
649 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D203
|
||||
650 | def sort_services(self):
|
||||
651 | pass
|
||||
|
|
||||
= help: Insert 1 blank line before class docstring
|
||||
|
||||
ℹ Fix
|
||||
646 646 | "
|
||||
647 647 |
|
||||
648 648 | class StatementOnSameLineAsDocstring:
|
||||
649 |+
|
||||
649 650 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
|
||||
650 651 | def sort_services(self):
|
||||
651 652 | pass
|
||||
|
||||
D.py:654:5: D203 [*] 1 blank line required before class docstring
|
||||
|
|
||||
653 | class StatementOnSameLineAsDocstring:
|
||||
654 | "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D203
|
||||
|
|
||||
= help: Insert 1 blank line before class docstring
|
||||
|
||||
ℹ Fix
|
||||
651 651 | pass
|
||||
652 652 |
|
||||
653 653 | class StatementOnSameLineAsDocstring:
|
||||
654 |+
|
||||
654 655 | "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
|
||||
655 656 |
|
||||
656 657 |
|
||||
|
||||
D.py:658:5: D203 [*] 1 blank line required before class docstring
|
||||
|
|
||||
657 | class CommentAfterDocstring:
|
||||
658 | "After this docstring there's a comment." # priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D203
|
||||
659 | def sort_services(self):
|
||||
660 | pass
|
||||
|
|
||||
= help: Insert 1 blank line before class docstring
|
||||
|
||||
ℹ Fix
|
||||
655 655 |
|
||||
656 656 |
|
||||
657 657 | class CommentAfterDocstring:
|
||||
658 |+
|
||||
658 659 | "After this docstring there's a comment." # priorities=1
|
||||
659 660 | def sort_services(self):
|
||||
660 661 | pass
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:181:5: D204 [*] 1 blank line required after class docstring
|
||||
|
|
||||
179 | class TrailingSpace:
|
||||
180 |
|
||||
181 | """TrailingSpace."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D204
|
||||
182 | pass
|
||||
|
|
||||
= help: Insert 1 blank line after class docstring
|
||||
|
||||
ℹ Fix
|
||||
179 179 | class TrailingSpace:
|
||||
180 180 |
|
||||
181 181 | """TrailingSpace."""
|
||||
182 |+
|
||||
182 183 | pass
|
||||
183 184 |
|
||||
184 185 |
|
||||
|
||||
D.py:192:5: D204 [*] 1 blank line required after class docstring
|
||||
|
|
||||
191 | class LeadingAndTrailingSpaceMissing:
|
||||
192 | """Leading and trailing space missing."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D204
|
||||
193 | pass
|
||||
|
|
||||
= help: Insert 1 blank line after class docstring
|
||||
|
||||
ℹ Fix
|
||||
190 190 |
|
||||
191 191 | class LeadingAndTrailingSpaceMissing:
|
||||
192 192 | """Leading and trailing space missing."""
|
||||
193 |+
|
||||
193 194 | pass
|
||||
194 195 |
|
||||
195 196 |
|
||||
|
||||
D.py:649:5: D204 [*] 1 blank line required after class docstring
|
||||
|
|
||||
648 | class StatementOnSameLineAsDocstring:
|
||||
649 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D204
|
||||
650 | def sort_services(self):
|
||||
651 | pass
|
||||
|
|
||||
= help: Insert 1 blank line after class docstring
|
||||
|
||||
ℹ Fix
|
||||
646 646 | "
|
||||
647 647 |
|
||||
648 648 | class StatementOnSameLineAsDocstring:
|
||||
649 |- "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
|
||||
649 |+ "After this docstring there's another statement on the same line separated by a semicolon."
|
||||
650 |+
|
||||
651 |+ priorities=1
|
||||
650 652 | def sort_services(self):
|
||||
651 653 | pass
|
||||
652 654 |
|
||||
|
||||
D.py:654:5: D204 [*] 1 blank line required after class docstring
|
||||
|
|
||||
653 | class StatementOnSameLineAsDocstring:
|
||||
654 | "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D204
|
||||
|
|
||||
= help: Insert 1 blank line after class docstring
|
||||
|
||||
ℹ Fix
|
||||
651 651 | pass
|
||||
652 652 |
|
||||
653 653 | class StatementOnSameLineAsDocstring:
|
||||
654 |- "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
|
||||
654 |+ "After this docstring there's another statement on the same line separated by a semicolon."
|
||||
655 |+
|
||||
656 |+ priorities=1
|
||||
655 657 |
|
||||
656 658 |
|
||||
657 659 | class CommentAfterDocstring:
|
||||
|
||||
D.py:658:5: D204 [*] 1 blank line required after class docstring
|
||||
|
|
||||
657 | class CommentAfterDocstring:
|
||||
658 | "After this docstring there's a comment." # priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D204
|
||||
659 | def sort_services(self):
|
||||
660 | pass
|
||||
|
|
||||
= help: Insert 1 blank line after class docstring
|
||||
|
||||
ℹ Fix
|
||||
656 656 |
|
||||
657 657 | class CommentAfterDocstring:
|
||||
658 658 | "After this docstring there's a comment." # priorities=1
|
||||
659 |+
|
||||
659 660 | def sort_services(self):
|
||||
660 661 | pass
|
||||
661 662 |
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:200:5: D205 1 blank line required between summary line and description
|
||||
|
|
||||
198 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
199 | def multi_line_zero_separating_blanks():
|
||||
200 | """Summary.
|
||||
| _____^
|
||||
201 | | Description.
|
||||
202 | |
|
||||
203 | | """
|
||||
| |_______^ D205
|
||||
|
|
||||
= help: Insert single blank line
|
||||
|
||||
D.py:210:5: D205 [*] 1 blank line required between summary line and description (found 2)
|
||||
|
|
||||
208 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
209 | def multi_line_two_separating_blanks():
|
||||
210 | """Summary.
|
||||
| _____^
|
||||
211 | |
|
||||
212 | |
|
||||
213 | | Description.
|
||||
214 | |
|
||||
215 | | """
|
||||
| |_______^ D205
|
||||
|
|
||||
= help: Insert single blank line
|
||||
|
||||
ℹ Fix
|
||||
209 209 | def multi_line_two_separating_blanks():
|
||||
210 210 | """Summary.
|
||||
211 211 |
|
||||
212 |-
|
||||
213 212 | Description.
|
||||
214 213 |
|
||||
215 214 | """
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:232:1: D207 [*] Docstring is under-indented
|
||||
|
|
||||
230 | """Summary.
|
||||
231 |
|
||||
232 | Description.
|
||||
| D207
|
||||
233 |
|
||||
234 | """
|
||||
|
|
||||
= help: Increase indentation
|
||||
|
||||
ℹ Fix
|
||||
229 229 | def asdfsdf():
|
||||
230 230 | """Summary.
|
||||
231 231 |
|
||||
232 |-Description.
|
||||
232 |+ Description.
|
||||
233 233 |
|
||||
234 234 | """
|
||||
235 235 |
|
||||
|
||||
D.py:244:1: D207 [*] Docstring is under-indented
|
||||
|
|
||||
242 | Description.
|
||||
243 |
|
||||
244 | """
|
||||
| D207
|
||||
|
|
||||
= help: Increase indentation
|
||||
|
||||
ℹ Fix
|
||||
241 241 |
|
||||
242 242 | Description.
|
||||
243 243 |
|
||||
244 |-"""
|
||||
244 |+ """
|
||||
245 245 |
|
||||
246 246 |
|
||||
247 247 | @expect('D208: Docstring is over-indented')
|
||||
|
||||
D.py:440:1: D207 [*] Docstring is under-indented
|
||||
|
|
||||
438 | def docstring_start_in_same_line(): """First Line.
|
||||
439 |
|
||||
440 | Second Line
|
||||
| D207
|
||||
441 | """
|
||||
|
|
||||
= help: Increase indentation
|
||||
|
||||
ℹ Fix
|
||||
437 437 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
438 438 | def docstring_start_in_same_line(): """First Line.
|
||||
439 439 |
|
||||
440 |- Second Line
|
||||
440 |+ Second Line
|
||||
441 441 | """
|
||||
442 442 |
|
||||
443 443 |
|
||||
|
||||
D.py:441:1: D207 [*] Docstring is under-indented
|
||||
|
|
||||
440 | Second Line
|
||||
441 | """
|
||||
| D207
|
||||
|
|
||||
= help: Increase indentation
|
||||
|
||||
ℹ Fix
|
||||
438 438 | def docstring_start_in_same_line(): """First Line.
|
||||
439 439 |
|
||||
440 440 | Second Line
|
||||
441 |- """
|
||||
441 |+ """
|
||||
442 442 |
|
||||
443 443 |
|
||||
444 444 | def function_with_lambda_arg(x=lambda y: y):
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:252:1: D208 [*] Docstring is over-indented
|
||||
|
|
||||
250 | """Summary.
|
||||
251 |
|
||||
252 | Description.
|
||||
| D208
|
||||
253 |
|
||||
254 | """
|
||||
|
|
||||
= help: Remove over-indentation
|
||||
|
||||
ℹ Fix
|
||||
249 249 | def asdfsdsdf24():
|
||||
250 250 | """Summary.
|
||||
251 251 |
|
||||
252 |- Description.
|
||||
252 |+ Description.
|
||||
253 253 |
|
||||
254 254 | """
|
||||
255 255 |
|
||||
|
||||
D.py:264:1: D208 [*] Docstring is over-indented
|
||||
|
|
||||
262 | Description.
|
||||
263 |
|
||||
264 | """
|
||||
| D208
|
||||
|
|
||||
= help: Remove over-indentation
|
||||
|
||||
ℹ Fix
|
||||
261 261 |
|
||||
262 262 | Description.
|
||||
263 263 |
|
||||
264 |- """
|
||||
264 |+ """
|
||||
265 265 |
|
||||
266 266 |
|
||||
267 267 | @expect('D208: Docstring is over-indented')
|
||||
|
||||
D.py:272:1: D208 [*] Docstring is over-indented
|
||||
|
|
||||
270 | """Summary.
|
||||
271 |
|
||||
272 | Description.
|
||||
| D208
|
||||
273 |
|
||||
274 | """
|
||||
|
|
||||
= help: Remove over-indentation
|
||||
|
||||
ℹ Fix
|
||||
269 269 | def asdfsdfsdsdsdfsdf24():
|
||||
270 270 | """Summary.
|
||||
271 271 |
|
||||
272 |- Description.
|
||||
272 |+ Description.
|
||||
273 273 |
|
||||
274 274 | """
|
||||
275 275 |
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:281:5: D209 [*] Multi-line docstring closing quotes should be on a separate line
|
||||
|
|
||||
279 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
280 | def asdfljdf24():
|
||||
281 | """Summary.
|
||||
| _____^
|
||||
282 | |
|
||||
283 | | Description."""
|
||||
| |___________________^ D209
|
||||
|
|
||||
= help: Move closing quotes to new line
|
||||
|
||||
ℹ Fix
|
||||
280 280 | def asdfljdf24():
|
||||
281 281 | """Summary.
|
||||
282 282 |
|
||||
283 |- Description."""
|
||||
283 |+ Description.
|
||||
284 |+ """
|
||||
284 285 |
|
||||
285 286 |
|
||||
286 287 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
|
||||
D.py:588:5: D209 [*] Multi-line docstring closing quotes should be on a separate line
|
||||
|
|
||||
586 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
587 | def asdfljdjgf24():
|
||||
588 | """Summary.
|
||||
| _____^
|
||||
589 | |
|
||||
590 | | Description. """
|
||||
| |_____________________^ D209
|
||||
|
|
||||
= help: Move closing quotes to new line
|
||||
|
||||
ℹ Fix
|
||||
587 587 | def asdfljdjgf24():
|
||||
588 588 | """Summary.
|
||||
589 589 |
|
||||
590 |- Description. """
|
||||
590 |+ Description.
|
||||
591 |+ """
|
||||
591 592 |
|
||||
592 593 |
|
||||
593 594 | @expect('D200: One-line docstring should fit on one line with quotes '
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:288:5: D210 [*] No whitespaces allowed surrounding docstring text
|
||||
|
|
||||
286 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
287 | def endswith():
|
||||
288 | """Whitespace at the end. """
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D210
|
||||
|
|
||||
= help: Trim surrounding whitespace
|
||||
|
||||
ℹ Fix
|
||||
285 285 |
|
||||
286 286 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
287 287 | def endswith():
|
||||
288 |- """Whitespace at the end. """
|
||||
288 |+ """Whitespace at the end."""
|
||||
289 289 |
|
||||
290 290 |
|
||||
291 291 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
|
||||
D.py:293:5: D210 [*] No whitespaces allowed surrounding docstring text
|
||||
|
|
||||
291 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
292 | def around():
|
||||
293 | """ Whitespace at everywhere. """
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D210
|
||||
|
|
||||
= help: Trim surrounding whitespace
|
||||
|
||||
ℹ Fix
|
||||
290 290 |
|
||||
291 291 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
292 292 | def around():
|
||||
293 |- """ Whitespace at everywhere. """
|
||||
293 |+ """Whitespace at everywhere."""
|
||||
294 294 |
|
||||
295 295 |
|
||||
296 296 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
|
||||
D.py:299:5: D210 [*] No whitespaces allowed surrounding docstring text
|
||||
|
|
||||
297 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
298 | def multiline():
|
||||
299 | """ Whitespace at the beginning.
|
||||
| _____^
|
||||
300 | |
|
||||
301 | | This is the end.
|
||||
302 | | """
|
||||
| |_______^ D210
|
||||
|
|
||||
= help: Trim surrounding whitespace
|
||||
|
||||
ℹ Fix
|
||||
296 296 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
297 297 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
298 298 | def multiline():
|
||||
299 |- """ Whitespace at the beginning.
|
||||
299 |+ """Whitespace at the beginning.
|
||||
300 300 |
|
||||
301 301 | This is the end.
|
||||
302 302 | """
|
||||
|
||||
D.py:581:5: D210 No whitespaces allowed surrounding docstring text
|
||||
|
|
||||
579 | "or exclamation point (not '\"')")
|
||||
580 | def endswith_quote():
|
||||
581 | """Whitespace at the end, but also a quote" """
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D210
|
||||
|
|
||||
= help: Trim surrounding whitespace
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:170:5: D211 [*] No blank lines allowed before class docstring
|
||||
|
|
||||
168 | class WithLeadingSpace:
|
||||
169 |
|
||||
170 | """With leading space."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ D211
|
||||
|
|
||||
= help: Remove blank line(s) before class docstring
|
||||
|
||||
ℹ Fix
|
||||
166 166 |
|
||||
167 167 |
|
||||
168 168 | class WithLeadingSpace:
|
||||
169 |-
|
||||
170 169 | """With leading space."""
|
||||
171 170 |
|
||||
172 171 |
|
||||
|
||||
D.py:181:5: D211 [*] No blank lines allowed before class docstring
|
||||
|
|
||||
179 | class TrailingSpace:
|
||||
180 |
|
||||
181 | """TrailingSpace."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D211
|
||||
182 | pass
|
||||
|
|
||||
= help: Remove blank line(s) before class docstring
|
||||
|
||||
ℹ Fix
|
||||
177 177 |
|
||||
178 178 |
|
||||
179 179 | class TrailingSpace:
|
||||
180 |-
|
||||
181 180 | """TrailingSpace."""
|
||||
182 181 | pass
|
||||
183 182 |
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:129:5: D212 [*] Multi-line docstring summary should start at the first line
|
||||
|
|
||||
127 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
128 | def asdlkfasd():
|
||||
129 | """
|
||||
| _____^
|
||||
130 | | Wrong.
|
||||
131 | | """
|
||||
| |_______^ D212
|
||||
|
|
||||
= help: Remove whitespace after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
126 126 | '(found 3)')
|
||||
127 127 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
128 128 | def asdlkfasd():
|
||||
129 |- """
|
||||
130 |- Wrong.
|
||||
129 |+ """Wrong.
|
||||
131 130 | """
|
||||
132 131 |
|
||||
133 132 |
|
||||
|
||||
D.py:597:5: D212 [*] Multi-line docstring summary should start at the first line
|
||||
|
|
||||
595 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
596 | def one_liner():
|
||||
597 | """
|
||||
| _____^
|
||||
598 | |
|
||||
599 | | Wrong."""
|
||||
| |_____________^ D212
|
||||
|
|
||||
= help: Remove whitespace after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
594 594 | '(found 3)')
|
||||
595 595 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
596 596 | def one_liner():
|
||||
597 |- """
|
||||
598 |-
|
||||
599 |- Wrong."""
|
||||
597 |+ """Wrong."""
|
||||
600 598 |
|
||||
601 599 |
|
||||
602 600 | @expect('D200: One-line docstring should fit on one line with quotes '
|
||||
|
||||
D.py:624:5: D212 [*] Multi-line docstring summary should start at the first line
|
||||
|
|
||||
622 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
623 | def one_liner():
|
||||
624 | """
|
||||
| _____^
|
||||
625 | |
|
||||
626 | | "Wrong."""
|
||||
| |______________^ D212
|
||||
|
|
||||
= help: Remove whitespace after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
621 621 | '(found 3)')
|
||||
622 622 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
623 623 | def one_liner():
|
||||
624 |- """
|
||||
625 |-
|
||||
626 |- "Wrong."""
|
||||
624 |+ """"Wrong."""
|
||||
627 625 |
|
||||
628 626 |
|
||||
629 627 | @expect('D404: First word of the docstring should not be "This"')
|
||||
|
||||
|
|
@ -0,0 +1,550 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:200:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
198 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
199 | def multi_line_zero_separating_blanks():
|
||||
200 | """Summary.
|
||||
| _____^
|
||||
201 | | Description.
|
||||
202 | |
|
||||
203 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
197 197 | '(found 0)')
|
||||
198 198 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
199 199 | def multi_line_zero_separating_blanks():
|
||||
200 |- """Summary.
|
||||
200 |+ """
|
||||
201 |+ Summary.
|
||||
201 202 | Description.
|
||||
202 203 |
|
||||
203 204 | """
|
||||
|
||||
D.py:210:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
208 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
209 | def multi_line_two_separating_blanks():
|
||||
210 | """Summary.
|
||||
| _____^
|
||||
211 | |
|
||||
212 | |
|
||||
213 | | Description.
|
||||
214 | |
|
||||
215 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
207 207 | '(found 2)')
|
||||
208 208 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
209 209 | def multi_line_two_separating_blanks():
|
||||
210 |- """Summary.
|
||||
210 |+ """
|
||||
211 |+ Summary.
|
||||
211 212 |
|
||||
212 213 |
|
||||
213 214 | Description.
|
||||
|
||||
D.py:220:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
218 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
219 | def multi_line_one_separating_blanks():
|
||||
220 | """Summary.
|
||||
| _____^
|
||||
221 | |
|
||||
222 | | Description.
|
||||
223 | |
|
||||
224 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
217 217 |
|
||||
218 218 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
219 219 | def multi_line_one_separating_blanks():
|
||||
220 |- """Summary.
|
||||
220 |+ """
|
||||
221 |+ Summary.
|
||||
221 222 |
|
||||
222 223 | Description.
|
||||
223 224 |
|
||||
|
||||
D.py:230:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
228 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
229 | def asdfsdf():
|
||||
230 | """Summary.
|
||||
| _____^
|
||||
231 | |
|
||||
232 | | Description.
|
||||
233 | |
|
||||
234 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
227 227 | @expect('D207: Docstring is under-indented')
|
||||
228 228 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
229 229 | def asdfsdf():
|
||||
230 |- """Summary.
|
||||
230 |+ """
|
||||
231 |+ Summary.
|
||||
231 232 |
|
||||
232 233 | Description.
|
||||
233 234 |
|
||||
|
||||
D.py:240:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
238 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
239 | def asdsdfsdffsdf():
|
||||
240 | """Summary.
|
||||
| _____^
|
||||
241 | |
|
||||
242 | | Description.
|
||||
243 | |
|
||||
244 | | """
|
||||
| |___^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
237 237 | @expect('D207: Docstring is under-indented')
|
||||
238 238 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
239 239 | def asdsdfsdffsdf():
|
||||
240 |- """Summary.
|
||||
240 |+ """
|
||||
241 |+ Summary.
|
||||
241 242 |
|
||||
242 243 | Description.
|
||||
243 244 |
|
||||
|
||||
D.py:250:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
248 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
249 | def asdfsdsdf24():
|
||||
250 | """Summary.
|
||||
| _____^
|
||||
251 | |
|
||||
252 | | Description.
|
||||
253 | |
|
||||
254 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
247 247 | @expect('D208: Docstring is over-indented')
|
||||
248 248 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
249 249 | def asdfsdsdf24():
|
||||
250 |- """Summary.
|
||||
250 |+ """
|
||||
251 |+ Summary.
|
||||
251 252 |
|
||||
252 253 | Description.
|
||||
253 254 |
|
||||
|
||||
D.py:260:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
258 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
259 | def asdfsdsdfsdf24():
|
||||
260 | """Summary.
|
||||
| _____^
|
||||
261 | |
|
||||
262 | | Description.
|
||||
263 | |
|
||||
264 | | """
|
||||
| |___________^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
257 257 | @expect('D208: Docstring is over-indented')
|
||||
258 258 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
259 259 | def asdfsdsdfsdf24():
|
||||
260 |- """Summary.
|
||||
260 |+ """
|
||||
261 |+ Summary.
|
||||
261 262 |
|
||||
262 263 | Description.
|
||||
263 264 |
|
||||
|
||||
D.py:270:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
268 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
269 | def asdfsdfsdsdsdfsdf24():
|
||||
270 | """Summary.
|
||||
| _____^
|
||||
271 | |
|
||||
272 | | Description.
|
||||
273 | |
|
||||
274 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
267 267 | @expect('D208: Docstring is over-indented')
|
||||
268 268 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
269 269 | def asdfsdfsdsdsdfsdf24():
|
||||
270 |- """Summary.
|
||||
270 |+ """
|
||||
271 |+ Summary.
|
||||
271 272 |
|
||||
272 273 | Description.
|
||||
273 274 |
|
||||
|
||||
D.py:281:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
279 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
280 | def asdfljdf24():
|
||||
281 | """Summary.
|
||||
| _____^
|
||||
282 | |
|
||||
283 | | Description."""
|
||||
| |___________________^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
278 278 | 'line')
|
||||
279 279 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
280 280 | def asdfljdf24():
|
||||
281 |- """Summary.
|
||||
281 |+ """
|
||||
282 |+ Summary.
|
||||
282 283 |
|
||||
283 284 | Description."""
|
||||
284 285 |
|
||||
|
||||
D.py:299:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
297 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
298 | def multiline():
|
||||
299 | """ Whitespace at the beginning.
|
||||
| _____^
|
||||
300 | |
|
||||
301 | | This is the end.
|
||||
302 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
296 296 | @expect('D210: No whitespaces allowed surrounding docstring text')
|
||||
297 297 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
298 298 | def multiline():
|
||||
299 |- """ Whitespace at the beginning.
|
||||
299 |+ """
|
||||
300 |+ Whitespace at the beginning.
|
||||
300 301 |
|
||||
301 302 | This is the end.
|
||||
302 303 | """
|
||||
|
||||
D.py:343:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
341 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
342 | def exceptions_of_D301():
|
||||
343 | """Exclude some backslashes from D301.
|
||||
| _____^
|
||||
344 | |
|
||||
345 | | In particular, line continuations \
|
||||
346 | | and unicode literals \u0394 and \N{GREEK CAPITAL LETTER DELTA}.
|
||||
347 | | They are considered to be intentionally unescaped.
|
||||
348 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
340 340 |
|
||||
341 341 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
342 342 | def exceptions_of_D301():
|
||||
343 |- """Exclude some backslashes from D301.
|
||||
343 |+ """
|
||||
344 |+ Exclude some backslashes from D301.
|
||||
344 345 |
|
||||
345 346 | In particular, line continuations \
|
||||
346 347 | and unicode literals \u0394 and \N{GREEK CAPITAL LETTER DELTA}.
|
||||
|
||||
D.py:383:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
381 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
382 | def new_209():
|
||||
383 | """First line.
|
||||
| _____^
|
||||
384 | |
|
||||
385 | | More lines.
|
||||
386 | | """
|
||||
| |_______^ D213
|
||||
387 | pass
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
380 380 |
|
||||
381 381 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
382 382 | def new_209():
|
||||
383 |- """First line.
|
||||
383 |+ """
|
||||
384 |+ First line.
|
||||
384 385 |
|
||||
385 386 | More lines.
|
||||
386 387 | """
|
||||
|
||||
D.py:392:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
390 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
391 | def old_209():
|
||||
392 | """One liner.
|
||||
| _____^
|
||||
393 | |
|
||||
394 | | Multi-line comments. OK to have extra blank line
|
||||
395 | |
|
||||
396 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
389 389 |
|
||||
390 390 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
391 391 | def old_209():
|
||||
392 |- """One liner.
|
||||
392 |+ """
|
||||
393 |+ One liner.
|
||||
393 394 |
|
||||
394 395 | Multi-line comments. OK to have extra blank line
|
||||
395 396 |
|
||||
|
||||
D.py:438:37: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
436 | @expect("D207: Docstring is under-indented")
|
||||
437 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
438 | def docstring_start_in_same_line(): """First Line.
|
||||
| _____________________________________^
|
||||
439 | |
|
||||
440 | | Second Line
|
||||
441 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
435 435 |
|
||||
436 436 | @expect("D207: Docstring is under-indented")
|
||||
437 437 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
438 |-def docstring_start_in_same_line(): """First Line.
|
||||
438 |+def docstring_start_in_same_line(): """
|
||||
439 |+ First Line.
|
||||
439 440 |
|
||||
440 441 | Second Line
|
||||
441 442 | """
|
||||
|
||||
D.py:450:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
448 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
449 | def a_following_valid_function(x=None):
|
||||
450 | """Check for a bug where the previous function caused an assertion.
|
||||
| _____^
|
||||
451 | |
|
||||
452 | | The assertion was caused in the next function, so this one is necessary.
|
||||
453 | |
|
||||
454 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
447 447 |
|
||||
448 448 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
449 449 | def a_following_valid_function(x=None):
|
||||
450 |- """Check for a bug where the previous function caused an assertion.
|
||||
450 |+ """
|
||||
451 |+ Check for a bug where the previous function caused an assertion.
|
||||
451 452 |
|
||||
452 453 | The assertion was caused in the next function, so this one is necessary.
|
||||
453 454 |
|
||||
|
||||
D.py:526:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
524 | # parameters as functions for Google / Numpy conventions.
|
||||
525 | class Blah: # noqa: D203,D213
|
||||
526 | """A Blah.
|
||||
| _____^
|
||||
527 | |
|
||||
528 | | Parameters
|
||||
529 | | ----------
|
||||
530 | | x : int
|
||||
531 | |
|
||||
532 | | """
|
||||
| |_______^ D213
|
||||
533 |
|
||||
534 | def __init__(self, x):
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
523 523 | # This is reproducing a bug where AttributeError is raised when parsing class
|
||||
524 524 | # parameters as functions for Google / Numpy conventions.
|
||||
525 525 | class Blah: # noqa: D203,D213
|
||||
526 |- """A Blah.
|
||||
526 |+ """
|
||||
527 |+ A Blah.
|
||||
527 528 |
|
||||
528 529 | Parameters
|
||||
529 530 | ----------
|
||||
|
||||
D.py:546:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
544 | def multiline_leading_space():
|
||||
545 |
|
||||
546 | """Leading space.
|
||||
| _____^
|
||||
547 | |
|
||||
548 | | More content.
|
||||
549 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
543 543 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
544 544 | def multiline_leading_space():
|
||||
545 545 |
|
||||
546 |- """Leading space.
|
||||
546 |+ """
|
||||
547 |+ Leading space.
|
||||
547 548 |
|
||||
548 549 | More content.
|
||||
549 550 | """
|
||||
|
||||
D.py:555:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
553 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
554 | def multiline_trailing_space():
|
||||
555 | """Leading space.
|
||||
| _____^
|
||||
556 | |
|
||||
557 | | More content.
|
||||
558 | | """
|
||||
| |_______^ D213
|
||||
559 |
|
||||
560 | pass
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
552 552 | @expect('D202: No blank lines allowed after function docstring (found 1)')
|
||||
553 553 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
554 554 | def multiline_trailing_space():
|
||||
555 |- """Leading space.
|
||||
555 |+ """
|
||||
556 |+ Leading space.
|
||||
556 557 |
|
||||
557 558 | More content.
|
||||
558 559 | """
|
||||
|
||||
D.py:568:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
566 | def multiline_trailing_and_leading_space():
|
||||
567 |
|
||||
568 | """Trailing and leading space.
|
||||
| _____^
|
||||
569 | |
|
||||
570 | | More content.
|
||||
571 | | """
|
||||
| |_______^ D213
|
||||
572 |
|
||||
573 | pass
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
565 565 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
566 566 | def multiline_trailing_and_leading_space():
|
||||
567 567 |
|
||||
568 |- """Trailing and leading space.
|
||||
568 |+ """
|
||||
569 |+ Trailing and leading space.
|
||||
569 570 |
|
||||
570 571 | More content.
|
||||
571 572 | """
|
||||
|
||||
D.py:588:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
586 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
587 | def asdfljdjgf24():
|
||||
588 | """Summary.
|
||||
| _____^
|
||||
589 | |
|
||||
590 | | Description. """
|
||||
| |_____________________^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
585 585 | 'line')
|
||||
586 586 | @expect('D213: Multi-line docstring summary should start at the second line')
|
||||
587 587 | def asdfljdjgf24():
|
||||
588 |- """Summary.
|
||||
588 |+ """
|
||||
589 |+ Summary.
|
||||
589 590 |
|
||||
590 591 | Description. """
|
||||
591 592 |
|
||||
|
||||
D.py:606:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
604 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
605 | def one_liner():
|
||||
606 | r"""Wrong.
|
||||
| _____^
|
||||
607 | |
|
||||
608 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
603 603 | '(found 3)')
|
||||
604 604 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
605 605 | def one_liner():
|
||||
606 |- r"""Wrong.
|
||||
606 |+ r"""
|
||||
607 |+ Wrong.
|
||||
607 608 |
|
||||
608 609 | """
|
||||
609 610 |
|
||||
|
||||
D.py:615:5: D213 [*] Multi-line docstring summary should start at the second line
|
||||
|
|
||||
613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 | def one_liner():
|
||||
615 | """Wrong."
|
||||
| _____^
|
||||
616 | |
|
||||
617 | | """
|
||||
| |_______^ D213
|
||||
|
|
||||
= help: Insert line break and indentation after opening quotes
|
||||
|
||||
ℹ Fix
|
||||
612 612 | '(found 3)')
|
||||
613 613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 614 | def one_liner():
|
||||
615 |- """Wrong."
|
||||
615 |+ """
|
||||
616 |+ Wrong."
|
||||
616 617 |
|
||||
617 618 | """
|
||||
618 619 |
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D214_module.py:1:1: D214 [*] Section is over-indented ("Returns")
|
||||
|
|
||||
1 | / """A module docstring with D214 violations
|
||||
2 | |
|
||||
3 | | Returns
|
||||
4 | | -----
|
||||
5 | | valid returns
|
||||
6 | |
|
||||
7 | | Args
|
||||
8 | | -----
|
||||
9 | | valid args
|
||||
10 | | """
|
||||
| |___^ D214
|
||||
11 |
|
||||
12 | import os
|
||||
|
|
||||
= help: Remove over-indentation from "Returns"
|
||||
|
||||
ℹ Fix
|
||||
1 1 | """A module docstring with D214 violations
|
||||
2 2 |
|
||||
3 |- Returns
|
||||
3 |+Returns
|
||||
4 4 | -----
|
||||
5 5 | valid returns
|
||||
6 6 |
|
||||
|
||||
D214_module.py:1:1: D214 [*] Section is over-indented ("Args")
|
||||
|
|
||||
1 | / """A module docstring with D214 violations
|
||||
2 | |
|
||||
3 | | Returns
|
||||
4 | | -----
|
||||
5 | | valid returns
|
||||
6 | |
|
||||
7 | | Args
|
||||
8 | | -----
|
||||
9 | | valid args
|
||||
10 | | """
|
||||
| |___^ D214
|
||||
11 |
|
||||
12 | import os
|
||||
|
|
||||
= help: Remove over-indentation from "Args"
|
||||
|
||||
ℹ Fix
|
||||
4 4 | -----
|
||||
5 5 | valid returns
|
||||
6 6 |
|
||||
7 |- Args
|
||||
7 |+Args
|
||||
8 8 | -----
|
||||
9 9 | valid args
|
||||
10 10 | """
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:144:5: D214 [*] Section is over-indented ("Returns")
|
||||
|
|
||||
142 | @expect("D214: Section is over-indented ('Returns')")
|
||||
143 | def section_overindented(): # noqa: D416
|
||||
144 | """Toggle the gizmo.
|
||||
| _____^
|
||||
145 | |
|
||||
146 | | Returns
|
||||
147 | | -------
|
||||
148 | | A value of some sort.
|
||||
149 | |
|
||||
150 | | """
|
||||
| |_______^ D214
|
||||
|
|
||||
= help: Remove over-indentation from "Returns"
|
||||
|
||||
ℹ Fix
|
||||
143 143 | def section_overindented(): # noqa: D416
|
||||
144 144 | """Toggle the gizmo.
|
||||
145 145 |
|
||||
146 |- Returns
|
||||
146 |+ Returns
|
||||
147 147 | -------
|
||||
148 148 | A value of some sort.
|
||||
149 149 |
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:156:5: D215 [*] Section underline is over-indented ("Returns")
|
||||
|
|
||||
154 | @expect("D215: Section underline is over-indented (in section 'Returns')")
|
||||
155 | def section_underline_overindented(): # noqa: D416
|
||||
156 | """Toggle the gizmo.
|
||||
| _____^
|
||||
157 | |
|
||||
158 | | Returns
|
||||
159 | | -------
|
||||
160 | | A value of some sort.
|
||||
161 | |
|
||||
162 | | """
|
||||
| |_______^ D215
|
||||
|
|
||||
= help: Remove over-indentation from "Returns" underline
|
||||
|
||||
ℹ Fix
|
||||
156 156 | """Toggle the gizmo.
|
||||
157 157 |
|
||||
158 158 | Returns
|
||||
159 |- -------
|
||||
159 |+ ------
|
||||
160 160 | A value of some sort.
|
||||
161 161 |
|
||||
162 162 | """
|
||||
|
||||
sections.py:170:5: D215 [*] Section underline is over-indented ("Returns")
|
||||
|
|
||||
168 | @expect("D414: Section has no content ('Returns')")
|
||||
169 | def section_underline_overindented_and_contentless(): # noqa: D416
|
||||
170 | """Toggle the gizmo.
|
||||
| _____^
|
||||
171 | |
|
||||
172 | | Returns
|
||||
173 | | -------
|
||||
174 | | """
|
||||
| |_______^ D215
|
||||
|
|
||||
= help: Remove over-indentation from "Returns" underline
|
||||
|
||||
ℹ Fix
|
||||
170 170 | """Toggle the gizmo.
|
||||
171 171 |
|
||||
172 172 | Returns
|
||||
173 |- -------
|
||||
173 |+ ------
|
||||
174 174 | """
|
||||
175 175 |
|
||||
176 176 |
|
||||
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:307:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
305 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
|
||||
306 | def triple_single_quotes_raw():
|
||||
307 | r'''Summary.'''
|
||||
| ^^^^^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
D.py:312:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
310 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
|
||||
311 | def triple_single_quotes_raw_uppercase():
|
||||
312 | R'''Summary.'''
|
||||
| ^^^^^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
D.py:317:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
315 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
|
||||
316 | def single_quotes_raw():
|
||||
317 | r'Summary.'
|
||||
| ^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
D.py:322:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
320 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
|
||||
321 | def single_quotes_raw_uppercase():
|
||||
322 | R'Summary.'
|
||||
| ^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
D.py:328:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
326 | @expect('D301: Use r""" if any backslashes in a docstring')
|
||||
327 | def single_quotes_raw_uppercase_backslash():
|
||||
328 | R'Sum\mary.'
|
||||
| ^^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
D.py:645:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
644 | def single_line_docstring_with_an_escaped_backslash():
|
||||
645 | "\
|
||||
| _____^
|
||||
646 | | "
|
||||
| |_____^ D300
|
||||
647 |
|
||||
648 | class StatementOnSameLineAsDocstring:
|
||||
|
|
||||
|
||||
D.py:649:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
648 | class StatementOnSameLineAsDocstring:
|
||||
649 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D300
|
||||
650 | def sort_services(self):
|
||||
651 | pass
|
||||
|
|
||||
|
||||
D.py:654:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
653 | class StatementOnSameLineAsDocstring:
|
||||
654 | "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
D.py:658:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
657 | class CommentAfterDocstring:
|
||||
658 | "After this docstring there's a comment." # priorities=1
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D300
|
||||
659 | def sort_services(self):
|
||||
660 | pass
|
||||
|
|
||||
|
||||
D.py:664:5: D300 Use triple double quotes `"""`
|
||||
|
|
||||
663 | def newline_after_closing_quote(self):
|
||||
664 | "We enforce a newline after the closing quote for a multi-line docstring \
|
||||
| _____^
|
||||
665 | | but continuations shouldn't be considered multi-line"
|
||||
| |_________________________________________________________^ D300
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:328:5: D301 Use `r"""` if any backslashes in a docstring
|
||||
|
|
||||
326 | @expect('D301: Use r""" if any backslashes in a docstring')
|
||||
327 | def single_quotes_raw_uppercase_backslash():
|
||||
328 | R'Sum\mary.'
|
||||
| ^^^^^^^^^^^^ D301
|
||||
|
|
||||
|
||||
D.py:333:5: D301 Use `r"""` if any backslashes in a docstring
|
||||
|
|
||||
331 | @expect('D301: Use r""" if any backslashes in a docstring')
|
||||
332 | def double_quotes_backslash():
|
||||
333 | """Sum\\mary."""
|
||||
| ^^^^^^^^^^^^^^^^ D301
|
||||
|
|
||||
|
||||
D.py:338:5: D301 Use `r"""` if any backslashes in a docstring
|
||||
|
|
||||
336 | @expect('D301: Use r""" if any backslashes in a docstring')
|
||||
337 | def double_quotes_backslash_uppercase():
|
||||
338 | R"""Sum\\mary."""
|
||||
| ^^^^^^^^^^^^^^^^^ D301
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D301.py:2:5: D301 Use `r"""` if any backslashes in a docstring
|
||||
|
|
||||
1 | def double_quotes_backslash():
|
||||
2 | """Sum\\mary."""
|
||||
| ^^^^^^^^^^^^^^^^ D301
|
||||
|
|
||||
|
||||
D301.py:10:5: D301 Use `r"""` if any backslashes in a docstring
|
||||
|
|
||||
9 | def double_quotes_backslash_uppercase():
|
||||
10 | R"""Sum\\mary."""
|
||||
| ^^^^^^^^^^^^^^^^^ D301
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:355:5: D400 [*] First line should end with a period
|
||||
|
|
||||
353 | "or exclamation point (not 'y')")
|
||||
354 | def lwnlkjl():
|
||||
355 | """Summary"""
|
||||
| ^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
352 352 | @expect("D415: First line should end with a period, question mark, "
|
||||
353 353 | "or exclamation point (not 'y')")
|
||||
354 354 | def lwnlkjl():
|
||||
355 |- """Summary"""
|
||||
355 |+ """Summary."""
|
||||
356 356 |
|
||||
357 357 |
|
||||
358 358 | @expect("D401: First line should be in imperative mood "
|
||||
|
||||
D.py:406:25: D400 [*] First line should end with a period
|
||||
|
|
||||
404 | @expect("D415: First line should end with a period, question mark,"
|
||||
405 | " or exclamation point (not 'r')")
|
||||
406 | def oneliner_withdoc(): """One liner"""
|
||||
| ^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
403 403 | @expect("D400: First line should end with a period (not 'r')")
|
||||
404 404 | @expect("D415: First line should end with a period, question mark,"
|
||||
405 405 | " or exclamation point (not 'r')")
|
||||
406 |-def oneliner_withdoc(): """One liner"""
|
||||
406 |+def oneliner_withdoc(): """One liner."""
|
||||
407 407 |
|
||||
408 408 |
|
||||
409 409 | def ignored_decorator(func): # noqa: D400,D401,D415
|
||||
|
||||
D.py:410:5: D400 [*] First line should end with a period
|
||||
|
|
||||
409 | def ignored_decorator(func): # noqa: D400,D401,D415
|
||||
410 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D400
|
||||
411 | func()
|
||||
412 | pass
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
407 407 |
|
||||
408 408 |
|
||||
409 409 | def ignored_decorator(func): # noqa: D400,D401,D415
|
||||
410 |- """Runs something"""
|
||||
410 |+ """Runs something."""
|
||||
411 411 | func()
|
||||
412 412 | pass
|
||||
413 413 |
|
||||
|
||||
D.py:416:5: D400 [*] First line should end with a period
|
||||
|
|
||||
415 | def decorator_for_test(func): # noqa: D400,D401,D415
|
||||
416 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D400
|
||||
417 | func()
|
||||
418 | pass
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
413 413 |
|
||||
414 414 |
|
||||
415 415 | def decorator_for_test(func): # noqa: D400,D401,D415
|
||||
416 |- """Runs something"""
|
||||
416 |+ """Runs something."""
|
||||
417 417 | func()
|
||||
418 418 | pass
|
||||
419 419 |
|
||||
|
||||
D.py:422:35: D400 [*] First line should end with a period
|
||||
|
|
||||
421 | @ignored_decorator
|
||||
422 | def oneliner_ignored_decorator(): """One liner"""
|
||||
| ^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
419 419 |
|
||||
420 420 |
|
||||
421 421 | @ignored_decorator
|
||||
422 |-def oneliner_ignored_decorator(): """One liner"""
|
||||
422 |+def oneliner_ignored_decorator(): """One liner."""
|
||||
423 423 |
|
||||
424 424 |
|
||||
425 425 | @decorator_for_test
|
||||
|
||||
D.py:429:49: D400 [*] First line should end with a period
|
||||
|
|
||||
427 | @expect("D415: First line should end with a period, question mark,"
|
||||
428 | " or exclamation point (not 'r')")
|
||||
429 | def oneliner_with_decorator_expecting_errors(): """One liner"""
|
||||
| ^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
426 426 | @expect("D400: First line should end with a period (not 'r')")
|
||||
427 427 | @expect("D415: First line should end with a period, question mark,"
|
||||
428 428 | " or exclamation point (not 'r')")
|
||||
429 |-def oneliner_with_decorator_expecting_errors(): """One liner"""
|
||||
429 |+def oneliner_with_decorator_expecting_errors(): """One liner."""
|
||||
430 430 |
|
||||
431 431 |
|
||||
432 432 | @decorator_for_test
|
||||
|
||||
D.py:470:5: D400 [*] First line should end with a period
|
||||
|
|
||||
468 | "or exclamation point (not 'g')")
|
||||
469 | def docstring_bad():
|
||||
470 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D400
|
||||
471 | pass
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
467 467 | @expect("D415: First line should end with a period, question mark, "
|
||||
468 468 | "or exclamation point (not 'g')")
|
||||
469 469 | def docstring_bad():
|
||||
470 |- """Runs something"""
|
||||
470 |+ """Runs something."""
|
||||
471 471 | pass
|
||||
472 472 |
|
||||
473 473 |
|
||||
|
||||
D.py:475:5: D400 [*] First line should end with a period
|
||||
|
|
||||
474 | def docstring_bad_ignore_all(): # noqa
|
||||
475 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D400
|
||||
476 | pass
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
472 472 |
|
||||
473 473 |
|
||||
474 474 | def docstring_bad_ignore_all(): # noqa
|
||||
475 |- """Runs something"""
|
||||
475 |+ """Runs something."""
|
||||
476 476 | pass
|
||||
477 477 |
|
||||
478 478 |
|
||||
|
||||
D.py:480:5: D400 [*] First line should end with a period
|
||||
|
|
||||
479 | def docstring_bad_ignore_one(): # noqa: D400,D401,D415
|
||||
480 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D400
|
||||
481 | pass
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
477 477 |
|
||||
478 478 |
|
||||
479 479 | def docstring_bad_ignore_one(): # noqa: D400,D401,D415
|
||||
480 |- """Runs something"""
|
||||
480 |+ """Runs something."""
|
||||
481 481 | pass
|
||||
482 482 |
|
||||
483 483 |
|
||||
|
||||
D.py:487:5: D400 [*] First line should end with a period
|
||||
|
|
||||
485 | "(perhaps 'Run', not 'Runs')")
|
||||
486 | def docstring_ignore_some_violations_but_catch_D401(): # noqa: E501,D400,D415
|
||||
487 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D400
|
||||
488 | pass
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
484 484 | @expect("D401: First line should be in imperative mood "
|
||||
485 485 | "(perhaps 'Run', not 'Runs')")
|
||||
486 486 | def docstring_ignore_some_violations_but_catch_D401(): # noqa: E501,D400,D415
|
||||
487 |- """Runs something"""
|
||||
487 |+ """Runs something."""
|
||||
488 488 | pass
|
||||
489 489 |
|
||||
490 490 |
|
||||
|
||||
D.py:514:5: D400 [*] First line should end with a period
|
||||
|
|
||||
513 | def valid_google_string(): # noqa: D400
|
||||
514 | """Test a valid something!"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
511 511 |
|
||||
512 512 |
|
||||
513 513 | def valid_google_string(): # noqa: D400
|
||||
514 |- """Test a valid something!"""
|
||||
514 |+ """Test a valid something!."""
|
||||
515 515 |
|
||||
516 516 |
|
||||
517 517 | @expect("D415: First line should end with a period, question mark, "
|
||||
|
||||
D.py:520:5: D400 [*] First line should end with a period
|
||||
|
|
||||
518 | "or exclamation point (not 'g')")
|
||||
519 | def bad_google_string(): # noqa: D400
|
||||
520 | """Test a valid something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
517 517 | @expect("D415: First line should end with a period, question mark, "
|
||||
518 518 | "or exclamation point (not 'g')")
|
||||
519 519 | def bad_google_string(): # noqa: D400
|
||||
520 |- """Test a valid something"""
|
||||
520 |+ """Test a valid something."""
|
||||
521 521 |
|
||||
522 522 |
|
||||
523 523 | # This is reproducing a bug where AttributeError is raised when parsing class
|
||||
|
||||
D.py:581:5: D400 [*] First line should end with a period
|
||||
|
|
||||
579 | "or exclamation point (not '\"')")
|
||||
580 | def endswith_quote():
|
||||
581 | """Whitespace at the end, but also a quote" """
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
578 578 | @expect("D415: First line should end with a period, question mark, "
|
||||
579 579 | "or exclamation point (not '\"')")
|
||||
580 580 | def endswith_quote():
|
||||
581 |- """Whitespace at the end, but also a quote" """
|
||||
581 |+ """Whitespace at the end, but also a quote". """
|
||||
582 582 |
|
||||
583 583 |
|
||||
584 584 | @expect('D209: Multi-line docstring closing quotes should be on a separate '
|
||||
|
||||
D.py:615:5: D400 [*] First line should end with a period
|
||||
|
|
||||
613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 | def one_liner():
|
||||
615 | """Wrong."
|
||||
| _____^
|
||||
616 | |
|
||||
617 | | """
|
||||
| |_______^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
612 612 | '(found 3)')
|
||||
613 613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 614 | def one_liner():
|
||||
615 |- """Wrong."
|
||||
615 |+ """Wrong.".
|
||||
616 616 |
|
||||
617 617 | """
|
||||
618 618 |
|
||||
|
||||
D.py:639:17: D400 [*] First line should end with a period
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
636 636 | """ This is a docstring that starts with a space.""" # noqa: D210
|
||||
637 637 |
|
||||
638 638 |
|
||||
639 |-class SameLine: """This is a docstring on the same line"""
|
||||
639 |+class SameLine: """This is a docstring on the same line."""
|
||||
640 640 |
|
||||
641 641 | def same_line(): """This is a docstring on the same line"""
|
||||
642 642 |
|
||||
|
||||
D.py:641:18: D400 [*] First line should end with a period
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
638 638 |
|
||||
639 639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 640 |
|
||||
641 |-def same_line(): """This is a docstring on the same line"""
|
||||
641 |+def same_line(): """This is a docstring on the same line."""
|
||||
642 642 |
|
||||
643 643 |
|
||||
644 644 | def single_line_docstring_with_an_escaped_backslash():
|
||||
|
||||
D.py:664:5: D400 [*] First line should end with a period
|
||||
|
|
||||
663 | def newline_after_closing_quote(self):
|
||||
664 | "We enforce a newline after the closing quote for a multi-line docstring \
|
||||
| _____^
|
||||
665 | | but continuations shouldn't be considered multi-line"
|
||||
| |_________________________________________________________^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
662 662 |
|
||||
663 663 | def newline_after_closing_quote(self):
|
||||
664 664 | "We enforce a newline after the closing quote for a multi-line docstring \
|
||||
665 |- but continuations shouldn't be considered multi-line"
|
||||
665 |+ but continuations shouldn't be considered multi-line."
|
||||
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D400.py:2:5: D400 [*] First line should end with a period
|
||||
|
|
||||
1 | def f():
|
||||
2 | "Here's a line without a period"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
3 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
1 1 | def f():
|
||||
2 |- "Here's a line without a period"
|
||||
2 |+ "Here's a line without a period."
|
||||
3 3 | ...
|
||||
4 4 |
|
||||
5 5 |
|
||||
|
||||
D400.py:7:5: D400 [*] First line should end with a period
|
||||
|
|
||||
6 | def f():
|
||||
7 | """Here's a line without a period"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
8 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
4 4 |
|
||||
5 5 |
|
||||
6 6 | def f():
|
||||
7 |- """Here's a line without a period"""
|
||||
7 |+ """Here's a line without a period."""
|
||||
8 8 | ...
|
||||
9 9 |
|
||||
10 10 |
|
||||
|
||||
D400.py:12:5: D400 [*] First line should end with a period
|
||||
|
|
||||
11 | def f():
|
||||
12 | """
|
||||
| _____^
|
||||
13 | | Here's a line without a period,
|
||||
14 | | but here's the next line
|
||||
15 | | """
|
||||
| |_______^ D400
|
||||
16 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
11 11 | def f():
|
||||
12 12 | """
|
||||
13 13 | Here's a line without a period,
|
||||
14 |- but here's the next line
|
||||
14 |+ but here's the next line.
|
||||
15 15 | """
|
||||
16 16 | ...
|
||||
17 17 |
|
||||
|
||||
D400.py:20:5: D400 [*] First line should end with a period
|
||||
|
|
||||
19 | def f():
|
||||
20 | """Here's a line without a period"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
21 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
17 17 |
|
||||
18 18 |
|
||||
19 19 | def f():
|
||||
20 |- """Here's a line without a period"""
|
||||
20 |+ """Here's a line without a period."""
|
||||
21 21 | ...
|
||||
22 22 |
|
||||
23 23 |
|
||||
|
||||
D400.py:25:5: D400 [*] First line should end with a period
|
||||
|
|
||||
24 | def f():
|
||||
25 | """
|
||||
| _____^
|
||||
26 | | Here's a line without a period,
|
||||
27 | | but here's the next line"""
|
||||
| |_______________________________^ D400
|
||||
28 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
24 24 | def f():
|
||||
25 25 | """
|
||||
26 26 | Here's a line without a period,
|
||||
27 |- but here's the next line"""
|
||||
27 |+ but here's the next line."""
|
||||
28 28 | ...
|
||||
29 29 |
|
||||
30 30 |
|
||||
|
||||
D400.py:32:5: D400 [*] First line should end with a period
|
||||
|
|
||||
31 | def f():
|
||||
32 | """
|
||||
| _____^
|
||||
33 | | Here's a line without a period,
|
||||
34 | | but here's the next line with trailing space """
|
||||
| |____________________________________________________^ D400
|
||||
35 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
31 31 | def f():
|
||||
32 32 | """
|
||||
33 33 | Here's a line without a period,
|
||||
34 |- but here's the next line with trailing space """
|
||||
34 |+ but here's the next line with trailing space. """
|
||||
35 35 | ...
|
||||
36 36 |
|
||||
37 37 |
|
||||
|
||||
D400.py:39:5: D400 [*] First line should end with a period
|
||||
|
|
||||
38 | def f():
|
||||
39 | r"Here's a line without a period"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
40 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
36 36 |
|
||||
37 37 |
|
||||
38 38 | def f():
|
||||
39 |- r"Here's a line without a period"
|
||||
39 |+ r"Here's a line without a period."
|
||||
40 40 | ...
|
||||
41 41 |
|
||||
42 42 |
|
||||
|
||||
D400.py:44:5: D400 [*] First line should end with a period
|
||||
|
|
||||
43 | def f():
|
||||
44 | r"""Here's a line without a period"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
45 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
41 41 |
|
||||
42 42 |
|
||||
43 43 | def f():
|
||||
44 |- r"""Here's a line without a period"""
|
||||
44 |+ r"""Here's a line without a period."""
|
||||
45 45 | ...
|
||||
46 46 |
|
||||
47 47 |
|
||||
|
||||
D400.py:49:5: D400 [*] First line should end with a period
|
||||
|
|
||||
48 | def f():
|
||||
49 | r"""
|
||||
| _____^
|
||||
50 | | Here's a line without a period,
|
||||
51 | | but here's the next line
|
||||
52 | | """
|
||||
| |_______^ D400
|
||||
53 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
48 48 | def f():
|
||||
49 49 | r"""
|
||||
50 50 | Here's a line without a period,
|
||||
51 |- but here's the next line
|
||||
51 |+ but here's the next line.
|
||||
52 52 | """
|
||||
53 53 | ...
|
||||
54 54 |
|
||||
|
||||
D400.py:57:5: D400 [*] First line should end with a period
|
||||
|
|
||||
56 | def f():
|
||||
57 | r"""Here's a line without a period"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D400
|
||||
58 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
54 54 |
|
||||
55 55 |
|
||||
56 56 | def f():
|
||||
57 |- r"""Here's a line without a period"""
|
||||
57 |+ r"""Here's a line without a period."""
|
||||
58 58 | ...
|
||||
59 59 |
|
||||
60 60 |
|
||||
|
||||
D400.py:62:5: D400 [*] First line should end with a period
|
||||
|
|
||||
61 | def f():
|
||||
62 | r"""
|
||||
| _____^
|
||||
63 | | Here's a line without a period,
|
||||
64 | | but here's the next line"""
|
||||
| |_______________________________^ D400
|
||||
65 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
61 61 | def f():
|
||||
62 62 | r"""
|
||||
63 63 | Here's a line without a period,
|
||||
64 |- but here's the next line"""
|
||||
64 |+ but here's the next line."""
|
||||
65 65 | ...
|
||||
66 66 |
|
||||
67 67 |
|
||||
|
||||
D400.py:69:5: D400 [*] First line should end with a period
|
||||
|
|
||||
68 | def f():
|
||||
69 | r"""
|
||||
| _____^
|
||||
70 | | Here's a line without a period,
|
||||
71 | | but here's the next line with trailing space """
|
||||
| |____________________________________________________^ D400
|
||||
72 | ...
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
68 68 | def f():
|
||||
69 69 | r"""
|
||||
70 70 | Here's a line without a period,
|
||||
71 |- but here's the next line with trailing space """
|
||||
71 |+ but here's the next line with trailing space. """
|
||||
72 72 | ...
|
||||
73 73 |
|
||||
74 74 |
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D401.py:10:5: D401 First line of docstring should be in imperative mood: "Returns foo."
|
||||
|
|
||||
9 | def bad_liouiwnlkjl():
|
||||
10 | """Returns foo."""
|
||||
| ^^^^^^^^^^^^^^^^^^ D401
|
||||
|
|
||||
|
||||
D401.py:14:5: D401 First line of docstring should be in imperative mood: "Constructor for a foo."
|
||||
|
|
||||
13 | def bad_sdgfsdg23245():
|
||||
14 | """Constructor for a foo."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D401
|
||||
|
|
||||
|
||||
D401.py:18:5: D401 First line of docstring should be in imperative mood: "Constructor for a boa."
|
||||
|
|
||||
17 | def bad_sdgfsdg23245777():
|
||||
18 | """
|
||||
| _____^
|
||||
19 | |
|
||||
20 | | Constructor for a boa.
|
||||
21 | |
|
||||
22 | | """
|
||||
| |_______^ D401
|
||||
|
|
||||
|
||||
D401.py:26:5: D401 First line of docstring should be in imperative mood: "Runs something"
|
||||
|
|
||||
25 | def bad_run_something():
|
||||
26 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D401
|
||||
27 |
|
||||
28 | def bad_nested():
|
||||
|
|
||||
|
||||
D401.py:29:9: D401 First line of docstring should be in imperative mood: "Runs other things, nested"
|
||||
|
|
||||
28 | def bad_nested():
|
||||
29 | """Runs other things, nested"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D401
|
||||
30 |
|
||||
31 | bad_nested()
|
||||
|
|
||||
|
||||
D401.py:35:5: D401 First line of docstring should be in imperative mood: "Writes a logical line that"
|
||||
|
|
||||
34 | def multi_line():
|
||||
35 | """Writes a logical line that
|
||||
| _____^
|
||||
36 | | extends to two physical lines.
|
||||
37 | | """
|
||||
| |_______^ D401
|
||||
|
|
||||
|
||||
D401.py:74:9: D401 First line of docstring should be in imperative mood: "This method docstring should be written in imperative mood."
|
||||
|
|
||||
73 | def bad_method(self):
|
||||
74 | """This method docstring should be written in imperative mood."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D401
|
||||
75 |
|
||||
76 | @property
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:378:5: D402 First line should not be the function's signature
|
||||
|
|
||||
376 | @expect('D402: First line should not be the function\'s "signature"')
|
||||
377 | def foobar():
|
||||
378 | """Signature: foobar()."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ D402
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D403.py:2:5: D403 [*] First word of the first line should be capitalized: `this` -> `This`
|
||||
|
|
||||
1 | def bad_function():
|
||||
2 | """this docstring is not capitalized"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D403
|
||||
3 |
|
||||
4 | def good_function():
|
||||
|
|
||||
= help: Capitalize `this` to `This`
|
||||
|
||||
ℹ Fix
|
||||
1 1 | def bad_function():
|
||||
2 |- """this docstring is not capitalized"""
|
||||
2 |+ """This docstring is not capitalized"""
|
||||
3 3 |
|
||||
4 4 | def good_function():
|
||||
5 5 | """This docstring is capitalized."""
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:631:5: D404 First word of the docstring should not be "This"
|
||||
|
|
||||
629 | @expect('D404: First word of the docstring should not be "This"')
|
||||
630 | def starts_with_this():
|
||||
631 | """This is a docstring."""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
|
|
||||
|
||||
D.py:636:5: D404 First word of the docstring should not be "This"
|
||||
|
|
||||
634 | @expect('D404: First word of the docstring should not be "This"')
|
||||
635 | def starts_with_space_then_this():
|
||||
636 | """ This is a docstring that starts with a space.""" # noqa: D210
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
|
|
||||
|
||||
D.py:639:17: D404 First word of the docstring should not be "This"
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
|
||||
|
||||
D.py:641:18: D404 First word of the docstring should not be "This"
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D404
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:17:5: D405 [*] Section name should be properly capitalized ("returns")
|
||||
|
|
||||
15 | "('Returns', not 'returns')")
|
||||
16 | def not_capitalized(): # noqa: D416
|
||||
17 | """Toggle the gizmo.
|
||||
| _____^
|
||||
18 | |
|
||||
19 | | returns
|
||||
20 | | -------
|
||||
21 | | A value of some sort.
|
||||
22 | |
|
||||
23 | | """
|
||||
| |_______^ D405
|
||||
|
|
||||
= help: Capitalize "returns"
|
||||
|
||||
ℹ Fix
|
||||
16 16 | def not_capitalized(): # noqa: D416
|
||||
17 17 | """Toggle the gizmo.
|
||||
18 18 |
|
||||
19 |- returns
|
||||
19 |+ Returns
|
||||
20 20 | -------
|
||||
21 21 | A value of some sort.
|
||||
22 22 |
|
||||
|
||||
sections.py:216:5: D405 [*] Section name should be properly capitalized ("Short summary")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D405
|
||||
|
|
||||
= help: Capitalize "Short summary"
|
||||
|
||||
ℹ Fix
|
||||
215 215 | def multiple_sections(): # noqa: D416
|
||||
216 216 | """Toggle the gizmo.
|
||||
217 217 |
|
||||
218 |- Short summary
|
||||
218 |+ Short Summary
|
||||
219 219 | -------------
|
||||
220 220 |
|
||||
221 221 | This is the function's description, which will also specify what it
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:30:5: D406 [*] Section name should end with a newline ("Returns")
|
||||
|
|
||||
28 | "('Returns', not 'Returns:')")
|
||||
29 | def superfluous_suffix(): # noqa: D416
|
||||
30 | """Toggle the gizmo.
|
||||
| _____^
|
||||
31 | |
|
||||
32 | | Returns:
|
||||
33 | | -------
|
||||
34 | | A value of some sort.
|
||||
35 | |
|
||||
36 | | """
|
||||
| |_______^ D406
|
||||
|
|
||||
= help: Add newline after "Returns"
|
||||
|
||||
ℹ Fix
|
||||
29 29 | def superfluous_suffix(): # noqa: D416
|
||||
30 30 | """Toggle the gizmo.
|
||||
31 31 |
|
||||
32 |- Returns:
|
||||
32 |+ Returns
|
||||
33 33 | -------
|
||||
34 34 | A value of some sort.
|
||||
35 35 |
|
||||
|
||||
sections.py:216:5: D406 [*] Section name should end with a newline ("Raises")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D406
|
||||
|
|
||||
= help: Add newline after "Raises"
|
||||
|
||||
ℹ Fix
|
||||
224 224 | Returns
|
||||
225 225 | ------
|
||||
226 226 | Many many wonderful things.
|
||||
227 |- Raises:
|
||||
227 |+ Raises
|
||||
228 228 | My attention.
|
||||
229 229 |
|
||||
230 230 | """
|
||||
|
||||
|
|
@ -0,0 +1,501 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:42:5: D407 [*] Missing dashed underline after section ("Returns")
|
||||
|
|
||||
40 | @expect("D407: Missing dashed underline after section ('Returns')")
|
||||
41 | def no_underline(): # noqa: D416
|
||||
42 | """Toggle the gizmo.
|
||||
| _____^
|
||||
43 | |
|
||||
44 | | Returns
|
||||
45 | | A value of some sort.
|
||||
46 | |
|
||||
47 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Returns"
|
||||
|
||||
ℹ Fix
|
||||
42 42 | """Toggle the gizmo.
|
||||
43 43 |
|
||||
44 44 | Returns
|
||||
45 |+ -------
|
||||
45 46 | A value of some sort.
|
||||
46 47 |
|
||||
47 48 | """
|
||||
|
||||
sections.py:54:5: D407 [*] Missing dashed underline after section ("Returns")
|
||||
|
|
||||
52 | @expect("D414: Section has no content ('Returns')")
|
||||
53 | def no_underline_and_no_description(): # noqa: D416
|
||||
54 | """Toggle the gizmo.
|
||||
| _____^
|
||||
55 | |
|
||||
56 | | Returns
|
||||
57 | |
|
||||
58 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Returns"
|
||||
|
||||
ℹ Fix
|
||||
54 54 | """Toggle the gizmo.
|
||||
55 55 |
|
||||
56 56 | Returns
|
||||
57 |+ -------
|
||||
57 58 |
|
||||
58 59 | """
|
||||
59 60 |
|
||||
|
||||
sections.py:65:5: D407 [*] Missing dashed underline after section ("Returns")
|
||||
|
|
||||
63 | @expect("D414: Section has no content ('Returns')")
|
||||
64 | def no_underline_and_no_newline(): # noqa: D416
|
||||
65 | """Toggle the gizmo.
|
||||
| _____^
|
||||
66 | |
|
||||
67 | | Returns"""
|
||||
| |______________^ D407
|
||||
|
|
||||
= help: Add dashed line under "Returns"
|
||||
|
||||
ℹ Fix
|
||||
64 64 | def no_underline_and_no_newline(): # noqa: D416
|
||||
65 65 | """Toggle the gizmo.
|
||||
66 66 |
|
||||
67 |- Returns"""
|
||||
67 |+ Returns
|
||||
68 |+ -------"""
|
||||
68 69 |
|
||||
69 70 |
|
||||
70 71 | @expect(_D213)
|
||||
|
||||
sections.py:216:5: D407 [*] Missing dashed underline after section ("Raises")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Raises"
|
||||
|
||||
ℹ Fix
|
||||
225 225 | ------
|
||||
226 226 | Many many wonderful things.
|
||||
227 227 | Raises:
|
||||
228 |+ ------
|
||||
228 229 | My attention.
|
||||
229 230 |
|
||||
230 231 | """
|
||||
|
||||
sections.py:261:5: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
259 | @expect("D414: Section has no content ('Returns')")
|
||||
260 | def valid_google_style_section(): # noqa: D406, D407
|
||||
261 | """Toggle the gizmo.
|
||||
| _____^
|
||||
262 | |
|
||||
263 | | Args:
|
||||
264 | | note: A random string.
|
||||
265 | |
|
||||
266 | | Returns:
|
||||
267 | |
|
||||
268 | | Raises:
|
||||
269 | | RandomError: A random error that occurs randomly.
|
||||
270 | |
|
||||
271 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
261 261 | """Toggle the gizmo.
|
||||
262 262 |
|
||||
263 263 | Args:
|
||||
264 |+ ----
|
||||
264 265 | note: A random string.
|
||||
265 266 |
|
||||
266 267 | Returns:
|
||||
|
||||
sections.py:261:5: D407 [*] Missing dashed underline after section ("Returns")
|
||||
|
|
||||
259 | @expect("D414: Section has no content ('Returns')")
|
||||
260 | def valid_google_style_section(): # noqa: D406, D407
|
||||
261 | """Toggle the gizmo.
|
||||
| _____^
|
||||
262 | |
|
||||
263 | | Args:
|
||||
264 | | note: A random string.
|
||||
265 | |
|
||||
266 | | Returns:
|
||||
267 | |
|
||||
268 | | Raises:
|
||||
269 | | RandomError: A random error that occurs randomly.
|
||||
270 | |
|
||||
271 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Returns"
|
||||
|
||||
ℹ Fix
|
||||
264 264 | note: A random string.
|
||||
265 265 |
|
||||
266 266 | Returns:
|
||||
267 |+ -------
|
||||
267 268 |
|
||||
268 269 | Raises:
|
||||
269 270 | RandomError: A random error that occurs randomly.
|
||||
|
||||
sections.py:261:5: D407 [*] Missing dashed underline after section ("Raises")
|
||||
|
|
||||
259 | @expect("D414: Section has no content ('Returns')")
|
||||
260 | def valid_google_style_section(): # noqa: D406, D407
|
||||
261 | """Toggle the gizmo.
|
||||
| _____^
|
||||
262 | |
|
||||
263 | | Args:
|
||||
264 | | note: A random string.
|
||||
265 | |
|
||||
266 | | Returns:
|
||||
267 | |
|
||||
268 | | Raises:
|
||||
269 | | RandomError: A random error that occurs randomly.
|
||||
270 | |
|
||||
271 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Raises"
|
||||
|
||||
ℹ Fix
|
||||
266 266 | Returns:
|
||||
267 267 |
|
||||
268 268 | Raises:
|
||||
269 |+ ------
|
||||
269 270 | RandomError: A random error that occurs randomly.
|
||||
270 271 |
|
||||
271 272 | """
|
||||
|
||||
sections.py:278:5: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
276 | "('Args:', not 'Args')")
|
||||
277 | def missing_colon_google_style_section(): # noqa: D406, D407
|
||||
278 | """Toggle the gizmo.
|
||||
| _____^
|
||||
279 | |
|
||||
280 | | Args
|
||||
281 | | note: A random string.
|
||||
282 | |
|
||||
283 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
278 278 | """Toggle the gizmo.
|
||||
279 279 |
|
||||
280 280 | Args
|
||||
281 |+ ----
|
||||
281 282 | note: A random string.
|
||||
282 283 |
|
||||
283 284 | """
|
||||
|
||||
sections.py:293:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
292 | def bar(y=2): # noqa: D207, D213, D406, D407
|
||||
293 | """Nested function test for docstrings.
|
||||
| _________^
|
||||
294 | |
|
||||
295 | | Will this work when referencing x?
|
||||
296 | |
|
||||
297 | | Args:
|
||||
298 | | x: Test something
|
||||
299 | | that is broken.
|
||||
300 | |
|
||||
301 | | """
|
||||
| |___________^ D407
|
||||
302 | print(x)
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
295 295 | Will this work when referencing x?
|
||||
296 296 |
|
||||
297 297 | Args:
|
||||
298 |+ ----
|
||||
298 299 | x: Test something
|
||||
299 300 | that is broken.
|
||||
300 301 |
|
||||
|
||||
sections.py:310:5: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
308 | "'test_missing_google_args' docstring)")
|
||||
309 | def test_missing_google_args(x=1, y=2, _private=3): # noqa: D406, D407
|
||||
310 | """Toggle the gizmo.
|
||||
| _____^
|
||||
311 | |
|
||||
312 | | Args:
|
||||
313 | | x (int): The greatest integer.
|
||||
314 | |
|
||||
315 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
310 310 | """Toggle the gizmo.
|
||||
311 311 |
|
||||
312 312 | Args:
|
||||
313 |+ ----
|
||||
313 314 | x (int): The greatest integer.
|
||||
314 315 |
|
||||
315 316 | """
|
||||
|
||||
sections.py:322:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
321 | def test_method(self, test, another_test, _): # noqa: D213, D407
|
||||
322 | """Test a valid args section.
|
||||
| _________^
|
||||
323 | |
|
||||
324 | | Args:
|
||||
325 | | test: A parameter.
|
||||
326 | | another_test: Another parameter.
|
||||
327 | |
|
||||
328 | | """
|
||||
| |___________^ D407
|
||||
329 |
|
||||
330 | @expect("D417: Missing argument descriptions in the docstring "
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
322 322 | """Test a valid args section.
|
||||
323 323 |
|
||||
324 324 | Args:
|
||||
325 |+ ----
|
||||
325 326 | test: A parameter.
|
||||
326 327 | another_test: Another parameter.
|
||||
327 328 |
|
||||
|
||||
sections.py:334:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
332 | "'test_missing_args' docstring)", arg_count=5)
|
||||
333 | def test_missing_args(self, test, x, y, z=3, _private_arg=3): # noqa: D213, D407
|
||||
334 | """Test a valid args section.
|
||||
| _________^
|
||||
335 | |
|
||||
336 | | Args:
|
||||
337 | | x: Another parameter.
|
||||
338 | |
|
||||
339 | | """
|
||||
| |___________^ D407
|
||||
340 |
|
||||
341 | @classmethod
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
334 334 | """Test a valid args section.
|
||||
335 335 |
|
||||
336 336 | Args:
|
||||
337 |+ ----
|
||||
337 338 | x: Another parameter.
|
||||
338 339 |
|
||||
339 340 | """
|
||||
|
||||
sections.py:346:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
344 | "'test_missing_args_class_method' docstring)", arg_count=5)
|
||||
345 | def test_missing_args_class_method(cls, test, x, y, _, z=3): # noqa: D213, D407
|
||||
346 | """Test a valid args section.
|
||||
| _________^
|
||||
347 | |
|
||||
348 | | Args:
|
||||
349 | | x: Another parameter. The parameter below is missing description.
|
||||
350 | | y:
|
||||
351 | |
|
||||
352 | | """
|
||||
| |___________^ D407
|
||||
353 |
|
||||
354 | @staticmethod
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
346 346 | """Test a valid args section.
|
||||
347 347 |
|
||||
348 348 | Args:
|
||||
349 |+ ----
|
||||
349 350 | x: Another parameter. The parameter below is missing description.
|
||||
350 351 | y:
|
||||
351 352 |
|
||||
|
||||
sections.py:359:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
357 | "'test_missing_args_static_method' docstring)", arg_count=4)
|
||||
358 | def test_missing_args_static_method(a, x, y, _test, z=3): # noqa: D213, D407
|
||||
359 | """Test a valid args section.
|
||||
| _________^
|
||||
360 | |
|
||||
361 | | Args:
|
||||
362 | | x: Another parameter.
|
||||
363 | |
|
||||
364 | | """
|
||||
| |___________^ D407
|
||||
365 |
|
||||
366 | @staticmethod
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
359 359 | """Test a valid args section.
|
||||
360 360 |
|
||||
361 361 | Args:
|
||||
362 |+ ----
|
||||
362 363 | x: Another parameter.
|
||||
363 364 |
|
||||
364 365 | """
|
||||
|
||||
sections.py:371:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
369 | "'test_missing_docstring' docstring)", arg_count=2)
|
||||
370 | def test_missing_docstring(a, b): # noqa: D213, D407
|
||||
371 | """Test a valid args section.
|
||||
| _________^
|
||||
372 | |
|
||||
373 | | Args:
|
||||
374 | | a:
|
||||
375 | |
|
||||
376 | | """
|
||||
| |___________^ D407
|
||||
377 |
|
||||
378 | @staticmethod
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
371 371 | """Test a valid args section.
|
||||
372 372 |
|
||||
373 373 | Args:
|
||||
374 |+ ----
|
||||
374 375 | a:
|
||||
375 376 |
|
||||
376 377 | """
|
||||
|
||||
sections.py:380:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
378 | @staticmethod
|
||||
379 | def test_hanging_indent(skip, verbose): # noqa: D213, D407
|
||||
380 | """Do stuff.
|
||||
| _________^
|
||||
381 | |
|
||||
382 | | Args:
|
||||
383 | | skip (:attr:`.Skip`):
|
||||
384 | | Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
385 | | Etiam at tellus a tellus faucibus maximus. Curabitur tellus
|
||||
386 | | mauris, semper id vehicula ac, feugiat ut tortor.
|
||||
387 | | verbose (bool):
|
||||
388 | | If True, print out as much information as possible.
|
||||
389 | | If False, print out concise "one-liner" information.
|
||||
390 | |
|
||||
391 | | """
|
||||
| |___________^ D407
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
380 380 | """Do stuff.
|
||||
381 381 |
|
||||
382 382 | Args:
|
||||
383 |+ ----
|
||||
383 384 | skip (:attr:`.Skip`):
|
||||
384 385 | Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
385 386 | Etiam at tellus a tellus faucibus maximus. Curabitur tellus
|
||||
|
||||
sections.py:499:9: D407 [*] Missing dashed underline after section ("Args")
|
||||
|
|
||||
497 | "'test_incorrect_indent' docstring)", arg_count=3)
|
||||
498 | def test_incorrect_indent(self, x=1, y=2): # noqa: D207, D213, D407
|
||||
499 | """Reproducing issue #437.
|
||||
| _________^
|
||||
500 | |
|
||||
501 | | Testing this incorrectly indented docstring.
|
||||
502 | |
|
||||
503 | | Args:
|
||||
504 | | x: Test argument.
|
||||
505 | |
|
||||
506 | | """
|
||||
| |___________^ D407
|
||||
|
|
||||
= help: Add dashed line under "Args"
|
||||
|
||||
ℹ Fix
|
||||
501 501 | Testing this incorrectly indented docstring.
|
||||
502 502 |
|
||||
503 503 | Args:
|
||||
504 |+ ----
|
||||
504 505 | x: Test argument.
|
||||
505 506 |
|
||||
506 507 | """
|
||||
|
||||
sections.py:519:5: D407 [*] Missing dashed underline after section ("Parameters")
|
||||
|
|
||||
518 | def replace_equals_with_dash():
|
||||
519 | """Equal length equals should be replaced with dashes.
|
||||
| _____^
|
||||
520 | |
|
||||
521 | | Parameters
|
||||
522 | | ==========
|
||||
523 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Parameters"
|
||||
|
||||
ℹ Fix
|
||||
519 519 | """Equal length equals should be replaced with dashes.
|
||||
520 520 |
|
||||
521 521 | Parameters
|
||||
522 |- ==========
|
||||
522 |+ ----------
|
||||
523 523 | """
|
||||
524 524 |
|
||||
525 525 |
|
||||
|
||||
sections.py:527:5: D407 [*] Missing dashed underline after section ("Parameters")
|
||||
|
|
||||
526 | def replace_equals_with_dash2():
|
||||
527 | """Here, the length of equals is not the same.
|
||||
| _____^
|
||||
528 | |
|
||||
529 | | Parameters
|
||||
530 | | ===========
|
||||
531 | | """
|
||||
| |_______^ D407
|
||||
|
|
||||
= help: Add dashed line under "Parameters"
|
||||
|
||||
ℹ Fix
|
||||
527 527 | """Here, the length of equals is not the same.
|
||||
528 528 |
|
||||
529 529 | Parameters
|
||||
530 |+ ----------
|
||||
530 531 | ===========
|
||||
531 532 | """
|
||||
532 533 |
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:94:5: D408 [*] Section underline should be in the line following the section's name ("Returns")
|
||||
|
|
||||
92 | "section's name ('Returns')")
|
||||
93 | def blank_line_before_underline(): # noqa: D416
|
||||
94 | """Toggle the gizmo.
|
||||
| _____^
|
||||
95 | |
|
||||
96 | | Returns
|
||||
97 | |
|
||||
98 | | -------
|
||||
99 | | A value of some sort.
|
||||
100 | |
|
||||
101 | | """
|
||||
| |_______^ D408
|
||||
|
|
||||
= help: Add underline to "Returns"
|
||||
|
||||
ℹ Fix
|
||||
94 94 | """Toggle the gizmo.
|
||||
95 95 |
|
||||
96 96 | Returns
|
||||
97 |-
|
||||
98 97 | -------
|
||||
99 98 | A value of some sort.
|
||||
100 99 |
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:108:5: D409 [*] Section underline should match the length of its name ("Returns")
|
||||
|
|
||||
106 | "(Expected 7 dashes in section 'Returns', got 2)")
|
||||
107 | def bad_underline_length(): # noqa: D416
|
||||
108 | """Toggle the gizmo.
|
||||
| _____^
|
||||
109 | |
|
||||
110 | | Returns
|
||||
111 | | --
|
||||
112 | | A value of some sort.
|
||||
113 | |
|
||||
114 | | """
|
||||
| |_______^ D409
|
||||
|
|
||||
= help: Adjust underline length to match "Returns"
|
||||
|
||||
ℹ Fix
|
||||
108 108 | """Toggle the gizmo.
|
||||
109 109 |
|
||||
110 110 | Returns
|
||||
111 |- --
|
||||
111 |+ -------
|
||||
112 112 | A value of some sort.
|
||||
113 113 |
|
||||
114 114 | """
|
||||
|
||||
sections.py:216:5: D409 [*] Section underline should match the length of its name ("Returns")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D409
|
||||
|
|
||||
= help: Adjust underline length to match "Returns"
|
||||
|
||||
ℹ Fix
|
||||
222 222 | returns.
|
||||
223 223 |
|
||||
224 224 | Returns
|
||||
225 |- ------
|
||||
225 |+ -------
|
||||
226 226 | Many many wonderful things.
|
||||
227 227 | Raises:
|
||||
228 228 | My attention.
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D410.py:2:5: D410 [*] Missing blank line after section ("Parameters")
|
||||
|
|
||||
1 | def f(a: int, b: int) -> int:
|
||||
2 | """Showcase function.
|
||||
| _____^
|
||||
3 | |
|
||||
4 | | Parameters
|
||||
5 | | ----------
|
||||
6 | | a : int
|
||||
7 | | _description_
|
||||
8 | | b : int
|
||||
9 | | _description_
|
||||
10 | | Returns
|
||||
11 | | -------
|
||||
12 | | int
|
||||
13 | | _description
|
||||
14 | | """
|
||||
| |_______^ D410
|
||||
15 | return b - a
|
||||
|
|
||||
= help: Add blank line after "Parameters"
|
||||
|
||||
ℹ Fix
|
||||
7 7 | _description_
|
||||
8 8 | b : int
|
||||
9 9 | _description_
|
||||
10 |+
|
||||
10 11 | Returns
|
||||
11 12 | -------
|
||||
12 13 | int
|
||||
|
||||
D410.py:19:5: D410 [*] Missing blank line after section ("Parameters")
|
||||
|
|
||||
18 | def f() -> int:
|
||||
19 | """Showcase function.
|
||||
| _____^
|
||||
20 | |
|
||||
21 | | Parameters
|
||||
22 | | ----------
|
||||
23 | | Returns
|
||||
24 | | -------
|
||||
25 | | """
|
||||
| |_______^ D410
|
||||
|
|
||||
= help: Add blank line after "Parameters"
|
||||
|
||||
ℹ Fix
|
||||
20 20 |
|
||||
21 21 | Parameters
|
||||
22 22 | ----------
|
||||
23 |+
|
||||
23 24 | Returns
|
||||
24 25 | -------
|
||||
25 26 | """
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:76:5: D410 [*] Missing blank line after section ("Returns")
|
||||
|
|
||||
74 | @expect("D414: Section has no content ('Yields')")
|
||||
75 | def consecutive_sections(): # noqa: D416
|
||||
76 | """Toggle the gizmo.
|
||||
| _____^
|
||||
77 | |
|
||||
78 | | Returns
|
||||
79 | | -------
|
||||
80 | | Yields
|
||||
81 | | ------
|
||||
82 | |
|
||||
83 | | Raises
|
||||
84 | | ------
|
||||
85 | | Questions.
|
||||
86 | |
|
||||
87 | | """
|
||||
| |_______^ D410
|
||||
|
|
||||
= help: Add blank line after "Returns"
|
||||
|
||||
ℹ Fix
|
||||
77 77 |
|
||||
78 78 | Returns
|
||||
79 79 | -------
|
||||
80 |+
|
||||
80 81 | Yields
|
||||
81 82 | ------
|
||||
82 83 |
|
||||
|
||||
sections.py:216:5: D410 [*] Missing blank line after section ("Returns")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D410
|
||||
|
|
||||
= help: Add blank line after "Returns"
|
||||
|
||||
ℹ Fix
|
||||
224 224 | Returns
|
||||
225 225 | ------
|
||||
226 226 | Many many wonderful things.
|
||||
227 |+
|
||||
227 228 | Raises:
|
||||
228 229 | My attention.
|
||||
229 230 |
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:76:5: D411 [*] Missing blank line before section ("Yields")
|
||||
|
|
||||
74 | @expect("D414: Section has no content ('Yields')")
|
||||
75 | def consecutive_sections(): # noqa: D416
|
||||
76 | """Toggle the gizmo.
|
||||
| _____^
|
||||
77 | |
|
||||
78 | | Returns
|
||||
79 | | -------
|
||||
80 | | Yields
|
||||
81 | | ------
|
||||
82 | |
|
||||
83 | | Raises
|
||||
84 | | ------
|
||||
85 | | Questions.
|
||||
86 | |
|
||||
87 | | """
|
||||
| |_______^ D411
|
||||
|
|
||||
= help: Add blank line before "Yields"
|
||||
|
||||
ℹ Fix
|
||||
77 77 |
|
||||
78 78 | Returns
|
||||
79 79 | -------
|
||||
80 |+
|
||||
80 81 | Yields
|
||||
81 82 | ------
|
||||
82 83 |
|
||||
|
||||
sections.py:131:5: D411 [*] Missing blank line before section ("Returns")
|
||||
|
|
||||
129 | @expect("D411: Missing blank line before section ('Returns')")
|
||||
130 | def no_blank_line_before_section(): # noqa: D416
|
||||
131 | """Toggle the gizmo.
|
||||
| _____^
|
||||
132 | |
|
||||
133 | | The function's description.
|
||||
134 | | Returns
|
||||
135 | | -------
|
||||
136 | | A value of some sort.
|
||||
137 | |
|
||||
138 | | """
|
||||
| |_______^ D411
|
||||
|
|
||||
= help: Add blank line before "Returns"
|
||||
|
||||
ℹ Fix
|
||||
131 131 | """Toggle the gizmo.
|
||||
132 132 |
|
||||
133 133 | The function's description.
|
||||
134 |+
|
||||
134 135 | Returns
|
||||
135 136 | -------
|
||||
136 137 | A value of some sort.
|
||||
|
||||
sections.py:216:5: D411 [*] Missing blank line before section ("Raises")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D411
|
||||
|
|
||||
= help: Add blank line before "Raises"
|
||||
|
||||
ℹ Fix
|
||||
224 224 | Returns
|
||||
225 225 | ------
|
||||
226 226 | Many many wonderful things.
|
||||
227 |+
|
||||
227 228 | Raises:
|
||||
228 229 | My attention.
|
||||
229 230 |
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:216:5: D412 [*] No blank lines allowed between a section header and its content ("Short summary")
|
||||
|
|
||||
214 | @expect("D407: Missing dashed underline after section ('Raises')")
|
||||
215 | def multiple_sections(): # noqa: D416
|
||||
216 | """Toggle the gizmo.
|
||||
| _____^
|
||||
217 | |
|
||||
218 | | Short summary
|
||||
219 | | -------------
|
||||
220 | |
|
||||
221 | | This is the function's description, which will also specify what it
|
||||
222 | | returns.
|
||||
223 | |
|
||||
224 | | Returns
|
||||
225 | | ------
|
||||
226 | | Many many wonderful things.
|
||||
227 | | Raises:
|
||||
228 | | My attention.
|
||||
229 | |
|
||||
230 | | """
|
||||
| |_______^ D412
|
||||
|
|
||||
= help: Remove blank line(s)
|
||||
|
||||
ℹ Fix
|
||||
217 217 |
|
||||
218 218 | Short summary
|
||||
219 219 | -------------
|
||||
220 |-
|
||||
221 220 | This is the function's description, which will also specify what it
|
||||
222 221 | returns.
|
||||
223 222 |
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:65:5: D413 [*] Missing blank line after last section ("Returns")
|
||||
|
|
||||
63 | @expect("D414: Section has no content ('Returns')")
|
||||
64 | def no_underline_and_no_newline(): # noqa: D416
|
||||
65 | """Toggle the gizmo.
|
||||
| _____^
|
||||
66 | |
|
||||
67 | | Returns"""
|
||||
| |______________^ D413
|
||||
|
|
||||
= help: Add blank line after "Returns"
|
||||
|
||||
ℹ Fix
|
||||
64 64 | def no_underline_and_no_newline(): # noqa: D416
|
||||
65 65 | """Toggle the gizmo.
|
||||
66 66 |
|
||||
67 |- Returns"""
|
||||
67 |+ Returns
|
||||
68 |+ """
|
||||
68 69 |
|
||||
69 70 |
|
||||
70 71 | @expect(_D213)
|
||||
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:54:5: D414 Section has no content ("Returns")
|
||||
|
|
||||
52 | @expect("D414: Section has no content ('Returns')")
|
||||
53 | def no_underline_and_no_description(): # noqa: D416
|
||||
54 | """Toggle the gizmo.
|
||||
| _____^
|
||||
55 | |
|
||||
56 | | Returns
|
||||
57 | |
|
||||
58 | | """
|
||||
| |_______^ D414
|
||||
|
|
||||
|
||||
sections.py:65:5: D414 Section has no content ("Returns")
|
||||
|
|
||||
63 | @expect("D414: Section has no content ('Returns')")
|
||||
64 | def no_underline_and_no_newline(): # noqa: D416
|
||||
65 | """Toggle the gizmo.
|
||||
| _____^
|
||||
66 | |
|
||||
67 | | Returns"""
|
||||
| |______________^ D414
|
||||
|
|
||||
|
||||
sections.py:76:5: D414 Section has no content ("Returns")
|
||||
|
|
||||
74 | @expect("D414: Section has no content ('Yields')")
|
||||
75 | def consecutive_sections(): # noqa: D416
|
||||
76 | """Toggle the gizmo.
|
||||
| _____^
|
||||
77 | |
|
||||
78 | | Returns
|
||||
79 | | -------
|
||||
80 | | Yields
|
||||
81 | | ------
|
||||
82 | |
|
||||
83 | | Raises
|
||||
84 | | ------
|
||||
85 | | Questions.
|
||||
86 | |
|
||||
87 | | """
|
||||
| |_______^ D414
|
||||
|
|
||||
|
||||
sections.py:76:5: D414 Section has no content ("Yields")
|
||||
|
|
||||
74 | @expect("D414: Section has no content ('Yields')")
|
||||
75 | def consecutive_sections(): # noqa: D416
|
||||
76 | """Toggle the gizmo.
|
||||
| _____^
|
||||
77 | |
|
||||
78 | | Returns
|
||||
79 | | -------
|
||||
80 | | Yields
|
||||
81 | | ------
|
||||
82 | |
|
||||
83 | | Raises
|
||||
84 | | ------
|
||||
85 | | Questions.
|
||||
86 | |
|
||||
87 | | """
|
||||
| |_______^ D414
|
||||
|
|
||||
|
||||
sections.py:170:5: D414 Section has no content ("Returns")
|
||||
|
|
||||
168 | @expect("D414: Section has no content ('Returns')")
|
||||
169 | def section_underline_overindented_and_contentless(): # noqa: D416
|
||||
170 | """Toggle the gizmo.
|
||||
| _____^
|
||||
171 | |
|
||||
172 | | Returns
|
||||
173 | | -------
|
||||
174 | | """
|
||||
| |_______^ D414
|
||||
|
|
||||
|
||||
sections.py:261:5: D414 Section has no content ("Returns")
|
||||
|
|
||||
259 | @expect("D414: Section has no content ('Returns')")
|
||||
260 | def valid_google_style_section(): # noqa: D406, D407
|
||||
261 | """Toggle the gizmo.
|
||||
| _____^
|
||||
262 | |
|
||||
263 | | Args:
|
||||
264 | | note: A random string.
|
||||
265 | |
|
||||
266 | | Returns:
|
||||
267 | |
|
||||
268 | | Raises:
|
||||
269 | | RandomError: A random error that occurs randomly.
|
||||
270 | |
|
||||
271 | | """
|
||||
| |_______^ D414
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:355:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
353 | "or exclamation point (not 'y')")
|
||||
354 | def lwnlkjl():
|
||||
355 | """Summary"""
|
||||
| ^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
352 352 | @expect("D415: First line should end with a period, question mark, "
|
||||
353 353 | "or exclamation point (not 'y')")
|
||||
354 354 | def lwnlkjl():
|
||||
355 |- """Summary"""
|
||||
355 |+ """Summary."""
|
||||
356 356 |
|
||||
357 357 |
|
||||
358 358 | @expect("D401: First line should be in imperative mood "
|
||||
|
||||
D.py:406:25: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
404 | @expect("D415: First line should end with a period, question mark,"
|
||||
405 | " or exclamation point (not 'r')")
|
||||
406 | def oneliner_withdoc(): """One liner"""
|
||||
| ^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
403 403 | @expect("D400: First line should end with a period (not 'r')")
|
||||
404 404 | @expect("D415: First line should end with a period, question mark,"
|
||||
405 405 | " or exclamation point (not 'r')")
|
||||
406 |-def oneliner_withdoc(): """One liner"""
|
||||
406 |+def oneliner_withdoc(): """One liner."""
|
||||
407 407 |
|
||||
408 408 |
|
||||
409 409 | def ignored_decorator(func): # noqa: D400,D401,D415
|
||||
|
||||
D.py:410:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
409 | def ignored_decorator(func): # noqa: D400,D401,D415
|
||||
410 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D415
|
||||
411 | func()
|
||||
412 | pass
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
407 407 |
|
||||
408 408 |
|
||||
409 409 | def ignored_decorator(func): # noqa: D400,D401,D415
|
||||
410 |- """Runs something"""
|
||||
410 |+ """Runs something."""
|
||||
411 411 | func()
|
||||
412 412 | pass
|
||||
413 413 |
|
||||
|
||||
D.py:416:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
415 | def decorator_for_test(func): # noqa: D400,D401,D415
|
||||
416 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D415
|
||||
417 | func()
|
||||
418 | pass
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
413 413 |
|
||||
414 414 |
|
||||
415 415 | def decorator_for_test(func): # noqa: D400,D401,D415
|
||||
416 |- """Runs something"""
|
||||
416 |+ """Runs something."""
|
||||
417 417 | func()
|
||||
418 418 | pass
|
||||
419 419 |
|
||||
|
||||
D.py:422:35: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
421 | @ignored_decorator
|
||||
422 | def oneliner_ignored_decorator(): """One liner"""
|
||||
| ^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
419 419 |
|
||||
420 420 |
|
||||
421 421 | @ignored_decorator
|
||||
422 |-def oneliner_ignored_decorator(): """One liner"""
|
||||
422 |+def oneliner_ignored_decorator(): """One liner."""
|
||||
423 423 |
|
||||
424 424 |
|
||||
425 425 | @decorator_for_test
|
||||
|
||||
D.py:429:49: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
427 | @expect("D415: First line should end with a period, question mark,"
|
||||
428 | " or exclamation point (not 'r')")
|
||||
429 | def oneliner_with_decorator_expecting_errors(): """One liner"""
|
||||
| ^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
426 426 | @expect("D400: First line should end with a period (not 'r')")
|
||||
427 427 | @expect("D415: First line should end with a period, question mark,"
|
||||
428 428 | " or exclamation point (not 'r')")
|
||||
429 |-def oneliner_with_decorator_expecting_errors(): """One liner"""
|
||||
429 |+def oneliner_with_decorator_expecting_errors(): """One liner."""
|
||||
430 430 |
|
||||
431 431 |
|
||||
432 432 | @decorator_for_test
|
||||
|
||||
D.py:470:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
468 | "or exclamation point (not 'g')")
|
||||
469 | def docstring_bad():
|
||||
470 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D415
|
||||
471 | pass
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
467 467 | @expect("D415: First line should end with a period, question mark, "
|
||||
468 468 | "or exclamation point (not 'g')")
|
||||
469 469 | def docstring_bad():
|
||||
470 |- """Runs something"""
|
||||
470 |+ """Runs something."""
|
||||
471 471 | pass
|
||||
472 472 |
|
||||
473 473 |
|
||||
|
||||
D.py:475:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
474 | def docstring_bad_ignore_all(): # noqa
|
||||
475 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D415
|
||||
476 | pass
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
472 472 |
|
||||
473 473 |
|
||||
474 474 | def docstring_bad_ignore_all(): # noqa
|
||||
475 |- """Runs something"""
|
||||
475 |+ """Runs something."""
|
||||
476 476 | pass
|
||||
477 477 |
|
||||
478 478 |
|
||||
|
||||
D.py:480:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
479 | def docstring_bad_ignore_one(): # noqa: D400,D401,D415
|
||||
480 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D415
|
||||
481 | pass
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
477 477 |
|
||||
478 478 |
|
||||
479 479 | def docstring_bad_ignore_one(): # noqa: D400,D401,D415
|
||||
480 |- """Runs something"""
|
||||
480 |+ """Runs something."""
|
||||
481 481 | pass
|
||||
482 482 |
|
||||
483 483 |
|
||||
|
||||
D.py:487:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
485 | "(perhaps 'Run', not 'Runs')")
|
||||
486 | def docstring_ignore_some_violations_but_catch_D401(): # noqa: E501,D400,D415
|
||||
487 | """Runs something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^ D415
|
||||
488 | pass
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
484 484 | @expect("D401: First line should be in imperative mood "
|
||||
485 485 | "(perhaps 'Run', not 'Runs')")
|
||||
486 486 | def docstring_ignore_some_violations_but_catch_D401(): # noqa: E501,D400,D415
|
||||
487 |- """Runs something"""
|
||||
487 |+ """Runs something."""
|
||||
488 488 | pass
|
||||
489 489 |
|
||||
490 490 |
|
||||
|
||||
D.py:520:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
518 | "or exclamation point (not 'g')")
|
||||
519 | def bad_google_string(): # noqa: D400
|
||||
520 | """Test a valid something"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
517 517 | @expect("D415: First line should end with a period, question mark, "
|
||||
518 518 | "or exclamation point (not 'g')")
|
||||
519 519 | def bad_google_string(): # noqa: D400
|
||||
520 |- """Test a valid something"""
|
||||
520 |+ """Test a valid something."""
|
||||
521 521 |
|
||||
522 522 |
|
||||
523 523 | # This is reproducing a bug where AttributeError is raised when parsing class
|
||||
|
||||
D.py:581:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
579 | "or exclamation point (not '\"')")
|
||||
580 | def endswith_quote():
|
||||
581 | """Whitespace at the end, but also a quote" """
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
578 578 | @expect("D415: First line should end with a period, question mark, "
|
||||
579 579 | "or exclamation point (not '\"')")
|
||||
580 580 | def endswith_quote():
|
||||
581 |- """Whitespace at the end, but also a quote" """
|
||||
581 |+ """Whitespace at the end, but also a quote". """
|
||||
582 582 |
|
||||
583 583 |
|
||||
584 584 | @expect('D209: Multi-line docstring closing quotes should be on a separate '
|
||||
|
||||
D.py:615:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 | def one_liner():
|
||||
615 | """Wrong."
|
||||
| _____^
|
||||
616 | |
|
||||
617 | | """
|
||||
| |_______^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
612 612 | '(found 3)')
|
||||
613 613 | @expect('D212: Multi-line docstring summary should start at the first line')
|
||||
614 614 | def one_liner():
|
||||
615 |- """Wrong."
|
||||
615 |+ """Wrong.".
|
||||
616 616 |
|
||||
617 617 | """
|
||||
618 618 |
|
||||
|
||||
D.py:639:17: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D415
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
636 636 | """ This is a docstring that starts with a space.""" # noqa: D210
|
||||
637 637 |
|
||||
638 638 |
|
||||
639 |-class SameLine: """This is a docstring on the same line"""
|
||||
639 |+class SameLine: """This is a docstring on the same line."""
|
||||
640 640 |
|
||||
641 641 | def same_line(): """This is a docstring on the same line"""
|
||||
642 642 |
|
||||
|
||||
D.py:641:18: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 |
|
||||
641 | def same_line(): """This is a docstring on the same line"""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
638 638 |
|
||||
639 639 | class SameLine: """This is a docstring on the same line"""
|
||||
640 640 |
|
||||
641 |-def same_line(): """This is a docstring on the same line"""
|
||||
641 |+def same_line(): """This is a docstring on the same line."""
|
||||
642 642 |
|
||||
643 643 |
|
||||
644 644 | def single_line_docstring_with_an_escaped_backslash():
|
||||
|
||||
D.py:664:5: D415 [*] First line should end with a period, question mark, or exclamation point
|
||||
|
|
||||
663 | def newline_after_closing_quote(self):
|
||||
664 | "We enforce a newline after the closing quote for a multi-line docstring \
|
||||
| _____^
|
||||
665 | | but continuations shouldn't be considered multi-line"
|
||||
| |_________________________________________________________^ D415
|
||||
|
|
||||
= help: Add closing punctuation
|
||||
|
||||
ℹ Suggested fix
|
||||
662 662 |
|
||||
663 663 | def newline_after_closing_quote(self):
|
||||
664 664 | "We enforce a newline after the closing quote for a multi-line docstring \
|
||||
665 |- but continuations shouldn't be considered multi-line"
|
||||
665 |+ but continuations shouldn't be considered multi-line."
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
sections.py:292:9: D417 Missing argument description in the docstring for `bar`: `y`
|
||||
|
|
||||
290 | x = 1
|
||||
291 |
|
||||
292 | def bar(y=2): # noqa: D207, D213, D406, D407
|
||||
| ^^^ D417
|
||||
293 | """Nested function test for docstrings.
|
||||
|
|
||||
|
||||
sections.py:309:5: D417 Missing argument description in the docstring for `test_missing_google_args`: `y`
|
||||
|
|
||||
307 | "(argument(s) y are missing descriptions in "
|
||||
308 | "'test_missing_google_args' docstring)")
|
||||
309 | def test_missing_google_args(x=1, y=2, _private=3): # noqa: D406, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
310 | """Toggle the gizmo.
|
||||
|
|
||||
|
||||
sections.py:333:9: D417 Missing argument descriptions in the docstring for `test_missing_args`: `test`, `y`, `z`
|
||||
|
|
||||
331 | "(argument(s) test, y, z are missing descriptions in "
|
||||
332 | "'test_missing_args' docstring)", arg_count=5)
|
||||
333 | def test_missing_args(self, test, x, y, z=3, _private_arg=3): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^ D417
|
||||
334 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:345:9: D417 Missing argument descriptions in the docstring for `test_missing_args_class_method`: `test`, `y`, `z`
|
||||
|
|
||||
343 | "(argument(s) test, y, z are missing descriptions in "
|
||||
344 | "'test_missing_args_class_method' docstring)", arg_count=5)
|
||||
345 | def test_missing_args_class_method(cls, test, x, y, _, z=3): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
346 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:358:9: D417 Missing argument descriptions in the docstring for `test_missing_args_static_method`: `a`, `y`, `z`
|
||||
|
|
||||
356 | "(argument(s) a, y, z are missing descriptions in "
|
||||
357 | "'test_missing_args_static_method' docstring)", arg_count=4)
|
||||
358 | def test_missing_args_static_method(a, x, y, _test, z=3): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
359 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:370:9: D417 Missing argument descriptions in the docstring for `test_missing_docstring`: `a`, `b`
|
||||
|
|
||||
368 | "(argument(s) a, b are missing descriptions in "
|
||||
369 | "'test_missing_docstring' docstring)", arg_count=2)
|
||||
370 | def test_missing_docstring(a, b): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
371 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:398:5: D417 Missing argument description in the docstring for `test_missing_numpy_args`: `y`
|
||||
|
|
||||
396 | "(argument(s) y are missing descriptions in "
|
||||
397 | "'test_missing_numpy_args' docstring)")
|
||||
398 | def test_missing_numpy_args(_private_arg=0, x=1, y=2): # noqa: D406, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
399 | """Toggle the gizmo.
|
||||
|
|
||||
|
||||
sections.py:434:9: D417 Missing argument descriptions in the docstring for `test_missing_args`: `test`, `y`, `z`
|
||||
|
|
||||
432 | "(argument(s) test, y, z are missing descriptions in "
|
||||
433 | "'test_missing_args' docstring)", arg_count=5)
|
||||
434 | def test_missing_args(self, test, x, y, z=3, t=1, _private=0): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^ D417
|
||||
435 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:449:9: D417 Missing argument descriptions in the docstring for `test_missing_args_class_method`: `test`, `y`, `z`
|
||||
|
|
||||
447 | "(argument(s) test, y, z are missing descriptions in "
|
||||
448 | "'test_missing_args_class_method' docstring)", arg_count=4)
|
||||
449 | def test_missing_args_class_method(cls, test, x, y, z=3): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
450 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:468:9: D417 Missing argument descriptions in the docstring for `test_missing_args_static_method`: `a`, `z`
|
||||
|
|
||||
466 | "(argument(s) a, z are missing descriptions in "
|
||||
467 | "'test_missing_args_static_method' docstring)", arg_count=3)
|
||||
468 | def test_missing_args_static_method(a, x, y, z=3, t=1): # noqa: D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
469 | """Test a valid args section.
|
||||
|
|
||||
|
||||
sections.py:498:9: D417 Missing argument description in the docstring for `test_incorrect_indent`: `y`
|
||||
|
|
||||
496 | "(argument(s) y are missing descriptions in "
|
||||
497 | "'test_incorrect_indent' docstring)", arg_count=3)
|
||||
498 | def test_incorrect_indent(self, x=1, y=2): # noqa: D207, D213, D407
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ D417
|
||||
499 | """Reproducing issue #437.
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:34:9: D418 Function decorated with `@overload` shouldn't contain a docstring
|
||||
|
|
||||
33 | @overload
|
||||
34 | def overloaded_method(self, a: str) -> str:
|
||||
| ^^^^^^^^^^^^^^^^^ D418
|
||||
35 | """Foo bar documentation."""
|
||||
36 | ...
|
||||
|
|
||||
|
||||
D.py:90:9: D418 Function decorated with `@overload` shouldn't contain a docstring
|
||||
|
|
||||
89 | @overload
|
||||
90 | def nested_overloaded_func(a: str) -> str:
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ D418
|
||||
91 | """Foo bar documentation."""
|
||||
92 | ...
|
||||
|
|
||||
|
||||
D.py:110:5: D418 Function decorated with `@overload` shouldn't contain a docstring
|
||||
|
|
||||
109 | @overload
|
||||
110 | def overloaded_func(a: str) -> str:
|
||||
| ^^^^^^^^^^^^^^^ D418
|
||||
111 | """Foo bar documentation."""
|
||||
112 | ...
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D.py:20:9: D419 Docstring is empty
|
||||
|
|
||||
19 | class meta:
|
||||
20 | """"""
|
||||
| ^^^^^^ D419
|
||||
21 |
|
||||
22 | @expect('D102: Missing docstring in public method')
|
||||
|
|
||||
|
||||
D.py:74:5: D419 Docstring is empty
|
||||
|
|
||||
72 | @expect('D419: Docstring is empty')
|
||||
73 | def function():
|
||||
74 | """ """
|
||||
| ^^^^^^^ D419
|
||||
75 | def ok_since_nested():
|
||||
76 | pass
|
||||
|
|
||||
|
||||
D.py:80:9: D419 Docstring is empty
|
||||
|
|
||||
78 | @expect('D419: Docstring is empty')
|
||||
79 | def nested():
|
||||
80 | ''
|
||||
| ^^ D419
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
all.py:1:1: D100 Missing docstring in public module
|
||||
|
|
||||
1 | def public_func():
|
||||
| D100
|
||||
2 | pass
|
||||
|
|
||||
|
||||
all.py:1:5: D103 Missing docstring in public function
|
||||
|
|
||||
1 | def public_func():
|
||||
| ^^^^^^^^^^^ D103
|
||||
2 | pass
|
||||
|
|
||||
|
||||
all.py:9:7: D101 Missing docstring in public class
|
||||
|
|
||||
9 | class PublicClass:
|
||||
| ^^^^^^^^^^^ D101
|
||||
10 | class PublicNestedClass:
|
||||
11 | pass
|
||||
|
|
||||
|
||||
all.py:10:11: D106 Missing docstring in public nested class
|
||||
|
|
||||
9 | class PublicClass:
|
||||
10 | class PublicNestedClass:
|
||||
| ^^^^^^^^^^^^^^^^^ D106
|
||||
11 | pass
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
bom.py:1:1: D300 Use triple double quotes `"""`
|
||||
|
|
||||
1 | ''' SAM macro definitions '''
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D300
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
D209_D400.py:2:5: D209 [*] Multi-line docstring closing quotes should be on a separate line
|
||||
|
|
||||
1 | def lorem():
|
||||
2 | """lorem ipsum dolor sit amet consectetur adipiscing elit
|
||||
| _____^
|
||||
3 | | sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"""
|
||||
| |________________________________________________________________________^ D209
|
||||
|
|
||||
= help: Move closing quotes to new line
|
||||
|
||||
ℹ Fix
|
||||
1 1 | def lorem():
|
||||
2 2 | """lorem ipsum dolor sit amet consectetur adipiscing elit
|
||||
3 |- sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"""
|
||||
3 |+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua
|
||||
4 |+ """
|
||||
|
||||
D209_D400.py:2:5: D400 [*] First line should end with a period
|
||||
|
|
||||
1 | def lorem():
|
||||
2 | """lorem ipsum dolor sit amet consectetur adipiscing elit
|
||||
| _____^
|
||||
3 | | sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"""
|
||||
| |________________________________________________________________________^ D400
|
||||
|
|
||||
= help: Add period
|
||||
|
||||
ℹ Suggested fix
|
||||
1 1 | def lorem():
|
||||
2 2 | """lorem ipsum dolor sit amet consectetur adipiscing elit
|
||||
3 |- sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"""
|
||||
3 |+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."""
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
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.
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
|
||||
---
|
||||
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.
|
||||
|
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue