diff --git a/README.md b/README.md index ab057bc557..93f53bb823 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/) (2/47) +- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (6/47) - [`pyupgrade`](https://pypi.org/project/pyupgrade/) (partial) Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8: @@ -304,6 +304,10 @@ 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 | | | +| 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 | | | | M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 | diff --git a/resources/test/fixtures/D.py b/resources/test/fixtures/D.py new file mode 100644 index 0000000000..1cbd8ec4c9 --- /dev/null +++ b/resources/test/fixtures/D.py @@ -0,0 +1,534 @@ +# No docstring, so we can test D100 +from functools import wraps +import os +from .expected import Expectation +from typing import overload + + +expectation = Expectation() +expect = expectation.expect + +expect('class_', 'D101: Missing docstring in public class') + + +class class_: + + expect('meta', 'D419: Docstring is empty') + + class meta: + """""" + + @expect('D102: Missing docstring in public method') + def method(self=None): + pass + + def _ok_since_private(self=None): + pass + + @overload + def overloaded_method(self, a: int) -> str: + ... + + @overload + def overloaded_method(self, a: str) -> str: + """Foo bar documentation.""" + ... + + def overloaded_method(a): + """Foo bar documentation.""" + return str(a) + + expect('overloaded_method', + "D418: Function/ Method decorated with @overload" + " shouldn't contain a docstring") + + @property + def foo(self): + """The foo of the thing, which isn't in imperitive mood.""" + return "hello" + + @expect('D102: Missing docstring in public method') + def __new__(self=None): + pass + + @expect('D107: Missing docstring in __init__') + def __init__(self=None): + pass + + @expect('D105: Missing docstring in magic method') + def __str__(self=None): + pass + + @expect('D102: Missing docstring in public method') + def __call__(self=None, x=None, y=None, z=None): + pass + + +@expect('D419: Docstring is empty') +def function(): + """ """ + def ok_since_nested(): + pass + + @expect('D419: Docstring is empty') + def nested(): + '' + + +def function_with_nesting(): + """Foo bar documentation.""" + @overload + def nested_overloaded_func(a: int) -> str: + ... + + @overload + def nested_overloaded_func(a: str) -> str: + """Foo bar documentation.""" + ... + + def nested_overloaded_func(a): + """Foo bar documentation.""" + return str(a) + + +expect('nested_overloaded_func', + "D418: Function/ Method decorated with @overload" + " shouldn't contain a docstring") + + +@overload +def overloaded_func(a: int) -> str: + ... + + +@overload +def overloaded_func(a: str) -> str: + """Foo bar documentation.""" + ... + + +def overloaded_func(a): + """Foo bar documentation.""" + return str(a) + + +expect('overloaded_func', + "D418: Function/ Method decorated with @overload" + " shouldn't contain a docstring") + + +@expect('D200: One-line docstring should fit on one line with quotes ' + '(found 3)') +@expect('D212: Multi-line docstring summary should start at the first line') +def asdlkfasd(): + """ + Wrong. + """ + + +@expect('D201: No blank lines allowed before function docstring (found 1)') +def leading_space(): + + """Leading space.""" + + +@expect('D202: No blank lines allowed after function docstring (found 1)') +def trailing_space(): + """Leading space.""" + + pass + + +@expect('D201: No blank lines allowed before function docstring (found 1)') +@expect('D202: No blank lines allowed after function docstring (found 1)') +def trailing_and_leading_space(): + + """Trailing and leading space.""" + + pass + + +expect('LeadingSpaceMissing', + 'D203: 1 blank line required before class docstring (found 0)') + + +class LeadingSpaceMissing: + """Leading space missing.""" + + +expect('WithLeadingSpace', + 'D211: No blank lines allowed before class docstring (found 1)') + + +class WithLeadingSpace: + + """With leading space.""" + + +expect('TrailingSpace', + 'D204: 1 blank line required after class docstring (found 0)') +expect('TrailingSpace', + 'D211: No blank lines allowed before class docstring (found 1)') + + +class TrailingSpace: + + """TrailingSpace.""" + pass + + +expect('LeadingAndTrailingSpaceMissing', + 'D203: 1 blank line required before class docstring (found 0)') +expect('LeadingAndTrailingSpaceMissing', + 'D204: 1 blank line required after class docstring (found 0)') + + +class LeadingAndTrailingSpaceMissing: + """Leading and trailing space missing.""" + pass + + +@expect('D205: 1 blank line required between summary line and description ' + '(found 0)') +@expect('D213: Multi-line docstring summary should start at the second line') +def multi_line_zero_separating_blanks(): + """Summary. + Description. + + """ + + +@expect('D205: 1 blank line required between summary line and description ' + '(found 2)') +@expect('D213: Multi-line docstring summary should start at the second line') +def multi_line_two_separating_blanks(): + """Summary. + + + Description. + + """ + + +@expect('D213: Multi-line docstring summary should start at the second line') +def multi_line_one_separating_blanks(): + """Summary. + + Description. + + """ + + +@expect('D207: Docstring is under-indented') +@expect('D213: Multi-line docstring summary should start at the second line') +def asdfsdf(): + """Summary. + +Description. + + """ + + +@expect('D207: Docstring is under-indented') +@expect('D213: Multi-line docstring summary should start at the second line') +def asdsdfsdffsdf(): + """Summary. + + Description. + +""" + + +@expect('D208: Docstring is over-indented') +@expect('D213: Multi-line docstring summary should start at the second line') +def asdfsdsdf24(): + """Summary. + + Description. + + """ + + +@expect('D208: Docstring is over-indented') +@expect('D213: Multi-line docstring summary should start at the second line') +def asdfsdsdfsdf24(): + """Summary. + + Description. + + """ + + +@expect('D208: Docstring is over-indented') +@expect('D213: Multi-line docstring summary should start at the second line') +def asdfsdfsdsdsdfsdf24(): + """Summary. + + Description. + + """ + + +@expect('D209: Multi-line docstring closing quotes should be on a separate ' + 'line') +@expect('D213: Multi-line docstring summary should start at the second line') +def asdfljdf24(): + """Summary. + + Description.""" + + +@expect('D210: No whitespaces allowed surrounding docstring text') +def endswith(): + """Whitespace at the end. """ + + +@expect('D210: No whitespaces allowed surrounding docstring text') +def around(): + """ Whitespace at everywhere. """ + + +@expect('D210: No whitespaces allowed surrounding docstring text') +@expect('D213: Multi-line docstring summary should start at the second line') +def multiline(): + """ Whitespace at the beginning. + + This is the end. + """ + + +@expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)') +def triple_single_quotes_raw(): + r'''Summary.''' + + +@expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)') +def triple_single_quotes_raw_uppercase(): + R'''Summary.''' + + +@expect('D300: Use """triple double quotes""" (found \'-quotes)') +def single_quotes_raw(): + r'Summary.' + + +@expect('D300: Use """triple double quotes""" (found \'-quotes)') +def single_quotes_raw_uppercase(): + R'Summary.' + + +@expect('D300: Use """triple double quotes""" (found \'-quotes)') +@expect('D301: Use r""" if any backslashes in a docstring') +def single_quotes_raw_uppercase_backslash(): + R'Sum\mary.' + + +@expect('D301: Use r""" if any backslashes in a docstring') +def double_quotes_backslash(): + """Sum\\mary.""" + + +@expect('D301: Use r""" if any backslashes in a docstring') +def double_quotes_backslash_uppercase(): + R"""Sum\\mary.""" + + +@expect('D213: Multi-line docstring summary should start at the second line') +def exceptions_of_D301(): + """Exclude some backslashes from D301. + + In particular, line continuations \ + and unicode literals \u0394 and \N{GREEK CAPITAL LETTER DELTA}. + They are considered to be intentionally unescaped. + """ + + +@expect("D400: First line should end with a period (not 'y')") +@expect("D415: First line should end with a period, question mark, " + "or exclamation point (not 'y')") +def lwnlkjl(): + """Summary""" + + +@expect("D401: First line should be in imperative mood " + "(perhaps 'Return', not 'Returns')") +def liouiwnlkjl(): + """Returns foo.""" + + +@expect("D401: First line should be in imperative mood; try rephrasing " + "(found 'Constructor')") +def sdgfsdg23245(): + """Constructor for a foo.""" + + +@expect("D401: First line should be in imperative mood; try rephrasing " + "(found 'Constructor')") +def sdgfsdg23245777(): + """Constructor.""" + + +@expect('D402: First line should not be the function\'s "signature"') +def foobar(): + """Signature: foobar().""" + + +@expect('D213: Multi-line docstring summary should start at the second line') +def new_209(): + """First line. + + More lines. + """ + pass + + +@expect('D213: Multi-line docstring summary should start at the second line') +def old_209(): + """One liner. + + Multi-line comments. OK to have extra blank line + + """ + + +@expect("D103: Missing docstring in public function") +def oneliner_d102(): return + + +@expect("D400: First line should end with a period (not 'r')") +@expect("D415: First line should end with a period, question mark," + " or exclamation point (not 'r')") +def oneliner_withdoc(): """One liner""" + + +def ignored_decorator(func): # noqa: D400,D401,D415 + """Runs something""" + func() + pass + + +def decorator_for_test(func): # noqa: D400,D401,D415 + """Runs something""" + func() + pass + + +@ignored_decorator +def oneliner_ignored_decorator(): """One liner""" + + +@decorator_for_test +@expect("D400: First line should end with a period (not 'r')") +@expect("D415: First line should end with a period, question mark," + " or exclamation point (not 'r')") +def oneliner_with_decorator_expecting_errors(): """One liner""" + + +@decorator_for_test +def valid_oneliner_with_decorator(): """One liner.""" + + +@expect("D207: Docstring is under-indented") +@expect('D213: Multi-line docstring summary should start at the second line') +def docstring_start_in_same_line(): """First Line. + + Second Line + """ + + +def function_with_lambda_arg(x=lambda y: y): + """Wrap the given lambda.""" + + +@expect('D213: Multi-line docstring summary should start at the second line') +def a_following_valid_function(x=None): + """Check for a bug where the previous function caused an assertion. + + The assertion was caused in the next function, so this one is necessary. + + """ + + +def outer_function(): + """Do something.""" + def inner_function(): + """Do inner something.""" + return 0 + + +@expect("D400: First line should end with a period (not 'g')") +@expect("D401: First line should be in imperative mood " + "(perhaps 'Run', not 'Runs')") +@expect("D415: First line should end with a period, question mark, " + "or exclamation point (not 'g')") +def docstring_bad(): + """Runs something""" + pass + + +def docstring_bad_ignore_all(): # noqa + """Runs something""" + pass + + +def docstring_bad_ignore_one(): # noqa: D400,D401,D415 + """Runs something""" + pass + + +@expect("D401: First line should be in imperative mood " + "(perhaps 'Run', not 'Runs')") +def docstring_ignore_some_violations_but_catch_D401(): # noqa: E501,D400,D415 + """Runs something""" + pass + + +@expect( + "D401: First line should be in imperative mood " + "(perhaps 'Initiate', not 'Initiates')" +) +def docstring_initiates(): + """Initiates the process.""" + + +@expect( + "D401: First line should be in imperative mood " + "(perhaps 'Initialize', not 'Initializes')" +) +def docstring_initializes(): + """Initializes the process.""" + + +@wraps(docstring_bad_ignore_one) +def bad_decorated_function(): + """Bad (E501) but decorated""" + pass + + +def valid_google_string(): # noqa: D400 + """Test a valid something!""" + + +@expect("D415: First line should end with a period, question mark, " + "or exclamation point (not 'g')") +def bad_google_string(): # noqa: D400 + """Test a valid something""" + + +# This is reproducing a bug where AttributeError is raised when parsing class +# parameters as functions for Google / Numpy conventions. +class Blah: # noqa: D203,D213 + """A Blah. + + Parameters + ---------- + x : int + + """ + + def __init__(self, x): + pass + + +expect(os.path.normcase(__file__ if __file__[-1] != 'c' else __file__[:-1]), + 'D100: Missing docstring in public module') diff --git a/resources/test/fixtures/D200.py b/resources/test/fixtures/D200.py deleted file mode 100644 index 9c44400e1a..0000000000 --- a/resources/test/fixtures/D200.py +++ /dev/null @@ -1,25 +0,0 @@ -def f(): - """ - Fail. - """ - - -def f(): - """Fail. - """ - - -def f(): - """ - Fail.""" - - -def f(): - """Pass.""" - - -def f(): - """Pass. - - More content here. - """ diff --git a/resources/test/fixtures/D400.py b/resources/test/fixtures/D400.py deleted file mode 100644 index 37b8ae9e1c..0000000000 --- a/resources/test/fixtures/D400.py +++ /dev/null @@ -1,27 +0,0 @@ -def f1() -> None: - """Hello, world. - - More content here. - """ - - -def f2() -> None: - """Hello, world! - - More content here. - """ - - -def f3() -> None: - """Hello, world - - More content here. - """ - - -def f4() -> None: - """.""" - - -def f5() -> None: - """""" diff --git a/resources/test/fixtures/D419.py b/resources/test/fixtures/D419.py deleted file mode 100644 index 7effbdf16f..0000000000 --- a/resources/test/fixtures/D419.py +++ /dev/null @@ -1,13 +0,0 @@ -"""""" - - -def f1() -> None: - """""" - - -def f2() -> None: - "" - - -def f3() -> None: - """Hello, world!""" diff --git a/src/check_ast.rs b/src/check_ast.rs index 4d13754b60..a761063718 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -1893,6 +1893,15 @@ impl<'a> Checker<'a> { if self.settings.enabled.contains(&CheckCode::D200) { docstrings::one_liner(self, &docstring); } + if self.settings.enabled.contains(&CheckCode::D205) { + docstrings::blank_after_summary(self, &docstring); + } + if self.settings.enabled.contains(&CheckCode::D209) { + docstrings::newline_after_last_paragraph(self, &docstring); + } + if self.settings.enabled.contains(&CheckCode::D210) { + docstrings::no_surrounding_whitespace(self, &docstring); + } if self.settings.enabled.contains(&CheckCode::D400) { docstrings::ends_with_period(self, &docstring); } diff --git a/src/checks.rs b/src/checks.rs index 239f90da30..57be7c65e8 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -152,6 +152,9 @@ pub enum CheckCode { U008, // pydocstyle D200, + D205, + D209, + D210, D400, D419, // Meta @@ -252,6 +255,9 @@ pub enum CheckKind { SuperCallWithParameters, // pydocstyle OneLinerDocstring, + BlankLineAfterSummary, + NewLineAfterLastParagraph, + NoSurroundingWhitespace, EmptyDocstring, DocstringEndsInNonPeriod, // Meta @@ -364,6 +370,9 @@ impl CheckCode { CheckCode::U008 => CheckKind::SuperCallWithParameters, // pydocstyle CheckCode::D200 => CheckKind::OneLinerDocstring, + CheckCode::D205 => CheckKind::BlankLineAfterSummary, + CheckCode::D209 => CheckKind::NewLineAfterLastParagraph, + CheckCode::D210 => CheckKind::NoSurroundingWhitespace, CheckCode::D400 => CheckKind::DocstringEndsInNonPeriod, CheckCode::D419 => CheckKind::EmptyDocstring, // Meta @@ -455,6 +464,9 @@ impl CheckKind { CheckKind::SuperCallWithParameters => &CheckCode::U008, // pydocstyle CheckKind::OneLinerDocstring => &CheckCode::D200, + CheckKind::BlankLineAfterSummary => &CheckCode::D205, + CheckKind::NewLineAfterLastParagraph => &CheckCode::D209, + CheckKind::NoSurroundingWhitespace => &CheckCode::D210, CheckKind::DocstringEndsInNonPeriod => &CheckCode::D400, CheckKind::EmptyDocstring => &CheckCode::D419, // Meta @@ -702,6 +714,15 @@ impl CheckKind { } // pydocstyle CheckKind::OneLinerDocstring => "One-line docstring should fit on one line".to_string(), + CheckKind::BlankLineAfterSummary => { + "1 blank line required between summary line and description".to_string() + } + CheckKind::NewLineAfterLastParagraph => { + "Multi-line docstring closing quotes should be on a separate line".to_string() + } + CheckKind::NoSurroundingWhitespace => { + "No whitespaces allowed surrounding docstring text".to_string() + } CheckKind::DocstringEndsInNonPeriod => { "First line should end with a period".to_string() } diff --git a/src/docstrings.rs b/src/docstrings.rs index fe256ea0a5..4e2e6cc32f 100644 --- a/src/docstrings.rs +++ b/src/docstrings.rs @@ -88,6 +88,83 @@ pub fn one_liner(checker: &mut Checker, docstring: &Docstring) { } } +pub fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) { + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + let mut lines_count = 1; + let mut blanks_count = 0; + for line in string.trim().lines().skip(1) { + lines_count += 1; + if line.trim().is_empty() { + blanks_count += 1; + } else { + break; + } + } + if lines_count > 1 && blanks_count != 1 { + checker.add_check(Check::new( + CheckKind::BlankLineAfterSummary, + Range::from_located(docstring.expr), + )); + } + } +} + +pub fn newline_after_last_paragraph(checker: &mut Checker, docstring: &Docstring) { + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + let mut line_count = 0; + for line in string.lines() { + if !line.trim().is_empty() { + line_count += 1; + } + if line_count > 1 { + let content = checker + .locator + .slice_source_code_range(&Range::from_located(docstring.expr)); + 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), + )); + } + } + return; + } + } + } +} + +pub fn no_surrounding_whitespace(checker: &mut Checker, docstring: &Docstring) { + if let ExprKind::Constant { + value: Constant::Str(string), + .. + } = &docstring.expr.node + { + let mut lines = string.lines(); + if let Some(line) = lines.next() { + 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), + )); + } + } + } +} + pub fn not_empty(checker: &mut Checker, docstring: &Docstring) { if let ExprKind::Constant { value: Constant::Str(string), diff --git a/src/linter.rs b/src/linter.rs index 17d3420760..fb8ed4aa33 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -981,7 +981,7 @@ mod tests { #[test] fn d200() -> Result<()> { let mut checks = check_path( - Path::new("./resources/test/fixtures/D200.py"), + Path::new("./resources/test/fixtures/D.py"), &settings::Settings::for_rule(CheckCode::D200), &fixer::Mode::Generate, )?; @@ -990,10 +990,46 @@ mod tests { Ok(()) } + #[test] + fn d205() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D205), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + + #[test] + fn d209() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D209), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + + #[test] + fn d210() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/D.py"), + &settings::Settings::for_rule(CheckCode::D210), + &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( - Path::new("./resources/test/fixtures/D400.py"), + Path::new("./resources/test/fixtures/D.py"), &settings::Settings::for_rule(CheckCode::D400), &fixer::Mode::Generate, )?; @@ -1005,7 +1041,7 @@ mod tests { #[test] fn d419() -> Result<()> { let mut checks = check_path( - Path::new("./resources/test/fixtures/D419.py"), + Path::new("./resources/test/fixtures/D.py"), &settings::Settings::for_rule(CheckCode::D419), &fixer::Mode::Generate, )?; diff --git a/src/snapshots/ruff__linter__tests__d200.snap b/src/snapshots/ruff__linter__tests__d200.snap index 0ca97f562e..a1bfad3481 100644 --- a/src/snapshots/ruff__linter__tests__d200.snap +++ b/src/snapshots/ruff__linter__tests__d200.snap @@ -4,26 +4,10 @@ expression: checks --- - kind: OneLinerDocstring location: - row: 2 + row: 124 column: 6 end_location: - row: 4 + row: 126 column: 8 fix: ~ -- kind: OneLinerDocstring - location: - row: 8 - column: 6 - end_location: - row: 9 - column: 8 - fix: ~ -- kind: OneLinerDocstring - location: - row: 13 - column: 6 - end_location: - row: 14 - column: 13 - fix: ~ diff --git a/src/snapshots/ruff__linter__tests__d205.snap b/src/snapshots/ruff__linter__tests__d205.snap new file mode 100644 index 0000000000..25466524ac --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d205.snap @@ -0,0 +1,21 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: BlankLineAfterSummary + location: + row: 195 + column: 6 + end_location: + row: 198 + column: 8 + fix: ~ +- kind: BlankLineAfterSummary + location: + row: 205 + column: 6 + end_location: + row: 210 + column: 8 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d209.snap b/src/snapshots/ruff__linter__tests__d209.snap new file mode 100644 index 0000000000..58928106f0 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d209.snap @@ -0,0 +1,13 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: NewLineAfterLastParagraph + location: + row: 276 + column: 6 + end_location: + row: 278 + column: 20 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d210.snap b/src/snapshots/ruff__linter__tests__d210.snap new file mode 100644 index 0000000000..6d7df49a64 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__d210.snap @@ -0,0 +1,29 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: NoSurroundingWhitespace + location: + row: 283 + column: 6 + end_location: + row: 283 + column: 34 + fix: ~ +- kind: NoSurroundingWhitespace + location: + row: 288 + column: 6 + end_location: + row: 288 + column: 38 + fix: ~ +- kind: NoSurroundingWhitespace + location: + row: 294 + column: 6 + end_location: + row: 297 + column: 8 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__d400.snap b/src/snapshots/ruff__linter__tests__d400.snap index e59a48bc6b..729f010063 100644 --- a/src/snapshots/ruff__linter__tests__d400.snap +++ b/src/snapshots/ruff__linter__tests__d400.snap @@ -4,18 +4,138 @@ expression: checks --- - kind: DocstringEndsInNonPeriod location: - row: 9 + row: 69 column: 6 end_location: - row: 12 + row: 69 + column: 12 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 124 + column: 6 + end_location: + row: 126 column: 8 fix: ~ - kind: DocstringEndsInNonPeriod location: - row: 16 + row: 283 column: 6 end_location: - row: 19 - column: 8 + row: 283 + column: 34 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 288 + column: 6 + end_location: + row: 288 + column: 38 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 350 + column: 6 + end_location: + row: 350 + column: 18 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 401 + column: 26 + end_location: + row: 401 + column: 40 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 405 + column: 6 + end_location: + row: 405 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 411 + column: 6 + end_location: + row: 411 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 417 + column: 36 + end_location: + row: 417 + column: 50 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 424 + column: 50 + end_location: + row: 424 + column: 64 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 465 + column: 6 + end_location: + row: 465 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 470 + column: 6 + end_location: + row: 470 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 475 + column: 6 + end_location: + row: 475 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 482 + column: 6 + end_location: + row: 482 + column: 25 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 504 + column: 6 + end_location: + row: 504 + column: 35 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 509 + column: 6 + end_location: + row: 509 + column: 34 + fix: ~ +- kind: DocstringEndsInNonPeriod + location: + row: 515 + column: 6 + 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 b258ea38b1..cf331f9771 100644 --- a/src/snapshots/ruff__linter__tests__d419.snap +++ b/src/snapshots/ruff__linter__tests__d419.snap @@ -4,26 +4,26 @@ expression: checks --- - kind: EmptyDocstring location: - row: 1 - column: 2 + row: 19 + column: 10 end_location: - row: 1 - column: 7 + row: 19 + column: 15 fix: ~ - kind: EmptyDocstring location: - row: 5 + row: 69 column: 6 end_location: - row: 5 + row: 69 + column: 12 + fix: ~ +- kind: EmptyDocstring + location: + row: 75 + column: 10 + end_location: + row: 75 column: 11 fix: ~ -- kind: EmptyDocstring - location: - row: 9 - column: 6 - end_location: - row: 9 - column: 7 - fix: ~