diff --git a/README.md b/README.md index e135e10b40..641a58447d 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ ruff also implements some of the most popular Flake8 plugins natively, including - [`flake8-print`](https://pypi.org/project/flake8-print/) - [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) (11/16) - [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (3/32) -- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (6/47) +- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (11/47) - [`pyupgrade`](https://pypi.org/project/pyupgrade/) (8/34) Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8: @@ -304,12 +304,17 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com | U006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | | 🛠 | | U007 | UsePEP604Annotation | Use `X \| Y` for type annotations | | 🛠 | | U008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | | 🛠 | -| D200 | OneLinerDocstring | One-line docstring should fit on one line | | | -| D205 | BlankLineAfterSummary | 1 blank line required between summary line and description | | | +| D200 | FitsOnOneLine | One-line docstring should fit on one line | | | +| D205 | NoBlankLineAfterSummary | 1 blank line required between summary line and description | | | | D209 | NewLineAfterLastParagraph | Multi-line docstring closing quotes should be on a separate line | | | | D210 | NoSurroundingWhitespace | No whitespaces allowed surrounding docstring text | | | -| D400 | DocstringEndsInNonPeriod | First line should end with a period | | | -| D419 | EmptyDocstring | Docstring is empty | | | +| D212 | MultiLineSummaryFirstLine | Multi-line docstring summary should start at the first line | | | +| D213 | MultiLineSummarySecondLine | Multi-line docstring summary should start at the second line | | | +| D300 | UsesTripleQuotes | Use """triple double quotes""" | | | +| D400 | EndsInPeriod | First line should end with a period | | | +| D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | | | +| D415 | EndsInPunctuation | First line should end with a period, question mark, or exclamation point | | | +| D419 | NonEmpty | Docstring is empty | | | | M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 | ## Integrations diff --git a/src/check_ast.rs b/src/check_ast.rs index a761063718..283b2de762 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -1902,9 +1902,23 @@ impl<'a> Checker<'a> { if self.settings.enabled.contains(&CheckCode::D210) { docstrings::no_surrounding_whitespace(self, &docstring); } + if self.settings.enabled.contains(&CheckCode::D212) + || self.settings.enabled.contains(&CheckCode::D213) + { + docstrings::multi_line_summary_start(self, &docstring); + } + if self.settings.enabled.contains(&CheckCode::D300) { + docstrings::triple_quotes(self, &docstring); + } if self.settings.enabled.contains(&CheckCode::D400) { docstrings::ends_with_period(self, &docstring); } + if self.settings.enabled.contains(&CheckCode::D403) { + docstrings::capitalized(self, &docstring); + } + if self.settings.enabled.contains(&CheckCode::D415) { + docstrings::ends_with_punctuation(self, &docstring); + } if self.settings.enabled.contains(&CheckCode::D419) { docstrings::not_empty(self, &docstring); } diff --git a/src/checks.rs b/src/checks.rs index a8415f909a..2abd2ccd6b 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -155,7 +155,12 @@ pub enum CheckCode { D205, D209, D210, + D212, + D213, + D300, D400, + D403, + D415, D419, // Meta M001, @@ -254,12 +259,17 @@ pub enum CheckKind { UsePEP604Annotation, SuperCallWithParameters, // pydocstyle - OneLinerDocstring, - BlankLineAfterSummary, + EndsInPeriod, + EndsInPunctuation, + FirstLineCapitalized, + FitsOnOneLine, + MultiLineSummaryFirstLine, + MultiLineSummarySecondLine, NewLineAfterLastParagraph, + NoBlankLineAfterSummary, NoSurroundingWhitespace, - EmptyDocstring, - DocstringEndsInNonPeriod, + NonEmpty, + UsesTripleQuotes, // Meta UnusedNOQA(Option>), } @@ -369,12 +379,17 @@ impl CheckCode { CheckCode::U007 => CheckKind::UsePEP604Annotation, CheckCode::U008 => CheckKind::SuperCallWithParameters, // pydocstyle - CheckCode::D200 => CheckKind::OneLinerDocstring, - CheckCode::D205 => CheckKind::BlankLineAfterSummary, + CheckCode::D200 => CheckKind::FitsOnOneLine, + CheckCode::D205 => CheckKind::NoBlankLineAfterSummary, CheckCode::D209 => CheckKind::NewLineAfterLastParagraph, CheckCode::D210 => CheckKind::NoSurroundingWhitespace, - CheckCode::D400 => CheckKind::DocstringEndsInNonPeriod, - CheckCode::D419 => CheckKind::EmptyDocstring, + CheckCode::D400 => CheckKind::EndsInPeriod, + CheckCode::D419 => CheckKind::NonEmpty, + CheckCode::D212 => CheckKind::MultiLineSummaryFirstLine, + CheckCode::D213 => CheckKind::MultiLineSummarySecondLine, + CheckCode::D300 => CheckKind::UsesTripleQuotes, + CheckCode::D403 => CheckKind::FirstLineCapitalized, + CheckCode::D415 => CheckKind::EndsInPunctuation, // Meta CheckCode::M001 => CheckKind::UnusedNOQA(None), } @@ -463,12 +478,17 @@ impl CheckKind { CheckKind::UselessObjectInheritance(_) => &CheckCode::U004, CheckKind::SuperCallWithParameters => &CheckCode::U008, // pydocstyle - CheckKind::OneLinerDocstring => &CheckCode::D200, - CheckKind::BlankLineAfterSummary => &CheckCode::D205, + CheckKind::FitsOnOneLine => &CheckCode::D200, + CheckKind::NoBlankLineAfterSummary => &CheckCode::D205, CheckKind::NewLineAfterLastParagraph => &CheckCode::D209, CheckKind::NoSurroundingWhitespace => &CheckCode::D210, - CheckKind::DocstringEndsInNonPeriod => &CheckCode::D400, - CheckKind::EmptyDocstring => &CheckCode::D419, + CheckKind::EndsInPeriod => &CheckCode::D400, + CheckKind::NonEmpty => &CheckCode::D419, + CheckKind::MultiLineSummaryFirstLine => &CheckCode::D212, + CheckKind::MultiLineSummarySecondLine => &CheckCode::D213, + CheckKind::UsesTripleQuotes => &CheckCode::D300, + CheckKind::FirstLineCapitalized => &CheckCode::D403, + CheckKind::EndsInPunctuation => &CheckCode::D415, // Meta CheckKind::UnusedNOQA(_) => &CheckCode::M001, } @@ -713,8 +733,8 @@ impl CheckKind { "Use `super()` instead of `super(__class__, self)`".to_string() } // pydocstyle - CheckKind::OneLinerDocstring => "One-line docstring should fit on one line".to_string(), - CheckKind::BlankLineAfterSummary => { + CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(), + CheckKind::NoBlankLineAfterSummary => { "1 blank line required between summary line and description".to_string() } CheckKind::NewLineAfterLastParagraph => { @@ -723,10 +743,22 @@ impl CheckKind { CheckKind::NoSurroundingWhitespace => { "No whitespaces allowed surrounding docstring text".to_string() } - CheckKind::DocstringEndsInNonPeriod => { - "First line should end with a period".to_string() + CheckKind::EndsInPeriod => "First line should end with a period".to_string(), + CheckKind::NonEmpty => "Docstring is empty".to_string(), + CheckKind::EndsInPunctuation => { + "First line should end with a period, question mark, or exclamation point" + .to_string() + } + CheckKind::FirstLineCapitalized => { + "First word of the first line should be properly capitalized".to_string() + } + CheckKind::UsesTripleQuotes => r#"Use """triple double quotes""""#.to_string(), + CheckKind::MultiLineSummaryFirstLine => { + "Multi-line docstring summary should start at the first line".to_string() + } + CheckKind::MultiLineSummarySecondLine => { + "Multi-line docstring summary should start at the second line".to_string() } - CheckKind::EmptyDocstring => "Docstring is empty".to_string(), // Meta CheckKind::UnusedNOQA(codes) => match codes { None => "Unused `noqa` directive".to_string(), diff --git a/src/docstrings.rs b/src/docstrings.rs index 4e2e6cc32f..7341588a9d 100644 --- a/src/docstrings.rs +++ b/src/docstrings.rs @@ -1,7 +1,8 @@ +use rustpython_ast::{Constant, Expr, ExprKind, Location, Stmt, StmtKind}; + use crate::ast::types::Range; use crate::check_ast::Checker; -use crate::checks::{Check, CheckKind}; -use rustpython_ast::{Constant, Expr, ExprKind, Stmt, StmtKind}; +use crate::checks::{Check, CheckCode, CheckKind}; #[derive(Debug)] pub enum DocstringKind { @@ -17,7 +18,7 @@ pub struct Docstring<'a> { pub expr: &'a Expr, } -/// Extract a docstring from an expression. +/// Extract a `Docstring` from an `Expr`. pub fn extract<'a, 'b>( checker: &'a Checker, stmt: &'b Stmt, @@ -27,7 +28,6 @@ pub fn extract<'a, 'b>( .binding_context() .defined_in .map(|index| checker.parents[index]); - match defined_in { None => { if checker.initial { @@ -61,6 +61,19 @@ pub fn extract<'a, 'b>( None } +/// Extract the source code range for a `Docstring`. +fn range_for(docstring: &Docstring) -> Range { + // RustPython currently omits the first quotation mark in a string, so offset the location. + Range { + location: Location::new( + docstring.expr.location.row(), + docstring.expr.location.column() - 1, + ), + end_location: docstring.expr.end_location, + } +} + +/// D200 pub fn one_liner(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), @@ -80,14 +93,12 @@ pub fn one_liner(checker: &mut Checker, docstring: &Docstring) { } if non_empty_line_count == 1 && line_count > 1 { - checker.add_check(Check::new( - CheckKind::OneLinerDocstring, - Range::from_located(docstring.expr), - )); + checker.add_check(Check::new(CheckKind::FitsOnOneLine, range_for(docstring))); } } } +/// D205 pub fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), @@ -106,13 +117,14 @@ pub fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) { } if lines_count > 1 && blanks_count != 1 { checker.add_check(Check::new( - CheckKind::BlankLineAfterSummary, - Range::from_located(docstring.expr), + CheckKind::NoBlankLineAfterSummary, + range_for(docstring), )); } } } +/// D209 pub fn newline_after_last_paragraph(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), @@ -127,13 +139,13 @@ pub fn newline_after_last_paragraph(checker: &mut Checker, docstring: &Docstring if line_count > 1 { let content = checker .locator - .slice_source_code_range(&Range::from_located(docstring.expr)); + .slice_source_code_range(&range_for(docstring)); if let Some(line) = content.lines().last() { let line = line.trim(); if line != "\"\"\"" && line != "'''" { checker.add_check(Check::new( CheckKind::NewLineAfterLastParagraph, - Range::from_located(docstring.expr), + range_for(docstring), )); } } @@ -143,6 +155,7 @@ pub fn newline_after_last_paragraph(checker: &mut Checker, docstring: &Docstring } } +/// D210 pub fn no_surrounding_whitespace(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), @@ -154,32 +167,82 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, docstring: &Docstring) { if line.trim().is_empty() { return; } - if line.starts_with(' ') || (matches!(lines.next(), None) && line.ends_with(' ')) { checker.add_check(Check::new( CheckKind::NoSurroundingWhitespace, - Range::from_located(docstring.expr), + range_for(docstring), )); } } } } -pub fn not_empty(checker: &mut Checker, docstring: &Docstring) { +/// D212, D213 +pub fn multi_line_summary_start(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), .. } = &docstring.expr.node { - if string.trim().is_empty() { + if string.lines().nth(1).is_some() { + let content = checker + .locator + .slice_source_code_range(&range_for(docstring)); + if let Some(first_line) = content.lines().next() { + let first_line = first_line.trim(); + if first_line == "\"\"\"" + || first_line == "'''" + || first_line == "u\"\"\"" + || first_line == "u'''" + || first_line == "r\"\"\"" + || first_line == "r'''" + || first_line == "ur\"\"\"" + || first_line == "ur'''" + { + if checker.settings.enabled.contains(&CheckCode::D212) { + checker.add_check(Check::new( + CheckKind::MultiLineSummaryFirstLine, + range_for(docstring), + )); + } + } else if checker.settings.enabled.contains(&CheckCode::D213) { + checker.add_check(Check::new( + CheckKind::MultiLineSummarySecondLine, + range_for(docstring), + )); + } + } + } + } +} + +/// D300 +pub fn triple_quotes(checker: &mut Checker, docstring: &Docstring) { + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + let content = checker + .locator + .slice_source_code_range(&range_for(docstring)); + if string.contains("\"\"\"") { + if !content.starts_with("'''") { + checker.add_check(Check::new( + CheckKind::UsesTripleQuotes, + range_for(docstring), + )); + } + } else if !content.starts_with("\"\"\"") { checker.add_check(Check::new( - CheckKind::EmptyDocstring, - Range::from_located(docstring.expr), + CheckKind::UsesTripleQuotes, + range_for(docstring), )); } } } +/// D400 pub fn ends_with_period(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), @@ -188,11 +251,71 @@ pub fn ends_with_period(checker: &mut Checker, docstring: &Docstring) { { if let Some(string) = string.lines().next() { if !string.ends_with('.') { + checker.add_check(Check::new(CheckKind::EndsInPeriod, range_for(docstring))); + } + } + } +} + +/// D403 +pub fn capitalized(checker: &mut Checker, docstring: &Docstring) { + if !matches!(docstring.kind, DocstringKind::Function) { + return; + } + + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + if let Some(first_word) = string.split(' ').next() { + if first_word == first_word.to_uppercase() { + return; + } + for char in first_word.chars() { + if !char.is_ascii_alphabetic() && char != '\'' { + return; + } + } + if let Some(first_char) = first_word.chars().next() { + if !first_char.is_uppercase() { + checker.add_check(Check::new( + CheckKind::FirstLineCapitalized, + range_for(docstring), + )); + } + } + } + } +} + +/// D415 +pub fn ends_with_punctuation(checker: &mut Checker, docstring: &Docstring) { + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + if let Some(string) = string.lines().next() { + if !(string.ends_with('.') || string.ends_with('!') || string.ends_with('?')) { checker.add_check(Check::new( - CheckKind::DocstringEndsInNonPeriod, - Range::from_located(docstring.expr), + CheckKind::EndsInPunctuation, + range_for(docstring), )); } } } } + +/// D419 +pub fn not_empty(checker: &mut Checker, docstring: &Docstring) { + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + if string.trim().is_empty() { + checker.add_check(Check::new(CheckKind::NonEmpty, range_for(docstring))); + } + } +} diff --git a/src/linter.rs b/src/linter.rs index 2ddc6dedc2..6ac4985c57 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -1056,6 +1056,42 @@ mod tests { Ok(()) } + #[test] + fn d212() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D212), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + + #[test] + fn d213() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D213), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + + #[test] + fn d300() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D300), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + #[test] fn d400() -> Result<()> { let mut checks = check_path( @@ -1068,6 +1104,30 @@ mod tests { Ok(()) } + #[test] + fn d403() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D403), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + + #[test] + fn d415() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D415), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + #[test] fn d419() -> Result<()> { let mut checks = check_path( diff --git a/src/snapshots/ruff__linter__tests__d200.snap b/src/snapshots/ruff__linter__tests__d200.snap index a1bfad3481..bc4feeb2f6 100644 --- a/src/snapshots/ruff__linter__tests__d200.snap +++ b/src/snapshots/ruff__linter__tests__d200.snap @@ -5,7 +5,7 @@ expression: checks - kind: OneLinerDocstring location: row: 124 - column: 6 + column: 5 end_location: row: 126 column: 8 diff --git a/src/snapshots/ruff__linter__tests__d205.snap b/src/snapshots/ruff__linter__tests__d205.snap index 25466524ac..a08d1cd71e 100644 --- a/src/snapshots/ruff__linter__tests__d205.snap +++ b/src/snapshots/ruff__linter__tests__d205.snap @@ -5,7 +5,7 @@ expression: checks - kind: BlankLineAfterSummary location: row: 195 - column: 6 + column: 5 end_location: row: 198 column: 8 @@ -13,7 +13,7 @@ expression: checks - kind: BlankLineAfterSummary location: row: 205 - column: 6 + column: 5 end_location: row: 210 column: 8 diff --git a/src/snapshots/ruff__linter__tests__d209.snap b/src/snapshots/ruff__linter__tests__d209.snap index 58928106f0..794d303ec2 100644 --- a/src/snapshots/ruff__linter__tests__d209.snap +++ b/src/snapshots/ruff__linter__tests__d209.snap @@ -5,7 +5,7 @@ expression: checks - kind: NewLineAfterLastParagraph location: row: 276 - column: 6 + column: 5 end_location: row: 278 column: 20 diff --git a/src/snapshots/ruff__linter__tests__d210.snap b/src/snapshots/ruff__linter__tests__d210.snap index 6d7df49a64..743d95c59e 100644 --- a/src/snapshots/ruff__linter__tests__d210.snap +++ b/src/snapshots/ruff__linter__tests__d210.snap @@ -5,7 +5,7 @@ expression: checks - kind: NoSurroundingWhitespace location: row: 283 - column: 6 + column: 5 end_location: row: 283 column: 34 @@ -13,7 +13,7 @@ expression: checks - kind: NoSurroundingWhitespace location: row: 288 - column: 6 + column: 5 end_location: row: 288 column: 38 @@ -21,7 +21,7 @@ expression: checks - kind: NoSurroundingWhitespace location: row: 294 - column: 6 + column: 5 end_location: row: 297 column: 8 diff --git a/src/snapshots/ruff__linter__tests__d212.snap b/src/snapshots/ruff__linter__tests__d212.snap new file mode 100644 index 0000000000..dafdf14226 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d212.snap @@ -0,0 +1,13 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: MultiLineSummaryFirstLine + location: + row: 124 + column: 5 + end_location: + row: 126 + column: 8 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d213.snap b/src/snapshots/ruff__linter__tests__d213.snap new file mode 100644 index 0000000000..508b0df6c9 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d213.snap @@ -0,0 +1,133 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: MultiLineSummarySecondLine + location: + row: 195 + column: 5 + end_location: + row: 198 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 205 + column: 5 + end_location: + row: 210 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 215 + column: 5 + end_location: + row: 219 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 225 + column: 5 + end_location: + row: 229 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 235 + column: 5 + end_location: + row: 239 + column: 4 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 245 + column: 5 + end_location: + row: 249 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 255 + column: 5 + end_location: + row: 259 + column: 12 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 265 + column: 5 + end_location: + row: 269 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 276 + column: 5 + end_location: + row: 278 + column: 20 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 294 + column: 5 + end_location: + row: 297 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 338 + column: 5 + end_location: + row: 343 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 378 + column: 5 + end_location: + row: 381 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 387 + column: 5 + end_location: + row: 391 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 433 + column: 37 + end_location: + row: 436 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 445 + column: 5 + end_location: + row: 449 + column: 8 + fix: ~ +- kind: MultiLineSummarySecondLine + location: + row: 521 + column: 5 + end_location: + row: 527 + column: 8 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d300.snap b/src/snapshots/ruff__linter__tests__d300.snap new file mode 100644 index 0000000000..cedc1fd8d4 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d300.snap @@ -0,0 +1,53 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: TripleQuotes + location: + row: 75 + column: 9 + end_location: + row: 75 + column: 11 + fix: ~ +- kind: TripleQuotes + location: + row: 302 + column: 6 + end_location: + row: 302 + column: 20 + fix: ~ +- kind: TripleQuotes + location: + row: 307 + column: 6 + end_location: + row: 307 + column: 20 + fix: ~ +- kind: TripleQuotes + location: + row: 312 + column: 6 + end_location: + row: 312 + column: 16 + fix: ~ +- kind: TripleQuotes + location: + row: 317 + column: 6 + end_location: + row: 317 + column: 16 + fix: ~ +- kind: TripleQuotes + location: + row: 323 + column: 6 + end_location: + row: 323 + column: 17 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d400.snap b/src/snapshots/ruff__linter__tests__d400.snap index 729f010063..e62dcc20d1 100644 --- a/src/snapshots/ruff__linter__tests__d400.snap +++ b/src/snapshots/ruff__linter__tests__d400.snap @@ -5,7 +5,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 69 - column: 6 + column: 5 end_location: row: 69 column: 12 @@ -13,7 +13,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 124 - column: 6 + column: 5 end_location: row: 126 column: 8 @@ -21,7 +21,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 283 - column: 6 + column: 5 end_location: row: 283 column: 34 @@ -29,7 +29,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 288 - column: 6 + column: 5 end_location: row: 288 column: 38 @@ -37,7 +37,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 350 - column: 6 + column: 5 end_location: row: 350 column: 18 @@ -45,7 +45,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 401 - column: 26 + column: 25 end_location: row: 401 column: 40 @@ -53,7 +53,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 405 - column: 6 + column: 5 end_location: row: 405 column: 25 @@ -61,7 +61,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 411 - column: 6 + column: 5 end_location: row: 411 column: 25 @@ -69,7 +69,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 417 - column: 36 + column: 35 end_location: row: 417 column: 50 @@ -77,7 +77,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 424 - column: 50 + column: 49 end_location: row: 424 column: 64 @@ -85,7 +85,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 465 - column: 6 + column: 5 end_location: row: 465 column: 25 @@ -93,7 +93,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 470 - column: 6 + column: 5 end_location: row: 470 column: 25 @@ -101,7 +101,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 475 - column: 6 + column: 5 end_location: row: 475 column: 25 @@ -109,7 +109,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 482 - column: 6 + column: 5 end_location: row: 482 column: 25 @@ -117,7 +117,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 504 - column: 6 + column: 5 end_location: row: 504 column: 35 @@ -125,7 +125,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 509 - column: 6 + column: 5 end_location: row: 509 column: 34 @@ -133,7 +133,7 @@ expression: checks - kind: DocstringEndsInNonPeriod location: row: 515 - column: 6 + column: 5 end_location: row: 515 column: 33 diff --git a/src/snapshots/ruff__linter__tests__d403.snap b/src/snapshots/ruff__linter__tests__d403.snap new file mode 100644 index 0000000000..60c615f917 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d403.snap @@ -0,0 +1,6 @@ +--- +source: src/linter.rs +expression: checks +--- +[] + diff --git a/src/snapshots/ruff__linter__tests__d415.snap b/src/snapshots/ruff__linter__tests__d415.snap new file mode 100644 index 0000000000..db141df312 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d415.snap @@ -0,0 +1,133 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: DocstringEndsInNonPunctuation + location: + row: 69 + column: 5 + end_location: + row: 69 + column: 12 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 124 + column: 5 + end_location: + row: 126 + column: 8 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 283 + column: 5 + end_location: + row: 283 + column: 34 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 288 + column: 5 + end_location: + row: 288 + column: 38 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 350 + column: 5 + end_location: + row: 350 + column: 18 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 401 + column: 25 + end_location: + row: 401 + column: 40 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 405 + column: 5 + end_location: + row: 405 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 411 + column: 5 + end_location: + row: 411 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 417 + column: 35 + end_location: + row: 417 + column: 50 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 424 + column: 49 + end_location: + row: 424 + column: 64 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 465 + column: 5 + end_location: + row: 465 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 470 + column: 5 + end_location: + row: 470 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 475 + column: 5 + end_location: + row: 475 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 482 + column: 5 + end_location: + row: 482 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 504 + column: 5 + end_location: + row: 504 + column: 35 + fix: ~ +- kind: DocstringEndsInNonPunctuation + location: + row: 515 + column: 5 + end_location: + row: 515 + column: 33 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d419.snap b/src/snapshots/ruff__linter__tests__d419.snap index cf331f9771..b236d8a8b7 100644 --- a/src/snapshots/ruff__linter__tests__d419.snap +++ b/src/snapshots/ruff__linter__tests__d419.snap @@ -5,7 +5,7 @@ expression: checks - kind: EmptyDocstring location: row: 19 - column: 10 + column: 9 end_location: row: 19 column: 15 @@ -13,7 +13,7 @@ expression: checks - kind: EmptyDocstring location: row: 69 - column: 6 + column: 5 end_location: row: 69 column: 12 @@ -21,7 +21,7 @@ expression: checks - kind: EmptyDocstring location: row: 75 - column: 10 + column: 9 end_location: row: 75 column: 11