From 7a1e782d09af33b39edae3e4a66e8b5070040fd3 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 25 May 2023 16:18:49 +0900 Subject: [PATCH 01/47] Added test fixture. --- .../test/fixtures/pycodestyle/E30.py | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 crates/ruff/resources/test/fixtures/pycodestyle/E30.py diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/E30.py b/crates/ruff/resources/test/fixtures/pycodestyle/E30.py new file mode 100644 index 0000000000000..ebe4e9d254690 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pycodestyle/E30.py @@ -0,0 +1,191 @@ +#: E301:5:5 +class X: + + def a(): + pass + def b(): + pass +#: E301:6:5 +class X: + + def a(): + pass + # comment + def b(): + pass +#: + + +#: E302:2:1 +"""Main module.""" +def _main(): + pass +#: E302:2:1 +import sys +def get_sys_path(): + return sys.path +#: E302:4:1 +def a(): + pass + +def b(): + pass +#: E302:6:1 +def a(): + pass + +# comment + +def b(): + pass +#: +#: E302:4:1 +def a(): + pass + +async def b(): + pass +#: + +#: E303:5:1 +print + + + +print +#: E303:5:1 +print + + + +# comment + +print +#: E303:5:5 E303:8:5 +def a(): + print + + + # comment + + + # another comment + + print +#: + + +#: E304:3:1 +@decorator + +def function(): + pass +#: E303:5:1 +#!python + + + +"""This class docstring comes on line 5. +It gives error E303: too many blank lines (3) +""" +#: + +#: E305:7:1 +def a(): + print + + # comment + + # another comment +a() +#: E305:8:1 +def a(): + print + + # comment + + # another comment + +try: + a() +except Exception: + pass +#: E305:5:1 +def a(): + print + +# Two spaces before comments, too. +if a(): + a() +#: + +#: E306:3:5 +def a(): + x = 1 + def b(): + pass +#: E306:3:5 +async def a(): + x = 1 + def b(): + pass +#: E306:3:5 E306:5:9 +def a(): + x = 2 + def b(): + x = 1 + def c(): + pass +#: E306:3:5 E306:6:5 +def a(): + x = 1 + class C: + pass + x = 2 + def b(): + pass +#: + +#: E305:8:1 +# Example from https://github.com/PyCQA/pycodestyle/issues/400 +import stuff + + +def main(): + blah, blah + +if __name__ == '__main__': + main() +# Previously just E272:1:6 E272:4:6 +#: E302:4:1 E271:1:6 E271:4:6 +async def x(): + pass + +async def x(y: int = 1): + pass +#: E704:3:1 E302:3:1 +def bar(): + pass +def baz(): pass +#: E704:1:1 E302:2:1 +def bar(): pass +def baz(): + pass +#: E704:4:5 E306:4:5 +def foo(): + def bar(): + pass + def baz(): pass +#: E704:2:5 E306:3:5 +def foo(): + def bar(): pass + def baz(): + pass +#: E302:5:1 +def f(): + pass + +# wat +@hi +def g(): + pass From 569dae92c4e49e7e29ea17a0aaeb2c985a65c4e1 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 25 May 2023 16:21:11 +0900 Subject: [PATCH 02/47] Start working on blank lines using logical lines. Added violations. --- crates/ruff/src/checkers/logical_lines.rs | 13 +- crates/ruff/src/codes.rs | 6 + crates/ruff/src/registry.rs | 12 + crates/ruff/src/rules/pycodestyle/mod.rs | 6 + .../rules/logical_lines/blank_lines.rs | 327 ++++++++++++++++++ .../pycodestyle/rules/logical_lines/mod.rs | 17 +- 6 files changed, 370 insertions(+), 11 deletions(-) create mode 100644 crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 2a5b0c09f3bee..ffa61767c58a1 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -7,10 +7,10 @@ use ruff_python_ast::token_kind::TokenKind; use crate::registry::{AsRule, Rule}; use crate::rules::pycodestyle::rules::logical_lines::{ - extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword, - missing_whitespace_around_operator, space_around_operator, whitespace_around_keywords, - whitespace_around_named_parameter_equals, whitespace_before_comment, - whitespace_before_parameters, LogicalLines, TokenFlags, + blank_lines, extraneous_whitespace, indentation, missing_whitespace, + missing_whitespace_after_keyword, missing_whitespace_around_operator, space_around_operator, + whitespace_around_keywords, whitespace_around_named_parameter_equals, + whitespace_before_comment, whitespace_before_parameters, LogicalLines, TokenFlags, }; use crate::settings::Settings; @@ -38,6 +38,7 @@ pub(crate) fn check_logical_lines( ) -> Vec { let mut context = LogicalLinesContext::new(settings); + let should_fix_blank_lines = settings.rules.should_fix(Rule::BlankLineBetweenMethods); // FIXME: Rule::BlankLines let should_fix_missing_whitespace = settings.rules.should_fix(Rule::MissingWhitespace); let should_fix_whitespace_before_parameters = @@ -47,6 +48,10 @@ pub(crate) fn check_logical_lines( let mut prev_indent_level = None; let indent_char = stylist.indentation().as_char(); + if should_fix_blank_lines || true { + blank_lines(tokens, locator, &mut context); + } + for line in &LogicalLines::from_tokens(tokens, locator) { if line.flags().contains(TokenFlags::OPERATOR) { space_around_operator(&line, &mut context); diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 0fe8f7cb60b46..83df2c956516e 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -74,6 +74,12 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pycodestyle, "E273") => (RuleGroup::Nursery, Rule::TabAfterKeyword), (Pycodestyle, "E274") => (RuleGroup::Nursery, Rule::TabBeforeKeyword), (Pycodestyle, "E275") => (RuleGroup::Nursery, Rule::MissingWhitespaceAfterKeyword), + (Pycodestyle, "E301") => (RuleGroup::Nursery, Rule::BlankLineBetweenMethods), + (Pycodestyle, "E302") => (RuleGroup::Nursery, Rule::BlankLinesTopLevel), + (Pycodestyle, "E303") => (RuleGroup::Nursery, Rule::TooManyBlankLines), + (Pycodestyle, "E304") => (RuleGroup::Nursery, Rule::BlankLineAfterDecorator), + (Pycodestyle, "E305") => (RuleGroup::Nursery, Rule::BlankLinesAfterFunctionOrClass), + (Pycodestyle, "E306") => (RuleGroup::Nursery, Rule::BlankLinesBeforeNestedDefinition), (Pycodestyle, "E401") => (RuleGroup::Unspecified, Rule::MultipleImportsOnOneLine), (Pycodestyle, "E402") => (RuleGroup::Unspecified, Rule::ModuleImportNotAtTopOfFile), (Pycodestyle, "E501") => (RuleGroup::Unspecified, Rule::LineTooLong), diff --git a/crates/ruff/src/registry.rs b/crates/ruff/src/registry.rs index bc7c6cdea214a..8944010843fac 100644 --- a/crates/ruff/src/registry.rs +++ b/crates/ruff/src/registry.rs @@ -14,6 +14,12 @@ mod rule_set; ruff_macros::register_rules!( // pycodestyle errors rules::pycodestyle::rules::MixedSpacesAndTabs, + rules::pycodestyle::rules::logical_lines::BlankLineBetweenMethods, + rules::pycodestyle::rules::logical_lines::BlankLinesTopLevel, + rules::pycodestyle::rules::logical_lines::TooManyBlankLines, + rules::pycodestyle::rules::logical_lines::BlankLineAfterDecorator, + rules::pycodestyle::rules::logical_lines::BlankLinesAfterFunctionOrClass, + rules::pycodestyle::rules::logical_lines::BlankLinesBeforeNestedDefinition, rules::pycodestyle::rules::logical_lines::IndentationWithInvalidMultiple, rules::pycodestyle::rules::logical_lines::NoIndentedBlock, rules::pycodestyle::rules::logical_lines::UnexpectedIndentation, @@ -950,6 +956,12 @@ impl Rule { Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => LintSource::Filesystem, Rule::IndentationWithInvalidMultiple | Rule::IndentationWithInvalidMultipleComment + | Rule::BlankLineBetweenMethods + | Rule::BlankLinesTopLevel + | Rule::TooManyBlankLines + | Rule::BlankLineAfterDecorator + | Rule::BlankLinesAfterFunctionOrClass + | Rule::BlankLinesBeforeNestedDefinition | Rule::MissingWhitespace | Rule::MissingWhitespaceAfterKeyword | Rule::MissingWhitespaceAroundArithmeticOperator diff --git a/crates/ruff/src/rules/pycodestyle/mod.rs b/crates/ruff/src/rules/pycodestyle/mod.rs index cc2570824631e..f6c41052269d3 100644 --- a/crates/ruff/src/rules/pycodestyle/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/mod.rs @@ -104,6 +104,12 @@ mod tests { Path::new("E25.py") )] #[test_case(Rule::MissingWhitespaceAroundParameterEquals, Path::new("E25.py"))] + #[test_case(Rule::BlankLineBetweenMethods, Path::new("E30.py"))] + #[test_case(Rule::BlankLinesTopLevel, Path::new("E30.py"))] + #[test_case(Rule::TooManyBlankLines, Path::new("E30.py"))] + #[test_case(Rule::BlankLineAfterDecorator, Path::new("E30.py"))] + #[test_case(Rule::BlankLinesAfterFunctionOrClass, Path::new("E30.py"))] + #[test_case(Rule::BlankLinesBeforeNestedDefinition, Path::new("E30.py"))] fn logical(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs new file mode 100644 index 0000000000000..4d3697784f606 --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -0,0 +1,327 @@ +use ruff_diagnostics::AlwaysAutofixableViolation; +use ruff_python_ast::source_code::Locator; +use ruff_text_size::TextRange; + +use ruff_diagnostics::DiagnosticKind; +use ruff_diagnostics::Violation; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::token_kind::TokenKind; +use rustpython_parser::lexer::LexResult; + +use crate::checkers::logical_lines::LogicalLinesContext; + +use super::LogicalLine; +use super::LogicalLines; + +/// Number of blank lines between various code parts. +pub(crate) enum BlankLinesConfig { + /// Top level class and function. + TopLevel = 2, + /// Methods and nested class and function. + Method = 1, +} + +/// ## What it does +/// Checks for missing blank lines between methods of a class. +/// +/// ## Why is this bad? +/// PEP 8 recommends the use of blank lines as follows: +/// - Two blank lines are expected between functions and classes +/// - One blank line is expected between methods of a class. +/// +/// ## Example +/// ```python +/// class MyClass(object): +/// def func1(): +/// pass +/// def func2(): +/// pass +/// ``` +/// +/// Use instead: +/// ```python +/// class MyClass(object): +/// def func1(): +/// pass +/// +/// def func2(): +/// pass +/// ``` +/// +/// ## References +/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) +/// - [Flake 8 rule](https://www.flake8rules.com/rules/E301.html) +#[violation] +pub struct BlankLineBetweenMethods { + nb_blank_lines: usize, +} + +impl AlwaysAutofixableViolation for BlankLineBetweenMethods { + #[derive_message_formats] + fn message(&self) -> String { + let BlankLineBetweenMethods { nb_blank_lines } = self; + format!("Expected 1 blank line, found {nb_blank_lines}") + } + + fn autofix_title(&self) -> String { + "Remove extraneous blank line(s)".to_string() + } +} + +/// ## What it does +/// Checks for extraneous blank lines between top level functions and classes. +/// +/// ## Why is this bad? +/// PEP 8 recommends the use of blank lines as follows: +/// - Two blank lines are expected between functions and classes +/// - One blank line is expected between methods of a class. +/// +/// ## Example +/// ```python +/// def func1(): +/// pass +/// def func2(): +/// pass +/// ``` +/// +/// Use instead: +/// ```python +/// def func1(): +/// pass +/// +/// +/// def func2(): +/// pass +/// ``` +/// +/// ## References +/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) +/// - [Flake 8 rule](https://www.flake8rules.com/rules/E302.html) +#[violation] +pub struct BlankLinesTopLevel(pub usize); + +impl AlwaysAutofixableViolation for BlankLinesTopLevel { + #[derive_message_formats] + fn message(&self) -> String { + let BlankLinesTopLevel(nb_blank_lines) = self; + format!("Expected 2 blank lines, found ({nb_blank_lines})") + } + + fn autofix_title(&self) -> String { + "Add missing blank line(s)".to_string() + } +} + +/// ## What it does +/// Checks for extraneous blank lines. +/// +/// ## Why is this bad? +/// PEP 8 recommends the using blank lines as following: +/// - Two blank lines are expected between functions and classes +/// - One blank line is expected between methods of a class. +/// +/// ## Example +/// ```python +/// def func1(): +/// pass +/// +/// +/// +/// def func2(): +/// pass +/// ``` +/// +/// Use instead: +/// ```python +/// def func1(): +/// pass +/// +/// +/// def func2(): +/// pass +/// ``` +/// +/// ## References +/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) +/// - [Flake 8 rule](https://www.flake8rules.com/rules/E303.html) +#[violation] +pub struct TooManyBlankLines(pub usize); + +impl AlwaysAutofixableViolation for TooManyBlankLines { + #[derive_message_formats] + fn message(&self) -> String { + let TooManyBlankLines(nb_blank_lines) = self; + format!("Too many blank lines ({nb_blank_lines})") + } + + fn autofix_title(&self) -> String { + "Remove extraneous blank line(s)".to_string() + } +} + +/// ## What it does +/// Checks for missing blank line after function decorator. +/// +/// ## Why is this bad? +/// PEP 8 recommends the use of blank lines as follows: +/// - Two blank lines are expected between functions and classes +/// - One blank line is expected between methods of a class. +/// +/// ## Example +/// ```python +/// class User(object): +/// +/// @property +/// +/// def name(self): +/// pass +/// ``` +/// +/// Use instead: +/// ```python +/// class User(object): +/// +/// @property +/// def name(self): +/// pass +/// ``` +/// +/// ## References +/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) +/// - [Flake 8 rule](https://www.flake8rules.com/rules/E304.html) +#[violation] +pub struct BlankLineAfterDecorator; + +impl AlwaysAutofixableViolation for BlankLineAfterDecorator { + #[derive_message_formats] + fn message(&self) -> String { + format!("blank lines found after function decorator") + } + + fn autofix_title(&self) -> String { + "Remove extraneous blank line(s)".to_string() + } +} + +/// ## What it does +/// Checks for blank lines after end of function or class. +/// +/// ## Why is this bad? +/// PEP 8 recommends the using blank lines as following: +/// - Two blank lines are expected between functions and classes +/// - One blank line is expected between methods of a class. +/// +/// ## Example +/// ```python +/// class User(object): +/// pass +/// user = User() +/// ``` +/// +/// Use instead: +/// ```python +/// class User(object): +/// pass +/// +/// +/// user = User() +/// ``` +/// +/// ## References +/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) +/// - [Flake 8 rule](https://www.flake8rules.com/rules/E305.html) +#[violation] +pub struct BlankLinesAfterFunctionOrClass(pub usize); + +impl AlwaysAutofixableViolation for BlankLinesAfterFunctionOrClass { + #[derive_message_formats] + fn message(&self) -> String { + let BlankLinesAfterFunctionOrClass(blank_lines) = self; + format!("expected 2 blank lines after class or function definition, found ({blank_lines})") + } + + fn autofix_title(&self) -> String { + "Add missing blank line(s)".to_string() + } +} + +/// ## What it does +/// Checks for blank lines after end of function or class. +/// +/// ## Why is this bad? +/// PEP 8 recommends the using blank lines as following: +/// - Two blank lines are expected between functions and classes +/// - One blank line is expected between methods of a class. +/// +/// ## Example FIXME: The pycodestyle example does not trigger an error... +/// ```python +/// def outer(): +/// def inner(): +/// pass +/// def inner2(): +/// pass +/// ``` +/// +/// Use instead: +/// ```python +/// def outer(): +/// def inner(): +/// pass +/// +/// def inner2(): +/// pass +/// ``` +/// +/// ## References +/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) +/// - [Flake 8 rule](https://www.flake8rules.com/rules/E306.html) +#[violation] +pub struct BlankLinesBeforeNestedDefinition(pub usize); + +impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { + #[derive_message_formats] + fn message(&self) -> String { + let BlankLinesBeforeNestedDefinition(blank_lines) = self; + format!("Expected 1 blank line before a nested definition, found ({blank_lines})") + } + + fn autofix_title(&self) -> String { + "Add missing blank line".to_string() + } +} + +/// E301, E303 +pub(crate) fn blank_lines( + tokens: &[LexResult], + locator: &Locator, + // stylist: &Stylist, + context: &mut LogicalLinesContext, +) { + let mut prev_line: Option = None; + let mut blank_lines: u32 = 0; + for line in &LogicalLines::from_tokens(tokens, locator) { + // Don't expect blank lines before the first line + if let Some(previous_logical) = prev_line { + if previous_logical.text_trimmed().starts_with("@") && blank_lines > 0 {} + // if blank_lines: + // yield 0, "E304 blank lines found after function decorator" + } else { + continue; + } + + // dbg!(line); + dbg!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + dbg!(line.text()); + for token in line.tokens() { + dbg!(token); + } + if let Some(prev_line) = prev_line { + dbg!("Previous"); + dbg!(prev_line.text()); + for token in prev_line.tokens() { + dbg!(token); + } + } + prev_line = Some(line); + } +} diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 9a9e716abb9c8..89d6e0298bc1a 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -7,6 +7,10 @@ use std::iter::FusedIterator; use ruff_python_ast::source_code::Locator; use ruff_python_ast::token_kind::TokenKind; +pub(crate) use blank_lines::{ + blank_lines, BlankLineAfterDecorator, BlankLineBetweenMethods, BlankLinesAfterFunctionOrClass, + BlankLinesBeforeNestedDefinition, BlankLinesTopLevel, TooManyBlankLines, +}; pub(crate) use extraneous_whitespace::{ extraneous_whitespace, WhitespaceAfterOpenBracket, WhitespaceBeforeCloseBracket, WhitespaceBeforePunctuation, @@ -45,6 +49,7 @@ pub(crate) use whitespace_before_parameters::{ whitespace_before_parameters, WhitespaceBeforeParameters, }; +mod blank_lines; mod extraneous_whitespace; mod indentation; mod missing_whitespace; @@ -511,13 +516,11 @@ impl LogicalLinesBuilder { let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] .iter() .all(|token| token.kind.is_newline()); - if !is_empty { - self.lines.push(Line { - flags: self.current_line.flags, - tokens_start: self.current_line.tokens_start, - tokens_end: end, - }); - } + self.lines.push(Line { + flags: self.current_line.flags, + tokens_start: self.current_line.tokens_start, + tokens_end: end, + }); self.current_line = CurrentLine { flags: TokenFlags::default(), From 119520d600c648f5afa8436a7f9159c6dfd64ac2 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 25 May 2023 18:03:19 +0900 Subject: [PATCH 03/47] Began looking at logic. --- .../rules/logical_lines/blank_lines.rs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 4d3697784f606..5cc36a8fbc99c 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -1,4 +1,5 @@ use ruff_diagnostics::AlwaysAutofixableViolation; +use ruff_diagnostics::Diagnostic; use ruff_python_ast::source_code::Locator; use ruff_text_size::TextRange; @@ -302,9 +303,29 @@ pub(crate) fn blank_lines( for line in &LogicalLines::from_tokens(tokens, locator) { // Don't expect blank lines before the first line if let Some(previous_logical) = prev_line { - if previous_logical.text_trimmed().starts_with("@") && blank_lines > 0 {} - // if blank_lines: - // yield 0, "E304 blank lines found after function decorator" + if previous_logical.text_trimmed().starts_with("@") && blank_lines > 0 { + context.push( + DiagnosticKind::from(BlankLineAfterDecorator), + TextRange::at( + line.first_token().unwrap().start(), + line.tokens().last().unwrap().end(), + ), + ); + // diagnostic.set_fix(Fix::suggested(Edit::range_replacement( + // "\n\n".to_string(), + // range, + // ))); + } else if (blank_lines > BlankLinesConfig::TopLevel + || (indent_level > 0 && blank_lines == BlankLinesConfig::Method + 1)) + { + context.push( + DiagnosticKind::from(TooManyBlankLines(blank_lines)), + TextRange::at( + line.first_token().unwrap().start(), + line.tokens().last().unwrap().end(), + ), + ); + } } else { continue; } From 7667d399bd3776c0ae7bc5388f6154363be9c2bb Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 25 May 2023 19:35:17 +0900 Subject: [PATCH 04/47] Began looking at the logic. --- crates/ruff/src/checkers/logical_lines.rs | 25 +++-- .../rules/logical_lines/blank_lines.rs | 97 ++++++++++--------- .../pycodestyle/rules/logical_lines/mod.rs | 3 +- 3 files changed, 72 insertions(+), 53 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index ffa61767c58a1..ff04ce1211dcb 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -45,13 +45,12 @@ pub(crate) fn check_logical_lines( settings.rules.should_fix(Rule::WhitespaceBeforeParameters); let mut prev_line = None; + let mut nb_blank_lines: usize = 0; + let mut follows_decorator = false; + + let mut prev_no_comment_line = None; let mut prev_indent_level = None; let indent_char = stylist.indentation().as_char(); - - if should_fix_blank_lines || true { - blank_lines(tokens, locator, &mut context); - } - for line in &LogicalLines::from_tokens(tokens, locator) { if line.flags().contains(TokenFlags::OPERATOR) { space_around_operator(&line, &mut context); @@ -101,7 +100,7 @@ pub(crate) fn check_logical_lines( for kind in indentation( &line, - prev_line.as_ref(), + prev_no_comment_line.as_ref(), indent_char, indent_level, prev_indent_level, @@ -111,9 +110,21 @@ pub(crate) fn check_logical_lines( context.push(kind, range); } } + if should_fix_blank_lines || true { + blank_lines( + &line, + prev_no_comment_line.as_ref(), + &mut nb_blank_lines, + &mut follows_decorator, + &indent_level, + locator, + &mut context, + ); + } + prev_line = Some(line.clone()); if !line.is_comment_only() { - prev_line = Some(line); + prev_no_comment_line = Some(line); prev_indent_level = Some(indent_level); } } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 5cc36a8fbc99c..9bbe8522eebd7 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -1,5 +1,7 @@ use ruff_diagnostics::AlwaysAutofixableViolation; use ruff_diagnostics::Diagnostic; +use ruff_diagnostics::Edit; +use ruff_diagnostics::Fix; use ruff_python_ast::source_code::Locator; use ruff_text_size::TextRange; @@ -7,6 +9,7 @@ use ruff_diagnostics::DiagnosticKind; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; +use ruff_text_size::TextSize; use rustpython_parser::lexer::LexResult; use crate::checkers::logical_lines::LogicalLinesContext; @@ -15,11 +18,13 @@ use super::LogicalLine; use super::LogicalLines; /// Number of blank lines between various code parts. -pub(crate) enum BlankLinesConfig { +struct BlankLinesConfig; + +impl BlankLinesConfig { /// Top level class and function. - TopLevel = 2, + const TOP_LEVEL: usize = 2; /// Methods and nested class and function. - Method = 1, + const METHOD: usize = 1; } /// ## What it does @@ -293,56 +298,58 @@ impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { /// E301, E303 pub(crate) fn blank_lines( - tokens: &[LexResult], + line: &LogicalLine, + prev_line: Option<&LogicalLine>, + blank_lines: &mut usize, + follows_decorator: &mut bool, + indent_level: &usize, locator: &Locator, // stylist: &Stylist, context: &mut LogicalLinesContext, ) { - let mut prev_line: Option = None; - let mut blank_lines: u32 = 0; - for line in &LogicalLines::from_tokens(tokens, locator) { - // Don't expect blank lines before the first line - if let Some(previous_logical) = prev_line { - if previous_logical.text_trimmed().starts_with("@") && blank_lines > 0 { - context.push( - DiagnosticKind::from(BlankLineAfterDecorator), - TextRange::at( - line.first_token().unwrap().start(), - line.tokens().last().unwrap().end(), - ), - ); - // diagnostic.set_fix(Fix::suggested(Edit::range_replacement( - // "\n\n".to_string(), - // range, - // ))); - } else if (blank_lines > BlankLinesConfig::TopLevel - || (indent_level > 0 && blank_lines == BlankLinesConfig::Method + 1)) + dbg!("#############################"); + dbg!(line.text()); + if let Some(previous_logical) = prev_line { + for token in line.tokens() { + if token.kind() == TokenKind::NonLogicalNewline { + *blank_lines += 1; + return; + } + + dbg!(&token); + dbg!(&blank_lines); + if *follows_decorator && *blank_lines > 0 { + let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); + + let range = token.range(); + dbg!(locator.line_start(range.start())); + dbg!(locator.line_start(range.start()) - TextSize::new(2 * *blank_lines as u32)); + + diagnostic.set_fix(Fix::suggested(Edit::deletion( + locator.line_start(range.start()) - TextSize::new(2 * *blank_lines as u32), + locator.line_start(range.start()) - TextSize::new(1), + ))); + context.push_diagnostic(diagnostic); + } else if token.kind() != TokenKind::NonLogicalNewline + && (*blank_lines > BlankLinesConfig::TOP_LEVEL + || (*indent_level > 0 && *blank_lines == BlankLinesConfig::METHOD + 1)) { - context.push( - DiagnosticKind::from(TooManyBlankLines(blank_lines)), - TextRange::at( - line.first_token().unwrap().start(), - line.tokens().last().unwrap().end(), - ), - ); + let mut diagnostic = + Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); + // TODO: diagnostic.set_fix // FIXME: Use stylist to use the user's preferred newline character + context.push_diagnostic(diagnostic); } - } else { - continue; - } - // dbg!(line); - dbg!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - dbg!(line.text()); - for token in line.tokens() { - dbg!(token); - } - if let Some(prev_line) = prev_line { - dbg!("Previous"); - dbg!(prev_line.text()); - for token in prev_line.tokens() { - dbg!(token); + if token.kind() == TokenKind::At { + *follows_decorator = true; + return; + } else { + *follows_decorator = false; + } + + if token.kind() != TokenKind::NonLogicalNewline { + *blank_lines = 0; } } - prev_line = Some(line); } } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 89d6e0298bc1a..7a8c8814ab6e1 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -149,7 +149,7 @@ impl<'a> IntoIterator for &'a LogicalLines<'a> { /// 2 /// ] /// ``` -#[derive(Debug)] +#[derive(Clone, Debug)] pub(crate) struct LogicalLine<'a> { lines: &'a LogicalLines<'a>, line: &'a Line, @@ -516,6 +516,7 @@ impl LogicalLinesBuilder { let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] .iter() .all(|token| token.kind.is_newline()); + self.lines.push(Line { flags: self.current_line.flags, tokens_start: self.current_line.tokens_start, From e7f28ac3f6be8039d11690fdff7824d2fbf20a29 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 25 May 2023 19:36:45 +0900 Subject: [PATCH 05/47] Removed debugs --- .../rules/pycodestyle/rules/logical_lines/blank_lines.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 9bbe8522eebd7..f119106c4f5d6 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -307,8 +307,6 @@ pub(crate) fn blank_lines( // stylist: &Stylist, context: &mut LogicalLinesContext, ) { - dbg!("#############################"); - dbg!(line.text()); if let Some(previous_logical) = prev_line { for token in line.tokens() { if token.kind() == TokenKind::NonLogicalNewline { @@ -316,15 +314,10 @@ pub(crate) fn blank_lines( return; } - dbg!(&token); - dbg!(&blank_lines); if *follows_decorator && *blank_lines > 0 { let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); let range = token.range(); - dbg!(locator.line_start(range.start())); - dbg!(locator.line_start(range.start()) - TextSize::new(2 * *blank_lines as u32)); - diagnostic.set_fix(Fix::suggested(Edit::deletion( locator.line_start(range.start()) - TextSize::new(2 * *blank_lines as u32), locator.line_start(range.start()) - TextSize::new(1), From 41cddde813726ce4947c6f8e90d5270d20636c10 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 25 May 2023 20:05:43 +0900 Subject: [PATCH 06/47] Minor cleanup. --- crates/ruff/src/checkers/logical_lines.rs | 6 ++-- .../rules/logical_lines/blank_lines.rs | 29 +++++++------------ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index ff04ce1211dcb..26508fa623280 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -45,7 +45,7 @@ pub(crate) fn check_logical_lines( settings.rules.should_fix(Rule::WhitespaceBeforeParameters); let mut prev_line = None; - let mut nb_blank_lines: usize = 0; + let mut nb_blank_lines: u32 = 0; let mut follows_decorator = false; let mut prev_no_comment_line = None; @@ -113,10 +113,10 @@ pub(crate) fn check_logical_lines( if should_fix_blank_lines || true { blank_lines( &line, - prev_no_comment_line.as_ref(), + prev_line.as_ref(), &mut nb_blank_lines, &mut follows_decorator, - &indent_level, + indent_level, locator, &mut context, ); diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index f119106c4f5d6..32b0d356a791c 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -3,28 +3,23 @@ use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Edit; use ruff_diagnostics::Fix; use ruff_python_ast::source_code::Locator; -use ruff_text_size::TextRange; -use ruff_diagnostics::DiagnosticKind; -use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; use ruff_text_size::TextSize; -use rustpython_parser::lexer::LexResult; use crate::checkers::logical_lines::LogicalLinesContext; use super::LogicalLine; -use super::LogicalLines; /// Number of blank lines between various code parts. struct BlankLinesConfig; impl BlankLinesConfig { /// Top level class and function. - const TOP_LEVEL: usize = 2; + const TOP_LEVEL: u32 = 2; /// Methods and nested class and function. - const METHOD: usize = 1; + const METHOD: u32 = 1; } /// ## What it does @@ -151,7 +146,7 @@ impl AlwaysAutofixableViolation for BlankLinesTopLevel { /// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) /// - [Flake 8 rule](https://www.flake8rules.com/rules/E303.html) #[violation] -pub struct TooManyBlankLines(pub usize); +pub struct TooManyBlankLines(pub u32); impl AlwaysAutofixableViolation for TooManyBlankLines { #[derive_message_formats] @@ -300,9 +295,9 @@ impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { pub(crate) fn blank_lines( line: &LogicalLine, prev_line: Option<&LogicalLine>, - blank_lines: &mut usize, + blank_lines: &mut u32, follows_decorator: &mut bool, - indent_level: &usize, + indent_level: usize, locator: &Locator, // stylist: &Stylist, context: &mut LogicalLinesContext, @@ -319,13 +314,13 @@ pub(crate) fn blank_lines( let range = token.range(); diagnostic.set_fix(Fix::suggested(Edit::deletion( - locator.line_start(range.start()) - TextSize::new(2 * *blank_lines as u32), - locator.line_start(range.start()) - TextSize::new(1), + locator.line_start(range.start()) - TextSize::new(*blank_lines), + locator.line_start(range.start()), ))); context.push_diagnostic(diagnostic); } else if token.kind() != TokenKind::NonLogicalNewline && (*blank_lines > BlankLinesConfig::TOP_LEVEL - || (*indent_level > 0 && *blank_lines == BlankLinesConfig::METHOD + 1)) + || (indent_level > 0 && *blank_lines == BlankLinesConfig::METHOD + 1)) { let mut diagnostic = Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); @@ -333,16 +328,12 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } + *blank_lines = 0; if token.kind() == TokenKind::At { *follows_decorator = true; return; - } else { - *follows_decorator = false; - } - - if token.kind() != TokenKind::NonLogicalNewline { - *blank_lines = 0; } + *follows_decorator = false; } } } From 47788de5f78f875ace1fffd2d1c99092d660bd78 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 26 May 2023 00:21:22 +0900 Subject: [PATCH 07/47] Add blank line rules to KNOWN_FORMATTING_VIOLATIONS --- scripts/check_docs_formatted.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/check_docs_formatted.py b/scripts/check_docs_formatted.py index 34068a2e8038f..fd4d74a5fdda6 100755 --- a/scripts/check_docs_formatted.py +++ b/scripts/check_docs_formatted.py @@ -27,6 +27,11 @@ "bad-quotes-docstring", "bad-quotes-inline-string", "bad-quotes-multiline-string", + "blank-lines-after-function-or-class", + "blank-lines-before-nested-definition", + "blank-lines-top-level", + "blank-line-after-decorator", + "blank-line-between-methods", "explicit-string-concatenation", "indentation-with-invalid-multiple", "line-too-long", @@ -45,6 +50,7 @@ "over-indented", "prohibited-trailing-comma", "too-few-spaces-before-inline-comment", + "too-many-blank-lines", "trailing-comma-on-bare-tuple", "unexpected-indentation-comment", "useless-semicolon", From 3ee918628a77da40a3c4374967f186bce01d6380 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 26 May 2023 12:13:42 +0900 Subject: [PATCH 08/47] Fixed errors created by not ignoring empty lines anymore. --- crates/ruff/src/checkers/logical_lines.rs | 2 +- .../pycodestyle/rules/logical_lines/indentation.rs | 4 ++++ .../src/rules/pycodestyle/rules/logical_lines/mod.rs | 11 ++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 26508fa623280..ae1681f3de5f8 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -123,7 +123,7 @@ pub(crate) fn check_logical_lines( } prev_line = Some(line.clone()); - if !line.is_comment_only() { + if !line.is_comment_only() && !line.is_empty() { prev_no_comment_line = Some(line); prev_indent_level = Some(indent_level); } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs index a059ee9b6c306..6a487db553277 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs @@ -246,6 +246,10 @@ pub(crate) fn indentation( ) -> Vec { let mut diagnostics = vec![]; + if logical_line.is_empty() { + return diagnostics; + } + if indent_level % indent_size != 0 { diagnostics.push(if logical_line.is_comment_only() { DiagnosticKind::from(IndentationWithInvalidMultipleComment { indent_size }) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 7a8c8814ab6e1..441289942a978 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -166,6 +166,11 @@ impl<'a> LogicalLine<'a> { self.flags() == TokenFlags::COMMENT } + /// Returns `true` if this is a comment only line + pub(crate) fn is_empty(&self) -> bool { + self.tokens().iter().all(|token| token.kind.is_newline()) + } + /// Returns logical line's text including comments, indents, dedent and trailing new lines. pub(crate) fn text(&self) -> &'a str { let tokens = self.tokens(); @@ -513,10 +518,6 @@ impl LogicalLinesBuilder { fn finish_line(&mut self) { let end = self.tokens.len() as u32; if self.current_line.tokens_start < end { - let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] - .iter() - .all(|token| token.kind.is_newline()); - self.lines.push(Line { flags: self.current_line.flags, tokens_start: self.current_line.tokens_start, @@ -631,7 +632,7 @@ if False: print() "# .trim(), - &["if False:", "print()", ""], + &["if False:", "", "print()", ""], ); } From 8f60ac9c73b13cb2b37313104fbea03c2b234301 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 26 May 2023 12:53:19 +0900 Subject: [PATCH 09/47] Fixed parser test expectation for E302 since support is added for it. --- crates/ruff/src/flake8_to_ruff/parser.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ruff/src/flake8_to_ruff/parser.rs b/crates/ruff/src/flake8_to_ruff/parser.rs index 5c305aafcde65..51a335ab2735a 100644 --- a/crates/ruff/src/flake8_to_ruff/parser.rs +++ b/crates/ruff/src/flake8_to_ruff/parser.rs @@ -290,6 +290,10 @@ mod tests { pattern: "examples/*".to_string(), prefix: codes::Pyflakes::_841.into(), }, + PatternPrefixPair { + pattern: "*.pyi".to_string(), + prefix: codes::Pycodestyle::E302.into(), + }, ]; assert_eq!(actual, expected); From 42c47373d009798b65f9aa3242ae10926c676cf2 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 26 May 2023 13:03:21 +0900 Subject: [PATCH 10/47] Add snapshot for E304. --- ...ules__pycodestyle__tests__E304_E30.py.snap | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap new file mode 100644 index 0000000000000..aaf49037eff51 --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap @@ -0,0 +1,24 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +E30.py:81:1: E304 [*] blank lines found after function decorator + | +81 | @decorator +82 | +83 | def function(): + | ^^^ E304 +84 | pass +85 | #: E303:5:1 + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +77 77 | +78 78 | #: E304:3:1 +79 79 | @decorator +80 |- +81 80 | def function(): +82 81 | pass +83 82 | #: E303:5:1 + + From 4bf73268ca4885936748449080a333cb57092729 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 26 May 2023 13:20:18 +0900 Subject: [PATCH 11/47] Count blank characters and use them to remove lines in order to handle \r\n cases. --- crates/ruff/src/checkers/logical_lines.rs | 2 ++ .../rules/logical_lines/blank_lines.rs | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index ae1681f3de5f8..03a9b977ce625 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -46,6 +46,7 @@ pub(crate) fn check_logical_lines( let mut prev_line = None; let mut nb_blank_lines: u32 = 0; + let mut blank_characters: usize = 0; let mut follows_decorator = false; let mut prev_no_comment_line = None; @@ -115,6 +116,7 @@ pub(crate) fn check_logical_lines( &line, prev_line.as_ref(), &mut nb_blank_lines, + &mut blank_characters, &mut follows_decorator, indent_level, locator, diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 32b0d356a791c..733023e8ff71f 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -296,6 +296,7 @@ pub(crate) fn blank_lines( line: &LogicalLine, prev_line: Option<&LogicalLine>, blank_lines: &mut u32, + blank_characters: &mut usize, follows_decorator: &mut bool, indent_level: usize, locator: &Locator, @@ -303,18 +304,24 @@ pub(crate) fn blank_lines( context: &mut LogicalLinesContext, ) { if let Some(previous_logical) = prev_line { - for token in line.tokens() { - if token.kind() == TokenKind::NonLogicalNewline { - *blank_lines += 1; - return; - } + if line.is_empty() { + *blank_lines += 1; + *blank_characters += line.text().len(); + return; + } + for token in line.tokens() { if *follows_decorator && *blank_lines > 0 { let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); let range = token.range(); diagnostic.set_fix(Fix::suggested(Edit::deletion( - locator.line_start(range.start()) - TextSize::new(*blank_lines), + locator.line_start(range.start()) + - TextSize::new( + u32::try_from(*blank_characters).expect( + "The number of blank characters should be relatively small", + ), + ), locator.line_start(range.start()), ))); context.push_diagnostic(diagnostic); @@ -329,6 +336,7 @@ pub(crate) fn blank_lines( } *blank_lines = 0; + *blank_characters = 0; if token.kind() == TokenKind::At { *follows_decorator = true; return; From e0827477f9a2819c4b23c0a836fde1515029bda5 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sat, 27 May 2023 22:30:19 +0900 Subject: [PATCH 12/47] Finished E303. Made blank_characters into a u32 again to avoid all the try_from. --- crates/ruff/src/checkers/logical_lines.rs | 2 +- .../rules/logical_lines/blank_lines.rs | 32 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 03a9b977ce625..de1efe235a29f 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -46,7 +46,7 @@ pub(crate) fn check_logical_lines( let mut prev_line = None; let mut nb_blank_lines: u32 = 0; - let mut blank_characters: usize = 0; + let mut blank_characters: u32 = 0; let mut follows_decorator = false; let mut prev_no_comment_line = None; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 733023e8ff71f..401a8e8e039dd 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -6,6 +6,7 @@ use ruff_python_ast::source_code::Locator; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; +use ruff_text_size::TextRange; use ruff_text_size::TextSize; use crate::checkers::logical_lines::LogicalLinesContext; @@ -296,7 +297,7 @@ pub(crate) fn blank_lines( line: &LogicalLine, prev_line: Option<&LogicalLine>, blank_lines: &mut u32, - blank_characters: &mut usize, + blank_characters: &mut u32, follows_decorator: &mut bool, indent_level: usize, locator: &Locator, @@ -306,7 +307,7 @@ pub(crate) fn blank_lines( if let Some(previous_logical) = prev_line { if line.is_empty() { *blank_lines += 1; - *blank_characters += line.text().len(); + *blank_characters += line.text().len() as u32; return; } @@ -327,14 +328,37 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } else if token.kind() != TokenKind::NonLogicalNewline && (*blank_lines > BlankLinesConfig::TOP_LEVEL - || (indent_level > 0 && *blank_lines == BlankLinesConfig::METHOD + 1)) + || (indent_level > 0 && *blank_lines > BlankLinesConfig::METHOD)) { let mut diagnostic = Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); - // TODO: diagnostic.set_fix // FIXME: Use stylist to use the user's preferred newline character + + let chars_to_remove = if indent_level > 0 { + *blank_characters - BlankLinesConfig::METHOD + } else { + *blank_characters - BlankLinesConfig::TOP_LEVEL + }; + let end = locator.line_start(token.range().start()); + let start = end - TextSize::new(chars_to_remove); + + #[allow(deprecated)] + diagnostic.set_fix(Fix::suggested(Edit::deletion(start, end))); context.push_diagnostic(diagnostic); } + // diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( + // annotation.to_string(), + // TextRange::new(start, end), + // ))); + // stylist.line_ending().as_str() + + // pub struct Stylist<'a> { + // locator: &'a Locator<'a>, + // indentation: Indentation, + // quote: Quote, + // line_ending: OnceCell, + // } + *blank_lines = 0; *blank_characters = 0; if token.kind() == TokenKind::At { From 4f369cc2dfedd5f6ffef965860d02454d26ffba6 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sat, 27 May 2023 23:59:44 +0900 Subject: [PATCH 13/47] Added E306 --- crates/ruff/src/checkers/logical_lines.rs | 3 + .../rules/logical_lines/blank_lines.rs | 139 ++++++++++-------- 2 files changed, 81 insertions(+), 61 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index de1efe235a29f..c5c6966615b8c 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -48,6 +48,7 @@ pub(crate) fn check_logical_lines( let mut nb_blank_lines: u32 = 0; let mut blank_characters: u32 = 0; let mut follows_decorator = false; + let mut follows_def = false; let mut prev_no_comment_line = None; let mut prev_indent_level = None; @@ -118,8 +119,10 @@ pub(crate) fn check_logical_lines( &mut nb_blank_lines, &mut blank_characters, &mut follows_decorator, + &mut follows_def, indent_level, locator, + stylist, &mut context, ); } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 401a8e8e039dd..0fa01ebe6fdd6 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -4,9 +4,10 @@ use ruff_diagnostics::Edit; use ruff_diagnostics::Fix; use ruff_python_ast::source_code::Locator; +use regex::Regex; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::source_code::Stylist; use ruff_python_ast::token_kind::TokenKind; -use ruff_text_size::TextRange; use ruff_text_size::TextSize; use crate::checkers::logical_lines::LogicalLinesContext; @@ -106,7 +107,7 @@ impl AlwaysAutofixableViolation for BlankLinesTopLevel { #[derive_message_formats] fn message(&self) -> String { let BlankLinesTopLevel(nb_blank_lines) = self; - format!("Expected 2 blank lines, found ({nb_blank_lines})") + format!("Expected 2 blank lines, found {nb_blank_lines}") } fn autofix_title(&self) -> String { @@ -278,13 +279,13 @@ impl AlwaysAutofixableViolation for BlankLinesAfterFunctionOrClass { /// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) /// - [Flake 8 rule](https://www.flake8rules.com/rules/E306.html) #[violation] -pub struct BlankLinesBeforeNestedDefinition(pub usize); +pub struct BlankLinesBeforeNestedDefinition(pub u32); impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { #[derive_message_formats] fn message(&self) -> String { let BlankLinesBeforeNestedDefinition(blank_lines) = self; - format!("Expected 1 blank line before a nested definition, found ({blank_lines})") + format!("Expected 1 blank line before a nested definition, found {blank_lines}") } fn autofix_title(&self) -> String { @@ -299,73 +300,89 @@ pub(crate) fn blank_lines( blank_lines: &mut u32, blank_characters: &mut u32, follows_decorator: &mut bool, + follows_def: &mut bool, indent_level: usize, locator: &Locator, - // stylist: &Stylist, + stylist: &Stylist, context: &mut LogicalLinesContext, ) { - if let Some(previous_logical) = prev_line { - if line.is_empty() { - *blank_lines += 1; - *blank_characters += line.text().len() as u32; - return; + dbg!("#############################"); + dbg!(line.text()); + + if line.is_empty() { + *blank_lines += 1; + *blank_characters += line.text().len() as u32; + return; + } + + for (token_idx, token) in line.tokens().iter().enumerate() { + dbg!(token); + // E304 + if *follows_decorator && *blank_lines > 0 { + let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); + + let range = token.range(); + diagnostic.set_fix(Fix::suggested(Edit::deletion( + locator.line_start(range.start()) + - TextSize::new( + u32::try_from(*blank_characters) + .expect("The number of blank characters should be relatively small"), + ), + locator.line_start(range.start()), + ))); + context.push_diagnostic(diagnostic); } + // E303 + else if token_idx == 0 && *blank_lines > BlankLinesConfig::TOP_LEVEL + || (indent_level > 0 && *blank_lines > BlankLinesConfig::METHOD) + { + let mut diagnostic = Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); + + let chars_to_remove = if indent_level > 0 { + *blank_characters - BlankLinesConfig::METHOD + } else { + *blank_characters - BlankLinesConfig::TOP_LEVEL + }; + let end = locator.line_start(token.range().start()); + let start = end - TextSize::new(chars_to_remove); + #[allow(deprecated)] + diagnostic.set_fix(Fix::suggested(Edit::deletion(start, end))); - for token in line.tokens() { - if *follows_decorator && *blank_lines > 0 { - let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); - - let range = token.range(); - diagnostic.set_fix(Fix::suggested(Edit::deletion( - locator.line_start(range.start()) - - TextSize::new( - u32::try_from(*blank_characters).expect( - "The number of blank characters should be relatively small", - ), - ), - locator.line_start(range.start()), - ))); - context.push_diagnostic(diagnostic); - } else if token.kind() != TokenKind::NonLogicalNewline - && (*blank_lines > BlankLinesConfig::TOP_LEVEL - || (indent_level > 0 && *blank_lines > BlankLinesConfig::METHOD)) - { - let mut diagnostic = - Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); - - let chars_to_remove = if indent_level > 0 { - *blank_characters - BlankLinesConfig::METHOD - } else { - *blank_characters - BlankLinesConfig::TOP_LEVEL - }; - let end = locator.line_start(token.range().start()); - let start = end - TextSize::new(chars_to_remove); - - #[allow(deprecated)] - diagnostic.set_fix(Fix::suggested(Edit::deletion(start, end))); - context.push_diagnostic(diagnostic); - } - - // diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( - // annotation.to_string(), - // TextRange::new(start, end), - // ))); - // stylist.line_ending().as_str() - - // pub struct Stylist<'a> { - // locator: &'a Locator<'a>, - // indentation: Indentation, - // quote: Quote, - // line_ending: OnceCell, - // } + context.push_diagnostic(diagnostic); + } + // E306 + else if token.kind() == TokenKind::Def && *follows_def && *blank_lines == 0 { + let mut diagnostic = Diagnostic::new( + BlankLinesBeforeNestedDefinition(*blank_lines), + token.range(), + ); + #[allow(deprecated)] + diagnostic.set_fix(Fix::unspecified(Edit::insertion( + stylist.line_ending().as_str().to_string(), + locator.line_start(token.range().start()), + ))); + context.push_diagnostic(diagnostic); + } + + if token.kind() == TokenKind::At { + *follows_decorator = true; + + *follows_def = false; *blank_lines = 0; *blank_characters = 0; - if token.kind() == TokenKind::At { - *follows_decorator = true; - return; - } + return; + } else if token.kind() == TokenKind::Def { + *follows_def = true; + *follows_decorator = false; + *blank_lines = 0; + *blank_characters = 0; + return; } } + *follows_decorator = false; + *follows_def = false; + *blank_lines = 0; + *blank_characters = 0; } From e1c3df0a12ec2206b2c318e70be37122675e6e38 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 00:30:07 +0900 Subject: [PATCH 14/47] Added is_in_class variable. --- crates/ruff/src/checkers/logical_lines.rs | 11 ++++++----- .../rules/logical_lines/blank_lines.rs | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index c5c6966615b8c..79391e1bfdc44 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -47,10 +47,11 @@ pub(crate) fn check_logical_lines( let mut prev_line = None; let mut nb_blank_lines: u32 = 0; let mut blank_characters: u32 = 0; + let mut class_indent_level: usize = 0; let mut follows_decorator = false; let mut follows_def = false; + let mut is_in_class = false; - let mut prev_no_comment_line = None; let mut prev_indent_level = None; let indent_char = stylist.indentation().as_char(); for line in &LogicalLines::from_tokens(tokens, locator) { @@ -102,7 +103,7 @@ pub(crate) fn check_logical_lines( for kind in indentation( &line, - prev_no_comment_line.as_ref(), + prev_line.as_ref(), indent_char, indent_level, prev_indent_level, @@ -115,11 +116,12 @@ pub(crate) fn check_logical_lines( if should_fix_blank_lines || true { blank_lines( &line, - prev_line.as_ref(), &mut nb_blank_lines, &mut blank_characters, &mut follows_decorator, &mut follows_def, + &mut is_in_class, + &mut class_indent_level, indent_level, locator, stylist, @@ -127,9 +129,8 @@ pub(crate) fn check_logical_lines( ); } - prev_line = Some(line.clone()); if !line.is_comment_only() && !line.is_empty() { - prev_no_comment_line = Some(line); + prev_line = Some(line); prev_indent_level = Some(indent_level); } } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 0fa01ebe6fdd6..a1ad8ba49786b 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -296,11 +296,12 @@ impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { /// E301, E303 pub(crate) fn blank_lines( line: &LogicalLine, - prev_line: Option<&LogicalLine>, blank_lines: &mut u32, blank_characters: &mut u32, follows_decorator: &mut bool, follows_def: &mut bool, + is_in_class: &mut bool, + class_indent_level: &mut usize, indent_level: usize, locator: &Locator, stylist: &Stylist, @@ -334,7 +335,7 @@ pub(crate) fn blank_lines( } // E303 else if token_idx == 0 && *blank_lines > BlankLinesConfig::TOP_LEVEL - || (indent_level > 0 && *blank_lines > BlankLinesConfig::METHOD) + || (*is_in_class && *blank_lines > BlankLinesConfig::METHOD) { let mut diagnostic = Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); @@ -365,6 +366,17 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } + if token.kind() == TokenKind::Class { + if !*is_in_class { + *class_indent_level = indent_level; + } + *is_in_class = true; + } + + if indent_level <= *class_indent_level { + *is_in_class = false; + } + if token.kind() == TokenKind::At { *follows_decorator = true; @@ -383,6 +395,7 @@ pub(crate) fn blank_lines( } *follows_decorator = false; *follows_def = false; + *is_in_class = false; *blank_lines = 0; *blank_characters = 0; } From ccd7468b4a3defb752ac48f9edeba89926cf7aa3 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 00:54:30 +0900 Subject: [PATCH 15/47] Added E301. --- crates/ruff/src/checkers/logical_lines.rs | 1 + .../rules/logical_lines/blank_lines.rs | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 79391e1bfdc44..62c284314a75a 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -116,6 +116,7 @@ pub(crate) fn check_logical_lines( if should_fix_blank_lines || true { blank_lines( &line, + prev_line.as_ref(), &mut nb_blank_lines, &mut blank_characters, &mut follows_decorator, diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index a1ad8ba49786b..86272515dee6b 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -4,7 +4,6 @@ use ruff_diagnostics::Edit; use ruff_diagnostics::Fix; use ruff_python_ast::source_code::Locator; -use regex::Regex; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::source_code::Stylist; use ruff_python_ast::token_kind::TokenKind; @@ -55,15 +54,12 @@ impl BlankLinesConfig { /// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) /// - [Flake 8 rule](https://www.flake8rules.com/rules/E301.html) #[violation] -pub struct BlankLineBetweenMethods { - nb_blank_lines: usize, -} +pub struct BlankLineBetweenMethods; impl AlwaysAutofixableViolation for BlankLineBetweenMethods { #[derive_message_formats] fn message(&self) -> String { - let BlankLineBetweenMethods { nb_blank_lines } = self; - format!("Expected 1 blank line, found {nb_blank_lines}") + format!("Expected 1 blank line, found 0") } fn autofix_title(&self) -> String { @@ -296,6 +292,7 @@ impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { /// E301, E303 pub(crate) fn blank_lines( line: &LogicalLine, + prev_line: Option<&LogicalLine>, blank_lines: &mut u32, blank_characters: &mut u32, follows_decorator: &mut bool, @@ -365,12 +362,29 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } + // E301 + if token.kind() == TokenKind::Def + && *is_in_class + && *blank_lines == 0 + && prev_line + .and_then(|prev_line| prev_line.tokens_trimmed().first()) + .map_or(false, |token| token.kind() != TokenKind::Class) + { + let mut diagnostic = Diagnostic::new(BlankLineBetweenMethods, token.range()); + #[allow(deprecated)] + diagnostic.set_fix(Fix::unspecified(Edit::insertion( + stylist.line_ending().as_str().to_string(), + locator.line_start(token.range().start()), + ))); + context.push_diagnostic(diagnostic); + } if token.kind() == TokenKind::Class { if !*is_in_class { *class_indent_level = indent_level; } *is_in_class = true; + return; } if indent_level <= *class_indent_level { @@ -395,7 +409,6 @@ pub(crate) fn blank_lines( } *follows_decorator = false; *follows_def = false; - *is_in_class = false; *blank_lines = 0; *blank_characters = 0; } From 44b146cef9f1e53c5df0ff58044456e4d4a3baf9 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 18:38:48 +0900 Subject: [PATCH 16/47] Added E302. --- .../rules/logical_lines/blank_lines.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 86272515dee6b..149a4a4bbb9c2 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -378,6 +378,25 @@ pub(crate) fn blank_lines( ))); context.push_diagnostic(diagnostic); } + // E302 + if token.kind() == TokenKind::Def + && !*is_in_class + && *blank_lines < 2 + && prev_line.is_some() + { + let mut diagnostic = + Diagnostic::new(BlankLinesTopLevel(*blank_lines as usize), token.range()); + #[allow(deprecated)] + diagnostic.set_fix(Fix::unspecified(Edit::insertion( + stylist + .line_ending() + .as_str() + .to_string() + .repeat(2 - *blank_lines as usize), + locator.line_start(token.range().start()), + ))); + context.push_diagnostic(diagnostic); + } if token.kind() == TokenKind::Class { if !*is_in_class { From 6ba1bb73d56af7fb87443830c38f7b3b10123cc4 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 20:59:21 +0900 Subject: [PATCH 17/47] Added E305. --- crates/ruff/src/checkers/logical_lines.rs | 6 +- .../rules/logical_lines/blank_lines.rs | 74 +++++++++++++------ 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 62c284314a75a..00c1d7b5284ce 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -47,10 +47,12 @@ pub(crate) fn check_logical_lines( let mut prev_line = None; let mut nb_blank_lines: u32 = 0; let mut blank_characters: u32 = 0; - let mut class_indent_level: usize = 0; let mut follows_decorator = false; let mut follows_def = false; let mut is_in_class = false; + let mut class_indent_level: usize = 0; + let mut is_in_fn = false; + let mut fn_indent_level: usize = 0; let mut prev_indent_level = None; let indent_char = stylist.indentation().as_char(); @@ -123,6 +125,8 @@ pub(crate) fn check_logical_lines( &mut follows_def, &mut is_in_class, &mut class_indent_level, + &mut is_in_fn, + &mut fn_indent_level, indent_level, locator, stylist, diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 149a4a4bbb9c2..2bd2deac2fe66 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -299,14 +299,13 @@ pub(crate) fn blank_lines( follows_def: &mut bool, is_in_class: &mut bool, class_indent_level: &mut usize, + is_in_fn: &mut bool, + fn_indent_level: &mut usize, indent_level: usize, locator: &Locator, stylist: &Stylist, context: &mut LogicalLinesContext, ) { - dbg!("#############################"); - dbg!(line.text()); - if line.is_empty() { *blank_lines += 1; *blank_characters += line.text().len() as u32; @@ -314,7 +313,6 @@ pub(crate) fn blank_lines( } for (token_idx, token) in line.tokens().iter().enumerate() { - dbg!(token); // E304 if *follows_decorator && *blank_lines > 0 { let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); @@ -397,33 +395,63 @@ pub(crate) fn blank_lines( ))); context.push_diagnostic(diagnostic); } + // E305 + if *blank_lines < 2 + && ((*is_in_class && indent_level == 0) || (*is_in_fn && indent_level == 0)) + { + let mut diagnostic = Diagnostic::new( + BlankLinesAfterFunctionOrClass(*blank_lines as usize), + token.range(), + ); + #[allow(deprecated)] + diagnostic.set_fix(Fix::unspecified(Edit::insertion( + stylist + .line_ending() + .as_str() + .to_string() + .repeat(2 - *blank_lines as usize), + locator.line_start(token.range().start()), + ))); + context.push_diagnostic(diagnostic); + } - if token.kind() == TokenKind::Class { - if !*is_in_class { - *class_indent_level = indent_level; + match token.kind() { + TokenKind::Class => { + if !*is_in_class { + *class_indent_level = indent_level; + } + *is_in_class = true; + return; } - *is_in_class = true; - return; + TokenKind::At => { + *follows_decorator = true; + + *follows_def = false; + *blank_lines = 0; + *blank_characters = 0; + return; + } + TokenKind::Def => { + if !*is_in_fn { + *fn_indent_level = indent_level; + } + *is_in_fn = true; + *follows_def = true; + + *follows_decorator = false; + *blank_lines = 0; + *blank_characters = 0; + return; + } + _ => {} } if indent_level <= *class_indent_level { *is_in_class = false; } - if token.kind() == TokenKind::At { - *follows_decorator = true; - - *follows_def = false; - *blank_lines = 0; - *blank_characters = 0; - return; - } else if token.kind() == TokenKind::Def { - *follows_def = true; - - *follows_decorator = false; - *blank_lines = 0; - *blank_characters = 0; - return; + if indent_level <= *fn_indent_level { + *is_in_fn = false; } } *follows_decorator = false; From d20fd0c98339d1db90f09859cfc4745f0bf16b72 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 21:16:10 +0900 Subject: [PATCH 18/47] Linting fixes. --- crates/ruff/src/checkers/logical_lines.rs | 36 +++++++++---------- .../src/rules/flake8_builtins/rules/rules.rs | 2 -- .../rules/logical_lines/blank_lines.rs | 13 +++---- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 00c1d7b5284ce..e7f264a64d0b2 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -38,9 +38,7 @@ pub(crate) fn check_logical_lines( ) -> Vec { let mut context = LogicalLinesContext::new(settings); - let should_fix_blank_lines = settings.rules.should_fix(Rule::BlankLineBetweenMethods); // FIXME: Rule::BlankLines let should_fix_missing_whitespace = settings.rules.should_fix(Rule::MissingWhitespace); - let should_fix_whitespace_before_parameters = settings.rules.should_fix(Rule::WhitespaceBeforeParameters); @@ -115,24 +113,22 @@ pub(crate) fn check_logical_lines( context.push(kind, range); } } - if should_fix_blank_lines || true { - blank_lines( - &line, - prev_line.as_ref(), - &mut nb_blank_lines, - &mut blank_characters, - &mut follows_decorator, - &mut follows_def, - &mut is_in_class, - &mut class_indent_level, - &mut is_in_fn, - &mut fn_indent_level, - indent_level, - locator, - stylist, - &mut context, - ); - } + blank_lines( + &line, + prev_line.as_ref(), + &mut nb_blank_lines, + &mut blank_characters, + &mut follows_decorator, + &mut follows_def, + &mut is_in_class, + &mut class_indent_level, + &mut is_in_fn, + &mut fn_indent_level, + indent_level, + locator, + stylist, + &mut context, + ); if !line.is_comment_only() && !line.is_empty() { prev_line = Some(line); diff --git a/crates/ruff/src/rules/flake8_builtins/rules/rules.rs b/crates/ruff/src/rules/flake8_builtins/rules/rules.rs index b28b04f643122..8b137891791fe 100644 --- a/crates/ruff/src/rules/flake8_builtins/rules/rules.rs +++ b/crates/ruff/src/rules/flake8_builtins/rules/rules.rs @@ -1,3 +1 @@ - - diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 2bd2deac2fe66..0c0d8509529c6 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -308,7 +308,8 @@ pub(crate) fn blank_lines( ) { if line.is_empty() { *blank_lines += 1; - *blank_characters += line.text().len() as u32; + *blank_characters += u32::try_from(line.text().len()) + .expect("The number of blank characters should be relatively small"); return; } @@ -319,11 +320,7 @@ pub(crate) fn blank_lines( let range = token.range(); diagnostic.set_fix(Fix::suggested(Edit::deletion( - locator.line_start(range.start()) - - TextSize::new( - u32::try_from(*blank_characters) - .expect("The number of blank characters should be relatively small"), - ), + locator.line_start(range.start()) - TextSize::new(*blank_characters), locator.line_start(range.start()), ))); context.push_diagnostic(diagnostic); @@ -396,9 +393,7 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } // E305 - if *blank_lines < 2 - && ((*is_in_class && indent_level == 0) || (*is_in_fn && indent_level == 0)) - { + if *blank_lines < 2 && (*is_in_fn || *is_in_class) && indent_level == 0 { let mut diagnostic = Diagnostic::new( BlankLinesAfterFunctionOrClass(*blank_lines as usize), token.range(), From 0dc80d5e900ae95fba25c4c0e0b19428a260d1ac Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 21:36:08 +0900 Subject: [PATCH 19/47] Put variables used to track the current state into a struct. --- crates/ruff/src/checkers/logical_lines.rs | 22 +-- .../rules/logical_lines/blank_lines.rs | 125 +++++++++++------- .../pycodestyle/rules/logical_lines/mod.rs | 3 +- 3 files changed, 80 insertions(+), 70 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index e7f264a64d0b2..2d873cfcecd4d 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -10,7 +10,8 @@ use crate::rules::pycodestyle::rules::logical_lines::{ blank_lines, extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword, missing_whitespace_around_operator, space_around_operator, whitespace_around_keywords, whitespace_around_named_parameter_equals, - whitespace_before_comment, whitespace_before_parameters, LogicalLines, TokenFlags, + whitespace_before_comment, whitespace_before_parameters, BlankLinesTrackingVars, LogicalLines, + TokenFlags, }; use crate::settings::Settings; @@ -42,16 +43,8 @@ pub(crate) fn check_logical_lines( let should_fix_whitespace_before_parameters = settings.rules.should_fix(Rule::WhitespaceBeforeParameters); + let mut blank_lines_tracking_vars = BlankLinesTrackingVars::default(); let mut prev_line = None; - let mut nb_blank_lines: u32 = 0; - let mut blank_characters: u32 = 0; - let mut follows_decorator = false; - let mut follows_def = false; - let mut is_in_class = false; - let mut class_indent_level: usize = 0; - let mut is_in_fn = false; - let mut fn_indent_level: usize = 0; - let mut prev_indent_level = None; let indent_char = stylist.indentation().as_char(); for line in &LogicalLines::from_tokens(tokens, locator) { @@ -116,14 +109,7 @@ pub(crate) fn check_logical_lines( blank_lines( &line, prev_line.as_ref(), - &mut nb_blank_lines, - &mut blank_characters, - &mut follows_decorator, - &mut follows_def, - &mut is_in_class, - &mut class_indent_level, - &mut is_in_fn, - &mut fn_indent_level, + &mut blank_lines_tracking_vars, indent_level, locator, stylist, diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 0c0d8509529c6..385333df7a811 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -13,6 +13,19 @@ use crate::checkers::logical_lines::LogicalLinesContext; use super::LogicalLine; +/// Contains variables used for the linting of blank lines. +#[derive(Default)] +pub(crate) struct BlankLinesTrackingVars { + blank_lines: u32, + blank_characters: u32, + follows_decorator: bool, + follows_def: bool, + is_in_class: bool, + class_indent_level: usize, + is_in_fn: bool, + fn_indent_level: usize, +} + /// Number of blank lines between various code parts. struct BlankLinesConfig; @@ -293,48 +306,50 @@ impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { pub(crate) fn blank_lines( line: &LogicalLine, prev_line: Option<&LogicalLine>, - blank_lines: &mut u32, - blank_characters: &mut u32, - follows_decorator: &mut bool, - follows_def: &mut bool, - is_in_class: &mut bool, - class_indent_level: &mut usize, - is_in_fn: &mut bool, - fn_indent_level: &mut usize, + tracked_vars: &mut BlankLinesTrackingVars, + // blank_lines: &mut u32, + // blank_characters: &mut u32, + // follows_decorator: &mut bool, + // follows_def: &mut bool, + // is_in_class: &mut bool, + // class_indent_level: &mut usize, + // is_in_fn: &mut bool, + // fn_indent_level: &mut usize, indent_level: usize, locator: &Locator, stylist: &Stylist, context: &mut LogicalLinesContext, ) { if line.is_empty() { - *blank_lines += 1; - *blank_characters += u32::try_from(line.text().len()) + tracked_vars.blank_lines += 1; + tracked_vars.blank_characters += u32::try_from(line.text().len()) .expect("The number of blank characters should be relatively small"); return; } for (token_idx, token) in line.tokens().iter().enumerate() { // E304 - if *follows_decorator && *blank_lines > 0 { + if tracked_vars.follows_decorator && tracked_vars.blank_lines > 0 { let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); let range = token.range(); diagnostic.set_fix(Fix::suggested(Edit::deletion( - locator.line_start(range.start()) - TextSize::new(*blank_characters), + locator.line_start(range.start()) - TextSize::new(tracked_vars.blank_characters), locator.line_start(range.start()), ))); context.push_diagnostic(diagnostic); } // E303 - else if token_idx == 0 && *blank_lines > BlankLinesConfig::TOP_LEVEL - || (*is_in_class && *blank_lines > BlankLinesConfig::METHOD) + else if token_idx == 0 && tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL + || (tracked_vars.is_in_class && tracked_vars.blank_lines > BlankLinesConfig::METHOD) { - let mut diagnostic = Diagnostic::new(TooManyBlankLines(*blank_lines), token.range()); + let mut diagnostic = + Diagnostic::new(TooManyBlankLines(tracked_vars.blank_lines), token.range()); let chars_to_remove = if indent_level > 0 { - *blank_characters - BlankLinesConfig::METHOD + tracked_vars.blank_characters - BlankLinesConfig::METHOD } else { - *blank_characters - BlankLinesConfig::TOP_LEVEL + tracked_vars.blank_characters - BlankLinesConfig::TOP_LEVEL }; let end = locator.line_start(token.range().start()); let start = end - TextSize::new(chars_to_remove); @@ -344,9 +359,12 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } // E306 - else if token.kind() == TokenKind::Def && *follows_def && *blank_lines == 0 { + else if token.kind() == TokenKind::Def + && tracked_vars.follows_def + && tracked_vars.blank_lines == 0 + { let mut diagnostic = Diagnostic::new( - BlankLinesBeforeNestedDefinition(*blank_lines), + BlankLinesBeforeNestedDefinition(tracked_vars.blank_lines), token.range(), ); #[allow(deprecated)] @@ -359,8 +377,8 @@ pub(crate) fn blank_lines( } // E301 if token.kind() == TokenKind::Def - && *is_in_class - && *blank_lines == 0 + && tracked_vars.is_in_class + && tracked_vars.blank_lines == 0 && prev_line .and_then(|prev_line| prev_line.tokens_trimmed().first()) .map_or(false, |token| token.kind() != TokenKind::Class) @@ -375,27 +393,32 @@ pub(crate) fn blank_lines( } // E302 if token.kind() == TokenKind::Def - && !*is_in_class - && *blank_lines < 2 + && !tracked_vars.is_in_class + && tracked_vars.blank_lines < 2 && prev_line.is_some() { - let mut diagnostic = - Diagnostic::new(BlankLinesTopLevel(*blank_lines as usize), token.range()); + let mut diagnostic = Diagnostic::new( + BlankLinesTopLevel(tracked_vars.blank_lines as usize), + token.range(), + ); #[allow(deprecated)] diagnostic.set_fix(Fix::unspecified(Edit::insertion( stylist .line_ending() .as_str() .to_string() - .repeat(2 - *blank_lines as usize), + .repeat(2 - tracked_vars.blank_lines as usize), locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); } // E305 - if *blank_lines < 2 && (*is_in_fn || *is_in_class) && indent_level == 0 { + if tracked_vars.blank_lines < 2 + && (tracked_vars.is_in_fn || tracked_vars.is_in_class) + && indent_level == 0 + { let mut diagnostic = Diagnostic::new( - BlankLinesAfterFunctionOrClass(*blank_lines as usize), + BlankLinesAfterFunctionOrClass(tracked_vars.blank_lines as usize), token.range(), ); #[allow(deprecated)] @@ -404,7 +427,7 @@ pub(crate) fn blank_lines( .line_ending() .as_str() .to_string() - .repeat(2 - *blank_lines as usize), + .repeat(2 - tracked_vars.blank_lines as usize), locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); @@ -412,45 +435,45 @@ pub(crate) fn blank_lines( match token.kind() { TokenKind::Class => { - if !*is_in_class { - *class_indent_level = indent_level; + if !tracked_vars.is_in_class { + tracked_vars.class_indent_level = indent_level; } - *is_in_class = true; + tracked_vars.is_in_class = true; return; } TokenKind::At => { - *follows_decorator = true; + tracked_vars.follows_decorator = true; - *follows_def = false; - *blank_lines = 0; - *blank_characters = 0; + tracked_vars.follows_def = false; + tracked_vars.blank_lines = 0; + tracked_vars.blank_characters = 0; return; } TokenKind::Def => { - if !*is_in_fn { - *fn_indent_level = indent_level; + if !tracked_vars.is_in_fn { + tracked_vars.fn_indent_level = indent_level; } - *is_in_fn = true; - *follows_def = true; + tracked_vars.is_in_fn = true; + tracked_vars.follows_def = true; - *follows_decorator = false; - *blank_lines = 0; - *blank_characters = 0; + tracked_vars.follows_decorator = false; + tracked_vars.blank_lines = 0; + tracked_vars.blank_characters = 0; return; } _ => {} } - if indent_level <= *class_indent_level { - *is_in_class = false; + if indent_level <= tracked_vars.class_indent_level { + tracked_vars.is_in_class = false; } - if indent_level <= *fn_indent_level { - *is_in_fn = false; + if indent_level <= tracked_vars.fn_indent_level { + tracked_vars.is_in_fn = false; } } - *follows_decorator = false; - *follows_def = false; - *blank_lines = 0; - *blank_characters = 0; + tracked_vars.follows_decorator = false; + tracked_vars.follows_def = false; + tracked_vars.blank_lines = 0; + tracked_vars.blank_characters = 0; } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 441289942a978..07e7f8c0756de 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -9,7 +9,8 @@ use ruff_python_ast::token_kind::TokenKind; pub(crate) use blank_lines::{ blank_lines, BlankLineAfterDecorator, BlankLineBetweenMethods, BlankLinesAfterFunctionOrClass, - BlankLinesBeforeNestedDefinition, BlankLinesTopLevel, TooManyBlankLines, + BlankLinesBeforeNestedDefinition, BlankLinesTopLevel, BlankLinesTrackingVars, + TooManyBlankLines, }; pub(crate) use extraneous_whitespace::{ extraneous_whitespace, WhitespaceAfterOpenBracket, WhitespaceBeforeCloseBracket, From 95cb0646ec36d06f046e757c3c5810df12107189 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 21:40:31 +0900 Subject: [PATCH 20/47] Added clippy allow --- .../src/rules/pycodestyle/rules/logical_lines/blank_lines.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 385333df7a811..9f6e06e77a7f8 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -15,6 +15,7 @@ use super::LogicalLine; /// Contains variables used for the linting of blank lines. #[derive(Default)] +#[allow(clippy::struct_excessive_bools)] pub(crate) struct BlankLinesTrackingVars { blank_lines: u32, blank_characters: u32, From a8242c16b1d8c0c4790d48eed9848121efbb80de Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 21:40:54 +0900 Subject: [PATCH 21/47] Add rules to ruff.schema.json --- ruff.schema.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ruff.schema.json b/ruff.schema.json index 1bcfb5fb08d67..55b7d7e78ff27 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1763,6 +1763,12 @@ "E273", "E274", "E275", + "E301", + "E302", + "E303", + "E304", + "E305", + "E306", "E4", "E40", "E401", From 210940a7487eb408cffeab0c98a144d0a1eb98e2 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 22:04:36 +0900 Subject: [PATCH 22/47] Put errors in order. --- .../rules/logical_lines/blank_lines.rs | 115 +++++++++--------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 9f6e06e77a7f8..97ce4be95b10d 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -17,13 +17,17 @@ use super::LogicalLine; #[derive(Default)] #[allow(clippy::struct_excessive_bools)] pub(crate) struct BlankLinesTrackingVars { + /// Number of consecutive blank lines. blank_lines: u32, + /// Number of blank characters in the blank lines (\n vs \r\n for example). blank_characters: u32, follows_decorator: bool, follows_def: bool, is_in_class: bool, + /// The indent level where the class started. class_indent_level: usize, is_in_fn: bool, + /// The indent level where the function started. fn_indent_level: usize, } @@ -31,9 +35,9 @@ pub(crate) struct BlankLinesTrackingVars { struct BlankLinesConfig; impl BlankLinesConfig { - /// Top level class and function. + /// Number of blank lines around top level classes and functions. const TOP_LEVEL: u32 = 2; - /// Methods and nested class and function. + /// Number of blank lines around methods and nested classes and functions. const METHOD: u32 = 1; } @@ -308,14 +312,6 @@ pub(crate) fn blank_lines( line: &LogicalLine, prev_line: Option<&LogicalLine>, tracked_vars: &mut BlankLinesTrackingVars, - // blank_lines: &mut u32, - // blank_characters: &mut u32, - // follows_decorator: &mut bool, - // follows_def: &mut bool, - // is_in_class: &mut bool, - // class_indent_level: &mut usize, - // is_in_fn: &mut bool, - // fn_indent_level: &mut usize, indent_level: usize, locator: &Locator, stylist: &Stylist, @@ -329,53 +325,6 @@ pub(crate) fn blank_lines( } for (token_idx, token) in line.tokens().iter().enumerate() { - // E304 - if tracked_vars.follows_decorator && tracked_vars.blank_lines > 0 { - let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); - - let range = token.range(); - diagnostic.set_fix(Fix::suggested(Edit::deletion( - locator.line_start(range.start()) - TextSize::new(tracked_vars.blank_characters), - locator.line_start(range.start()), - ))); - context.push_diagnostic(diagnostic); - } - // E303 - else if token_idx == 0 && tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL - || (tracked_vars.is_in_class && tracked_vars.blank_lines > BlankLinesConfig::METHOD) - { - let mut diagnostic = - Diagnostic::new(TooManyBlankLines(tracked_vars.blank_lines), token.range()); - - let chars_to_remove = if indent_level > 0 { - tracked_vars.blank_characters - BlankLinesConfig::METHOD - } else { - tracked_vars.blank_characters - BlankLinesConfig::TOP_LEVEL - }; - let end = locator.line_start(token.range().start()); - let start = end - TextSize::new(chars_to_remove); - #[allow(deprecated)] - diagnostic.set_fix(Fix::suggested(Edit::deletion(start, end))); - - context.push_diagnostic(diagnostic); - } - // E306 - else if token.kind() == TokenKind::Def - && tracked_vars.follows_def - && tracked_vars.blank_lines == 0 - { - let mut diagnostic = Diagnostic::new( - BlankLinesBeforeNestedDefinition(tracked_vars.blank_lines), - token.range(), - ); - #[allow(deprecated)] - diagnostic.set_fix(Fix::unspecified(Edit::insertion( - stylist.line_ending().as_str().to_string(), - locator.line_start(token.range().start()), - ))); - - context.push_diagnostic(diagnostic); - } // E301 if token.kind() == TokenKind::Def && tracked_vars.is_in_class @@ -392,6 +341,7 @@ pub(crate) fn blank_lines( ))); context.push_diagnostic(diagnostic); } + // E302 if token.kind() == TokenKind::Def && !tracked_vars.is_in_class @@ -413,6 +363,39 @@ pub(crate) fn blank_lines( ))); context.push_diagnostic(diagnostic); } + + // E303 + if token_idx == 0 && tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL + || (tracked_vars.is_in_class && tracked_vars.blank_lines > BlankLinesConfig::METHOD) + { + let mut diagnostic = + Diagnostic::new(TooManyBlankLines(tracked_vars.blank_lines), token.range()); + + let chars_to_remove = if indent_level > 0 { + tracked_vars.blank_characters - BlankLinesConfig::METHOD + } else { + tracked_vars.blank_characters - BlankLinesConfig::TOP_LEVEL + }; + let end = locator.line_start(token.range().start()); + let start = end - TextSize::new(chars_to_remove); + #[allow(deprecated)] + diagnostic.set_fix(Fix::suggested(Edit::deletion(start, end))); + + context.push_diagnostic(diagnostic); + } + + // E304 + if tracked_vars.follows_decorator && tracked_vars.blank_lines > 0 { + let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); + + let range = token.range(); + diagnostic.set_fix(Fix::suggested(Edit::deletion( + locator.line_start(range.start()) - TextSize::new(tracked_vars.blank_characters), + locator.line_start(range.start()), + ))); + context.push_diagnostic(diagnostic); + } + // E305 if tracked_vars.blank_lines < 2 && (tracked_vars.is_in_fn || tracked_vars.is_in_class) @@ -434,6 +417,24 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } + // E306 + if token.kind() == TokenKind::Def + && tracked_vars.follows_def + && tracked_vars.blank_lines == 0 + { + let mut diagnostic = Diagnostic::new( + BlankLinesBeforeNestedDefinition(tracked_vars.blank_lines), + token.range(), + ); + #[allow(deprecated)] + diagnostic.set_fix(Fix::unspecified(Edit::insertion( + stylist.line_ending().as_str().to_string(), + locator.line_start(token.range().start()), + ))); + + context.push_diagnostic(diagnostic); + } + match token.kind() { TokenKind::Class => { if !tracked_vars.is_in_class { From 00cfdce287b1c50bad3feed38da12eb66659de44 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 22:42:43 +0900 Subject: [PATCH 23/47] Fixed E303 --- .../rules/pycodestyle/rules/logical_lines/blank_lines.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 97ce4be95b10d..2a77d18f4f522 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -365,8 +365,10 @@ pub(crate) fn blank_lines( } // E303 - if token_idx == 0 && tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL - || (tracked_vars.is_in_class && tracked_vars.blank_lines > BlankLinesConfig::METHOD) + if token_idx == 0 + && (tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL + || ((tracked_vars.is_in_class || tracked_vars.is_in_fn) + && tracked_vars.blank_lines > BlankLinesConfig::METHOD)) { let mut diagnostic = Diagnostic::new(TooManyBlankLines(tracked_vars.blank_lines), token.range()); From 6183a1c53ad4a61e379d2fca7c1ac36f13057465 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 22:53:45 +0900 Subject: [PATCH 24/47] Add E301 snapshot --- ...ules__pycodestyle__tests__E301_E30.py.snap | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap new file mode 100644 index 0000000000000..dd25813f8be9f --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap @@ -0,0 +1,44 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +E30.py:6:5: E301 [*] Expected 1 blank line, found 0 + | + 6 | def a(): + 7 | pass + 8 | def b(): + | ^^^ E301 + 9 | pass +10 | #: E301:6:5 + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +3 3 | +4 4 | def a(): +5 5 | pass + 6 |+ +6 7 | def b(): +7 8 | pass +8 9 | #: E301:6:5 + +E30.py:14:5: E301 [*] Expected 1 blank line, found 0 + | +14 | pass +15 | # comment +16 | def b(): + | ^^^ E301 +17 | pass +18 | #: + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +11 11 | def a(): +12 12 | pass +13 13 | # comment + 14 |+ +14 15 | def b(): +15 16 | pass +16 17 | #: + + From e2923e0ef85363c89b06aef656974595d1c3a8f5 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 23:02:20 +0900 Subject: [PATCH 25/47] Add E302 snapshot --- ...ules__pycodestyle__tests__E302_E30.py.snap | 742 ++++++++++++++++++ 1 file changed, 742 insertions(+) create mode 100644 crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap new file mode 100644 index 0000000000000..25976db6dd258 --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap @@ -0,0 +1,742 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +E30.py:21:1: E302 [*] Expected 2 blank lines, found 0 + | +21 | #: E302:2:1 +22 | """Main module.""" +23 | def _main(): + | ^^^ E302 +24 | pass +25 | #: E302:2:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +18 18 | +19 19 | #: E302:2:1 +20 20 | """Main module.""" + 21 |+ + 22 |+ +21 23 | def _main(): +22 24 | pass +23 25 | #: E302:2:1 + +E30.py:25:1: E302 [*] Expected 2 blank lines, found 0 + | +25 | #: E302:2:1 +26 | import sys +27 | def get_sys_path(): + | ^^^ E302 +28 | return sys.path +29 | #: E302:4:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +22 22 | pass +23 23 | #: E302:2:1 +24 24 | import sys + 25 |+ + 26 |+ +25 27 | def get_sys_path(): +26 28 | return sys.path +27 29 | #: E302:4:1 + +E30.py:28:1: E302 [*] Expected 2 blank lines, found 0 + | +28 | return sys.path +29 | #: E302:4:1 +30 | def a(): + | ^^^ E302 +31 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +25 25 | def get_sys_path(): +26 26 | return sys.path +27 27 | #: E302:4:1 + 28 |+ + 29 |+ +28 30 | def a(): +29 31 | pass +30 32 | + +E30.py:31:1: E302 [*] Expected 2 blank lines, found 1 + | +31 | pass +32 | +33 | def b(): + | ^^^ E302 +34 | pass +35 | #: E302:6:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +28 28 | def a(): +29 29 | pass +30 30 | + 31 |+ +31 32 | def b(): +32 33 | pass +33 34 | #: E302:6:1 + +E30.py:34:1: E302 [*] Expected 2 blank lines, found 0 + | +34 | pass +35 | #: E302:6:1 +36 | def a(): + | ^^^ E302 +37 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +31 31 | def b(): +32 32 | pass +33 33 | #: E302:6:1 + 34 |+ + 35 |+ +34 36 | def a(): +35 37 | pass +36 38 | + +E30.py:39:1: E302 [*] Expected 2 blank lines, found 1 + | +39 | # comment +40 | +41 | def b(): + | ^^^ E302 +42 | pass +43 | #: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +36 36 | +37 37 | # comment +38 38 | + 39 |+ +39 40 | def b(): +40 41 | pass +41 42 | #: + +E30.py:43:1: E302 [*] Expected 2 blank lines, found 0 + | +43 | #: +44 | #: E302:4:1 +45 | def a(): + | ^^^ E302 +46 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +40 40 | pass +41 41 | #: +42 42 | #: E302:4:1 + 43 |+ + 44 |+ +43 45 | def a(): +44 46 | pass +45 47 | + +E30.py:46:7: E302 [*] Expected 2 blank lines, found 1 + | +46 | pass +47 | +48 | async def b(): + | ^^^ E302 +49 | pass +50 | #: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +43 43 | def a(): +44 44 | pass +45 45 | + 46 |+ +46 47 | async def b(): +47 48 | pass +48 49 | #: + +E30.py:65:1: E302 [*] Expected 2 blank lines, found 0 + | +65 | print +66 | #: E303:5:5 E303:8:5 +67 | def a(): + | ^^^ E302 +68 | print + | + = help: Add missing blank line(s) + +ℹ Suggested fix +62 62 | +63 63 | print +64 64 | #: E303:5:5 E303:8:5 + 65 |+ + 66 |+ +65 67 | def a(): +66 68 | print +67 69 | + +E30.py:81:1: E302 [*] Expected 2 blank lines, found 1 + | +81 | @decorator +82 | +83 | def function(): + | ^^^ E302 +84 | pass +85 | #: E303:5:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +78 78 | #: E304:3:1 +79 79 | @decorator +80 80 | + 81 |+ +81 82 | def function(): +82 83 | pass +83 84 | #: E303:5:1 + +E30.py:94:1: E302 [*] Expected 2 blank lines, found 0 + | +94 | #: E305:7:1 +95 | def a(): + | ^^^ E302 +96 | print + | + = help: Add missing blank line(s) + +ℹ Suggested fix +91 91 | #: +92 92 | +93 93 | #: E305:7:1 + 94 |+ + 95 |+ +94 96 | def a(): +95 97 | print +96 98 | + +E30.py:102:1: E302 [*] Expected 2 blank lines, found 0 + | +102 | a() +103 | #: E305:8:1 +104 | def a(): + | ^^^ E302 +105 | print + | + = help: Add missing blank line(s) + +ℹ Suggested fix +99 99 | # another comment +100 100 | a() +101 101 | #: E305:8:1 + 102 |+ + 103 |+ +102 104 | def a(): +103 105 | print +104 106 | + +E30.py:114:1: E302 [*] Expected 2 blank lines, found 0 + | +114 | pass +115 | #: E305:5:1 +116 | def a(): + | ^^^ E302 +117 | print + | + = help: Add missing blank line(s) + +ℹ Suggested fix +111 111 | except Exception: +112 112 | pass +113 113 | #: E305:5:1 + 114 |+ + 115 |+ +114 116 | def a(): +115 117 | print +116 118 | + +E30.py:123:1: E302 [*] Expected 2 blank lines, found 0 + | +123 | #: E306:3:5 +124 | def a(): + | ^^^ E302 +125 | x = 1 +126 | def b(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +120 120 | #: +121 121 | +122 122 | #: E306:3:5 + 123 |+ + 124 |+ +123 125 | def a(): +124 126 | x = 1 +125 127 | def b(): + +E30.py:125:5: E302 [*] Expected 2 blank lines, found 0 + | +125 | def a(): +126 | x = 1 +127 | def b(): + | ^^^ E302 +128 | pass +129 | #: E306:3:5 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +122 122 | #: E306:3:5 +123 123 | def a(): +124 124 | x = 1 + 125 |+ + 126 |+ +125 127 | def b(): +126 128 | pass +127 129 | #: E306:3:5 + +E30.py:128:7: E302 [*] Expected 2 blank lines, found 0 + | +128 | pass +129 | #: E306:3:5 +130 | async def a(): + | ^^^ E302 +131 | x = 1 +132 | def b(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +125 125 | def b(): +126 126 | pass +127 127 | #: E306:3:5 + 128 |+ + 129 |+ +128 130 | async def a(): +129 131 | x = 1 +130 132 | def b(): + +E30.py:130:5: E302 [*] Expected 2 blank lines, found 0 + | +130 | async def a(): +131 | x = 1 +132 | def b(): + | ^^^ E302 +133 | pass +134 | #: E306:3:5 E306:5:9 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +127 127 | #: E306:3:5 +128 128 | async def a(): +129 129 | x = 1 + 130 |+ + 131 |+ +130 132 | def b(): +131 133 | pass +132 134 | #: E306:3:5 E306:5:9 + +E30.py:133:1: E302 [*] Expected 2 blank lines, found 0 + | +133 | pass +134 | #: E306:3:5 E306:5:9 +135 | def a(): + | ^^^ E302 +136 | x = 2 +137 | def b(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +130 130 | def b(): +131 131 | pass +132 132 | #: E306:3:5 E306:5:9 + 133 |+ + 134 |+ +133 135 | def a(): +134 136 | x = 2 +135 137 | def b(): + +E30.py:135:5: E302 [*] Expected 2 blank lines, found 0 + | +135 | def a(): +136 | x = 2 +137 | def b(): + | ^^^ E302 +138 | x = 1 +139 | def c(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +132 132 | #: E306:3:5 E306:5:9 +133 133 | def a(): +134 134 | x = 2 + 135 |+ + 136 |+ +135 137 | def b(): +136 138 | x = 1 +137 139 | def c(): + +E30.py:137:9: E302 [*] Expected 2 blank lines, found 0 + | +137 | def b(): +138 | x = 1 +139 | def c(): + | ^^^ E302 +140 | pass +141 | #: E306:3:5 E306:6:5 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +134 134 | x = 2 +135 135 | def b(): +136 136 | x = 1 + 137 |+ + 138 |+ +137 139 | def c(): +138 140 | pass +139 141 | #: E306:3:5 E306:6:5 + +E30.py:140:1: E302 [*] Expected 2 blank lines, found 0 + | +140 | pass +141 | #: E306:3:5 E306:6:5 +142 | def a(): + | ^^^ E302 +143 | x = 1 +144 | class C: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +137 137 | def c(): +138 138 | pass +139 139 | #: E306:3:5 E306:6:5 + 140 |+ + 141 |+ +140 142 | def a(): +141 143 | x = 1 +142 144 | class C: + +E30.py:145:5: E302 [*] Expected 2 blank lines, found 0 + | +145 | pass +146 | x = 2 +147 | def b(): + | ^^^ E302 +148 | pass +149 | #: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +142 142 | class C: +143 143 | pass +144 144 | x = 2 + 145 |+ + 146 |+ +145 147 | def b(): +146 148 | pass +147 149 | #: + +E30.py:161:8: E302 [*] Expected 2 blank lines, found 0 + | +161 | # Previously just E272:1:6 E272:4:6 +162 | #: E302:4:1 E271:1:6 E271:4:6 +163 | async def x(): + | ^^^ E302 +164 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +158 158 | main() +159 159 | # Previously just E272:1:6 E272:4:6 +160 160 | #: E302:4:1 E271:1:6 E271:4:6 + 161 |+ + 162 |+ +161 163 | async def x(): +162 164 | pass +163 165 | + +E30.py:164:8: E302 [*] Expected 2 blank lines, found 1 + | +164 | pass +165 | +166 | async def x(y: int = 1): + | ^^^ E302 +167 | pass +168 | #: E704:3:1 E302:3:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +161 161 | async def x(): +162 162 | pass +163 163 | + 164 |+ +164 165 | async def x(y: int = 1): +165 166 | pass +166 167 | #: E704:3:1 E302:3:1 + +E30.py:167:1: E302 [*] Expected 2 blank lines, found 0 + | +167 | pass +168 | #: E704:3:1 E302:3:1 +169 | def bar(): + | ^^^ E302 +170 | pass +171 | def baz(): pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +164 164 | async def x(y: int = 1): +165 165 | pass +166 166 | #: E704:3:1 E302:3:1 + 167 |+ + 168 |+ +167 169 | def bar(): +168 170 | pass +169 171 | def baz(): pass + +E30.py:169:1: E302 [*] Expected 2 blank lines, found 0 + | +169 | def bar(): +170 | pass +171 | def baz(): pass + | ^^^ E302 +172 | #: E704:1:1 E302:2:1 +173 | def bar(): pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +166 166 | #: E704:3:1 E302:3:1 +167 167 | def bar(): +168 168 | pass + 169 |+ + 170 |+ +169 171 | def baz(): pass +170 172 | #: E704:1:1 E302:2:1 +171 173 | def bar(): pass + +E30.py:171:1: E302 [*] Expected 2 blank lines, found 0 + | +171 | def baz(): pass +172 | #: E704:1:1 E302:2:1 +173 | def bar(): pass + | ^^^ E302 +174 | def baz(): +175 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +168 168 | pass +169 169 | def baz(): pass +170 170 | #: E704:1:1 E302:2:1 + 171 |+ + 172 |+ +171 173 | def bar(): pass +172 174 | def baz(): +173 175 | pass + +E30.py:172:1: E302 [*] Expected 2 blank lines, found 0 + | +172 | #: E704:1:1 E302:2:1 +173 | def bar(): pass +174 | def baz(): + | ^^^ E302 +175 | pass +176 | #: E704:4:5 E306:4:5 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +169 169 | def baz(): pass +170 170 | #: E704:1:1 E302:2:1 +171 171 | def bar(): pass + 172 |+ + 173 |+ +172 174 | def baz(): +173 175 | pass +174 176 | #: E704:4:5 E306:4:5 + +E30.py:175:1: E302 [*] Expected 2 blank lines, found 0 + | +175 | pass +176 | #: E704:4:5 E306:4:5 +177 | def foo(): + | ^^^ E302 +178 | def bar(): +179 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +172 172 | def baz(): +173 173 | pass +174 174 | #: E704:4:5 E306:4:5 + 175 |+ + 176 |+ +175 177 | def foo(): +176 178 | def bar(): +177 179 | pass + +E30.py:176:5: E302 [*] Expected 2 blank lines, found 0 + | +176 | #: E704:4:5 E306:4:5 +177 | def foo(): +178 | def bar(): + | ^^^ E302 +179 | pass +180 | def baz(): pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +173 173 | pass +174 174 | #: E704:4:5 E306:4:5 +175 175 | def foo(): + 176 |+ + 177 |+ +176 178 | def bar(): +177 179 | pass +178 180 | def baz(): pass + +E30.py:178:5: E302 [*] Expected 2 blank lines, found 0 + | +178 | def bar(): +179 | pass +180 | def baz(): pass + | ^^^ E302 +181 | #: E704:2:5 E306:3:5 +182 | def foo(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +175 175 | def foo(): +176 176 | def bar(): +177 177 | pass + 178 |+ + 179 |+ +178 180 | def baz(): pass +179 181 | #: E704:2:5 E306:3:5 +180 182 | def foo(): + +E30.py:180:1: E302 [*] Expected 2 blank lines, found 0 + | +180 | def baz(): pass +181 | #: E704:2:5 E306:3:5 +182 | def foo(): + | ^^^ E302 +183 | def bar(): pass +184 | def baz(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +177 177 | pass +178 178 | def baz(): pass +179 179 | #: E704:2:5 E306:3:5 + 180 |+ + 181 |+ +180 182 | def foo(): +181 183 | def bar(): pass +182 184 | def baz(): + +E30.py:181:5: E302 [*] Expected 2 blank lines, found 0 + | +181 | #: E704:2:5 E306:3:5 +182 | def foo(): +183 | def bar(): pass + | ^^^ E302 +184 | def baz(): +185 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +178 178 | def baz(): pass +179 179 | #: E704:2:5 E306:3:5 +180 180 | def foo(): + 181 |+ + 182 |+ +181 183 | def bar(): pass +182 184 | def baz(): +183 185 | pass + +E30.py:182:5: E302 [*] Expected 2 blank lines, found 0 + | +182 | def foo(): +183 | def bar(): pass +184 | def baz(): + | ^^^ E302 +185 | pass +186 | #: E302:5:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +179 179 | #: E704:2:5 E306:3:5 +180 180 | def foo(): +181 181 | def bar(): pass + 182 |+ + 183 |+ +182 184 | def baz(): +183 185 | pass +184 186 | #: E302:5:1 + +E30.py:185:1: E302 [*] Expected 2 blank lines, found 0 + | +185 | pass +186 | #: E302:5:1 +187 | def f(): + | ^^^ E302 +188 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +182 182 | def baz(): +183 183 | pass +184 184 | #: E302:5:1 + 185 |+ + 186 |+ +185 187 | def f(): +186 188 | pass +187 189 | + +E30.py:190:1: E302 [*] Expected 2 blank lines, found 0 + | +190 | # wat +191 | @hi +192 | def g(): + | ^^^ E302 +193 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +187 187 | +188 188 | # wat +189 189 | @hi + 190 |+ + 191 |+ +190 192 | def g(): +191 193 | pass + + From db678a8f5b1417864d69062c45571581a1326f78 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 23:14:16 +0900 Subject: [PATCH 26/47] Add E305 snapshot --- ...ules__pycodestyle__tests__E305_E30.py.snap | 611 ++++++++++++++++++ 1 file changed, 611 insertions(+) create mode 100644 crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap new file mode 100644 index 0000000000000..dab921be603ad --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap @@ -0,0 +1,611 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +E30.py:8:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | + 8 | def b(): + 9 | pass +10 | #: E301:6:5 + | ^^^^^^^^^^^ E305 +11 | class X: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +5 5 | pass +6 6 | def b(): +7 7 | pass + 8 |+ + 9 |+ +8 10 | #: E301:6:5 +9 11 | class X: +10 12 | + +E30.py:16:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +16 | def b(): +17 | pass +18 | #: + | ^^ E305 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +13 13 | # comment +14 14 | def b(): +15 15 | pass + 16 |+ + 17 |+ +16 18 | #: +17 19 | +18 20 | + +E30.py:23:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +23 | def _main(): +24 | pass +25 | #: E302:2:1 + | ^^^^^^^^^^^ E305 +26 | import sys +27 | def get_sys_path(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +20 20 | """Main module.""" +21 21 | def _main(): +22 22 | pass + 23 |+ + 24 |+ +23 25 | #: E302:2:1 +24 26 | import sys +25 27 | def get_sys_path(): + +E30.py:27:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +27 | def get_sys_path(): +28 | return sys.path +29 | #: E302:4:1 + | ^^^^^^^^^^^ E305 +30 | def a(): +31 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +24 24 | import sys +25 25 | def get_sys_path(): +26 26 | return sys.path + 27 |+ + 28 |+ +27 29 | #: E302:4:1 +28 30 | def a(): +29 31 | pass + +E30.py:31:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +31 | pass +32 | +33 | def b(): + | E305 +34 | pass +35 | #: E302:6:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +28 28 | def a(): +29 29 | pass +30 30 | + 31 |+ +31 32 | def b(): +32 33 | pass +33 34 | #: E302:6:1 + +E30.py:33:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +33 | def b(): +34 | pass +35 | #: E302:6:1 + | ^^^^^^^^^^^ E305 +36 | def a(): +37 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +30 30 | +31 31 | def b(): +32 32 | pass + 33 |+ + 34 |+ +33 35 | #: E302:6:1 +34 36 | def a(): +35 37 | pass + +E30.py:37:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +37 | pass +38 | +39 | # comment + | ^^^^^^^^^ E305 +40 | +41 | def b(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +34 34 | def a(): +35 35 | pass +36 36 | + 37 |+ +37 38 | # comment +38 39 | +39 40 | def b(): + +E30.py:41:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +41 | def b(): +42 | pass +43 | #: + | ^^ E305 +44 | #: E302:4:1 +45 | def a(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +38 38 | +39 39 | def b(): +40 40 | pass + 41 |+ + 42 |+ +41 43 | #: +42 44 | #: E302:4:1 +43 45 | def a(): + +E30.py:46:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +46 | pass +47 | +48 | async def b(): + | E305 +49 | pass +50 | #: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +43 43 | def a(): +44 44 | pass +45 45 | + 46 |+ +46 47 | async def b(): +47 48 | pass +48 49 | #: + +E30.py:48:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +48 | async def b(): +49 | pass +50 | #: + | ^^ E305 +51 | +52 | #: E303:5:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +45 45 | +46 46 | async def b(): +47 47 | pass + 48 |+ + 49 |+ +48 50 | #: +49 51 | +50 52 | #: E303:5:1 + +E30.py:75:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +75 | print +76 | #: + | ^^ E305 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +72 72 | # another comment +73 73 | +74 74 | print + 75 |+ + 76 |+ +75 77 | #: +76 78 | +77 79 | + +E30.py:83:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +83 | def function(): +84 | pass +85 | #: E303:5:1 + | ^^^^^^^^^^^ E305 +86 | #!python + | + = help: Add missing blank line(s) + +ℹ Suggested fix +80 80 | +81 81 | def function(): +82 82 | pass + 83 |+ + 84 |+ +83 85 | #: E303:5:1 +84 86 | #!python +85 87 | + +E30.py:100:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +100 | # another comment +101 | a() + | E305 +102 | #: E305:8:1 +103 | def a(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +97 97 | # comment +98 98 | +99 99 | # another comment + 100 |+ + 101 |+ +100 102 | a() +101 103 | #: E305:8:1 +102 104 | def a(): + +E30.py:109:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +109 | # another comment +110 | +111 | try: + | E305 +112 | a() +113 | except Exception: + | + = help: Add missing blank line(s) + +ℹ Suggested fix +106 106 | +107 107 | # another comment +108 108 | + 109 |+ +109 110 | try: +110 111 | a() +111 112 | except Exception: + +E30.py:117:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +117 | print +118 | +119 | # Two spaces before comments, too. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E305 +120 | if a(): +121 | a() + | + = help: Add missing blank line(s) + +ℹ Suggested fix +114 114 | def a(): +115 115 | print +116 116 | + 117 |+ +117 118 | # Two spaces before comments, too. +118 119 | if a(): +119 120 | a() + +E30.py:127:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +127 | def b(): +128 | pass +129 | #: E306:3:5 + | ^^^^^^^^^^^ E305 +130 | async def a(): +131 | x = 1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +124 124 | x = 1 +125 125 | def b(): +126 126 | pass + 127 |+ + 128 |+ +127 129 | #: E306:3:5 +128 130 | async def a(): +129 131 | x = 1 + +E30.py:132:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +132 | def b(): +133 | pass +134 | #: E306:3:5 E306:5:9 + | ^^^^^^^^^^^^^^^^^^^^ E305 +135 | def a(): +136 | x = 2 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +129 129 | x = 1 +130 130 | def b(): +131 131 | pass + 132 |+ + 133 |+ +132 134 | #: E306:3:5 E306:5:9 +133 135 | def a(): +134 136 | x = 2 + +E30.py:139:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +139 | def c(): +140 | pass +141 | #: E306:3:5 E306:6:5 + | ^^^^^^^^^^^^^^^^^^^^ E305 +142 | def a(): +143 | x = 1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +136 136 | x = 1 +137 137 | def c(): +138 138 | pass + 139 |+ + 140 |+ +139 141 | #: E306:3:5 E306:6:5 +140 142 | def a(): +141 143 | x = 1 + +E30.py:147:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +147 | def b(): +148 | pass +149 | #: + | ^^ E305 +150 | +151 | #: E305:8:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +144 144 | x = 2 +145 145 | def b(): +146 146 | pass + 147 |+ + 148 |+ +147 149 | #: +148 150 | +149 151 | #: E305:8:1 + +E30.py:157:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +157 | blah, blah +158 | +159 | if __name__ == '__main__': + | E305 +160 | main() +161 | # Previously just E272:1:6 E272:4:6 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +154 154 | def main(): +155 155 | blah, blah +156 156 | + 157 |+ +157 158 | if __name__ == '__main__': +158 159 | main() +159 160 | # Previously just E272:1:6 E272:4:6 + +E30.py:164:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +164 | pass +165 | +166 | async def x(y: int = 1): + | E305 +167 | pass +168 | #: E704:3:1 E302:3:1 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +161 161 | async def x(): +162 162 | pass +163 163 | + 164 |+ +164 165 | async def x(y: int = 1): +165 166 | pass +166 167 | #: E704:3:1 E302:3:1 + +E30.py:166:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +166 | async def x(y: int = 1): +167 | pass +168 | #: E704:3:1 E302:3:1 + | ^^^^^^^^^^^^^^^^^^^^ E305 +169 | def bar(): +170 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +163 163 | +164 164 | async def x(y: int = 1): +165 165 | pass + 166 |+ + 167 |+ +166 168 | #: E704:3:1 E302:3:1 +167 169 | def bar(): +168 170 | pass + +E30.py:169:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +169 | def bar(): +170 | pass +171 | def baz(): pass + | E305 +172 | #: E704:1:1 E302:2:1 +173 | def bar(): pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +166 166 | #: E704:3:1 E302:3:1 +167 167 | def bar(): +168 168 | pass + 169 |+ + 170 |+ +169 171 | def baz(): pass +170 172 | #: E704:1:1 E302:2:1 +171 173 | def bar(): pass + +E30.py:170:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +170 | pass +171 | def baz(): pass +172 | #: E704:1:1 E302:2:1 + | ^^^^^^^^^^^^^^^^^^^^ E305 +173 | def bar(): pass +174 | def baz(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +167 167 | def bar(): +168 168 | pass +169 169 | def baz(): pass + 170 |+ + 171 |+ +170 172 | #: E704:1:1 E302:2:1 +171 173 | def bar(): pass +172 174 | def baz(): + +E30.py:172:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +172 | #: E704:1:1 E302:2:1 +173 | def bar(): pass +174 | def baz(): + | ^^^ E305 +175 | pass +176 | #: E704:4:5 E306:4:5 + | + = help: Add missing blank line(s) + +ℹ Suggested fix +169 169 | def baz(): pass +170 170 | #: E704:1:1 E302:2:1 +171 171 | def bar(): pass + 172 |+ + 173 |+ +172 174 | def baz(): +173 175 | pass +174 176 | #: E704:4:5 E306:4:5 + +E30.py:174:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +174 | def baz(): +175 | pass +176 | #: E704:4:5 E306:4:5 + | ^^^^^^^^^^^^^^^^^^^^ E305 +177 | def foo(): +178 | def bar(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +171 171 | def bar(): pass +172 172 | def baz(): +173 173 | pass + 174 |+ + 175 |+ +174 176 | #: E704:4:5 E306:4:5 +175 177 | def foo(): +176 178 | def bar(): + +E30.py:179:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +179 | pass +180 | def baz(): pass +181 | #: E704:2:5 E306:3:5 + | ^^^^^^^^^^^^^^^^^^^^ E305 +182 | def foo(): +183 | def bar(): pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +176 176 | def bar(): +177 177 | pass +178 178 | def baz(): pass + 179 |+ + 180 |+ +179 181 | #: E704:2:5 E306:3:5 +180 182 | def foo(): +181 183 | def bar(): pass + +E30.py:184:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +184 | def baz(): +185 | pass +186 | #: E302:5:1 + | ^^^^^^^^^^^ E305 +187 | def f(): +188 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +181 181 | def bar(): pass +182 182 | def baz(): +183 183 | pass + 184 |+ + 185 |+ +184 186 | #: E302:5:1 +185 187 | def f(): +186 188 | pass + +E30.py:188:1: E305 [*] expected 2 blank lines after class or function definition, found (1) + | +188 | pass +189 | +190 | # wat + | ^^^^^ E305 +191 | @hi +192 | def g(): + | + = help: Add missing blank line(s) + +ℹ Suggested fix +185 185 | def f(): +186 186 | pass +187 187 | + 188 |+ +188 189 | # wat +189 190 | @hi +190 191 | def g(): + +E30.py:192:1: E305 [*] expected 2 blank lines after class or function definition, found (0) + | +192 | def g(): +193 | pass + | + = help: Add missing blank line(s) + +ℹ Suggested fix +189 189 | @hi +190 190 | def g(): +191 191 | pass + 192 |+ + 193 |+ + + From 5c4b75b850454cac4ba7d3201e4ec5eb341101cd Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 23:19:24 +0900 Subject: [PATCH 27/47] Add E306 snapshot --- .../rules/logical_lines/blank_lines.rs | 23 +- ...ules__pycodestyle__tests__E306_E30.py.snap | 244 ++++++++++++++++++ 2 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 2a77d18f4f522..2f05c886be38b 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -263,7 +263,7 @@ impl AlwaysAutofixableViolation for BlankLinesAfterFunctionOrClass { } /// ## What it does -/// Checks for blank lines after end of function or class. +/// Checks for for 1 blank line between nested functions/classes definitions. /// /// ## Why is this bad? /// PEP 8 recommends the using blank lines as following: @@ -282,6 +282,7 @@ impl AlwaysAutofixableViolation for BlankLinesAfterFunctionOrClass { /// Use instead: /// ```python /// def outer(): +/// /// def inner(): /// pass /// @@ -419,9 +420,17 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } + if indent_level <= tracked_vars.class_indent_level { + tracked_vars.is_in_class = false; + } + + if indent_level <= tracked_vars.fn_indent_level { + tracked_vars.is_in_fn = false; + } + // E306 - if token.kind() == TokenKind::Def - && tracked_vars.follows_def + if matches!(token.kind(), TokenKind::Def | TokenKind::Class) + && (tracked_vars.is_in_class || tracked_vars.is_in_fn) && tracked_vars.blank_lines == 0 { let mut diagnostic = Diagnostic::new( @@ -467,14 +476,6 @@ pub(crate) fn blank_lines( } _ => {} } - - if indent_level <= tracked_vars.class_indent_level { - tracked_vars.is_in_class = false; - } - - if indent_level <= tracked_vars.fn_indent_level { - tracked_vars.is_in_fn = false; - } } tracked_vars.follows_decorator = false; tracked_vars.follows_def = false; diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap new file mode 100644 index 0000000000000..b82be0b079c61 --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap @@ -0,0 +1,244 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +E30.py:6:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | + 6 | def a(): + 7 | pass + 8 | def b(): + | ^^^ E306 + 9 | pass +10 | #: E301:6:5 + | + = help: Add missing blank line + +ℹ Suggested fix +3 3 | +4 4 | def a(): +5 5 | pass + 6 |+ +6 7 | def b(): +7 8 | pass +8 9 | #: E301:6:5 + +E30.py:14:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +14 | pass +15 | # comment +16 | def b(): + | ^^^ E306 +17 | pass +18 | #: + | + = help: Add missing blank line + +ℹ Suggested fix +11 11 | def a(): +12 12 | pass +13 13 | # comment + 14 |+ +14 15 | def b(): +15 16 | pass +16 17 | #: + +E30.py:125:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +125 | def a(): +126 | x = 1 +127 | def b(): + | ^^^ E306 +128 | pass +129 | #: E306:3:5 + | + = help: Add missing blank line + +ℹ Suggested fix +122 122 | #: E306:3:5 +123 123 | def a(): +124 124 | x = 1 + 125 |+ +125 126 | def b(): +126 127 | pass +127 128 | #: E306:3:5 + +E30.py:130:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +130 | async def a(): +131 | x = 1 +132 | def b(): + | ^^^ E306 +133 | pass +134 | #: E306:3:5 E306:5:9 + | + = help: Add missing blank line + +ℹ Suggested fix +127 127 | #: E306:3:5 +128 128 | async def a(): +129 129 | x = 1 + 130 |+ +130 131 | def b(): +131 132 | pass +132 133 | #: E306:3:5 E306:5:9 + +E30.py:135:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +135 | def a(): +136 | x = 2 +137 | def b(): + | ^^^ E306 +138 | x = 1 +139 | def c(): + | + = help: Add missing blank line + +ℹ Suggested fix +132 132 | #: E306:3:5 E306:5:9 +133 133 | def a(): +134 134 | x = 2 + 135 |+ +135 136 | def b(): +136 137 | x = 1 +137 138 | def c(): + +E30.py:137:9: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +137 | def b(): +138 | x = 1 +139 | def c(): + | ^^^ E306 +140 | pass +141 | #: E306:3:5 E306:6:5 + | + = help: Add missing blank line + +ℹ Suggested fix +134 134 | x = 2 +135 135 | def b(): +136 136 | x = 1 + 137 |+ +137 138 | def c(): +138 139 | pass +139 140 | #: E306:3:5 E306:6:5 + +E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +142 | def a(): +143 | x = 1 +144 | class C: + | ^^^^^ E306 +145 | pass +146 | x = 2 + | + = help: Add missing blank line + +ℹ Suggested fix +139 139 | #: E306:3:5 E306:6:5 +140 140 | def a(): +141 141 | x = 1 + 142 |+ +142 143 | class C: +143 144 | pass +144 145 | x = 2 + +E30.py:145:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +145 | pass +146 | x = 2 +147 | def b(): + | ^^^ E306 +148 | pass +149 | #: + | + = help: Add missing blank line + +ℹ Suggested fix +142 142 | class C: +143 143 | pass +144 144 | x = 2 + 145 |+ +145 146 | def b(): +146 147 | pass +147 148 | #: + +E30.py:176:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +176 | #: E704:4:5 E306:4:5 +177 | def foo(): +178 | def bar(): + | ^^^ E306 +179 | pass +180 | def baz(): pass + | + = help: Add missing blank line + +ℹ Suggested fix +173 173 | pass +174 174 | #: E704:4:5 E306:4:5 +175 175 | def foo(): + 176 |+ +176 177 | def bar(): +177 178 | pass +178 179 | def baz(): pass + +E30.py:178:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +178 | def bar(): +179 | pass +180 | def baz(): pass + | ^^^ E306 +181 | #: E704:2:5 E306:3:5 +182 | def foo(): + | + = help: Add missing blank line + +ℹ Suggested fix +175 175 | def foo(): +176 176 | def bar(): +177 177 | pass + 178 |+ +178 179 | def baz(): pass +179 180 | #: E704:2:5 E306:3:5 +180 181 | def foo(): + +E30.py:181:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +181 | #: E704:2:5 E306:3:5 +182 | def foo(): +183 | def bar(): pass + | ^^^ E306 +184 | def baz(): +185 | pass + | + = help: Add missing blank line + +ℹ Suggested fix +178 178 | def baz(): pass +179 179 | #: E704:2:5 E306:3:5 +180 180 | def foo(): + 181 |+ +181 182 | def bar(): pass +182 183 | def baz(): +183 184 | pass + +E30.py:182:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +182 | def foo(): +183 | def bar(): pass +184 | def baz(): + | ^^^ E306 +185 | pass +186 | #: E302:5:1 + | + = help: Add missing blank line + +ℹ Suggested fix +179 179 | #: E704:2:5 E306:3:5 +180 180 | def foo(): +181 181 | def bar(): pass + 182 |+ +182 183 | def baz(): +183 184 | pass +184 185 | #: E302:5:1 + + From 88a1fa4741b7b74c9a3c70ce8ef9493e79cb3b48 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 23:22:45 +0900 Subject: [PATCH 28/47] Add E303 snapshot --- ...ules__pycodestyle__tests__E303_E30.py.snap | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap new file mode 100644 index 0000000000000..371a666886a94 --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap @@ -0,0 +1,92 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +E30.py:55:1: E303 [*] Too many blank lines (3) + | +55 | print + | ^^^^^ E303 +56 | #: E303:5:1 +57 | print + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +51 51 | print +52 52 | +53 53 | +54 |- +55 54 | print +56 55 | #: E303:5:1 +57 56 | print + +E30.py:61:1: E303 [*] Too many blank lines (3) + | +61 | # comment + | ^^^^^^^^^ E303 +62 | +63 | print + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +57 57 | print +58 58 | +59 59 | +60 |- +61 60 | # comment +62 61 | +63 62 | print + +E30.py:69:5: E303 [*] Too many blank lines (2) + | +69 | # comment + | ^^^^^^^^^ E303 + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +65 65 | def a(): +66 66 | print +67 67 | +68 |- +69 68 | # comment +70 69 | +71 70 | + +E30.py:72:5: E303 [*] Too many blank lines (2) + | +72 | # another comment + | ^^^^^^^^^^^^^^^^^ E303 +73 | +74 | print + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +68 68 | +69 69 | # comment +70 70 | +71 |- +72 71 | # another comment +73 72 | +74 73 | print + +E30.py:88:1: E303 [*] Too many blank lines (3) + | +88 | """This class docstring comes on line 5. + | E303 +89 | It gives error E303: too many blank lines (3) +90 | """ + | + = help: Remove extraneous blank line(s) + +ℹ Suggested fix +84 84 | #!python +85 85 | +86 86 | +87 |- +88 87 | """This class docstring comes on line 5. +89 88 | It gives error E303: too many blank lines (3) +90 89 | """ + + From c4d471383609be544d703d332070d22082b72909 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 23:36:18 +0900 Subject: [PATCH 29/47] Fixed E302. Fixed is_in_class and is_in_fn being updated too late. --- .../rules/logical_lines/blank_lines.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 2f05c886be38b..1dc1e8d08943d 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -326,6 +326,14 @@ pub(crate) fn blank_lines( } for (token_idx, token) in line.tokens().iter().enumerate() { + if indent_level <= tracked_vars.class_indent_level { + tracked_vars.is_in_class = false; + } + + if indent_level <= tracked_vars.fn_indent_level { + tracked_vars.is_in_fn = false; + } + // E301 if token.kind() == TokenKind::Def && tracked_vars.is_in_class @@ -345,6 +353,7 @@ pub(crate) fn blank_lines( // E302 if token.kind() == TokenKind::Def + && !tracked_vars.follows_decorator && !tracked_vars.is_in_class && tracked_vars.blank_lines < 2 && prev_line.is_some() @@ -420,14 +429,6 @@ pub(crate) fn blank_lines( context.push_diagnostic(diagnostic); } - if indent_level <= tracked_vars.class_indent_level { - tracked_vars.is_in_class = false; - } - - if indent_level <= tracked_vars.fn_indent_level { - tracked_vars.is_in_fn = false; - } - // E306 if matches!(token.kind(), TokenKind::Def | TokenKind::Class) && (tracked_vars.is_in_class || tracked_vars.is_in_fn) From 4b0933faa03ba35041d12845bf6724cff0b1824e Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sun, 28 May 2023 23:37:41 +0900 Subject: [PATCH 30/47] Updated snapshots. --- ...ules__pycodestyle__tests__E302_E30.py.snap | 39 -- ...ules__pycodestyle__tests__E305_E30.py.snap | 607 ------------------ 2 files changed, 646 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap index 25976db6dd258..796b43e30c3c6 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap @@ -183,26 +183,6 @@ E30.py:65:1: E302 [*] Expected 2 blank lines, found 0 66 68 | print 67 69 | -E30.py:81:1: E302 [*] Expected 2 blank lines, found 1 - | -81 | @decorator -82 | -83 | def function(): - | ^^^ E302 -84 | pass -85 | #: E303:5:1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -78 78 | #: E304:3:1 -79 79 | @decorator -80 80 | - 81 |+ -81 82 | def function(): -82 83 | pass -83 84 | #: E303:5:1 - E30.py:94:1: E302 [*] Expected 2 blank lines, found 0 | 94 | #: E305:7:1 @@ -720,23 +700,4 @@ E30.py:185:1: E302 [*] Expected 2 blank lines, found 0 186 188 | pass 187 189 | -E30.py:190:1: E302 [*] Expected 2 blank lines, found 0 - | -190 | # wat -191 | @hi -192 | def g(): - | ^^^ E302 -193 | pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -187 187 | -188 188 | # wat -189 189 | @hi - 190 |+ - 191 |+ -190 192 | def g(): -191 193 | pass - diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap index dab921be603ad..47288f5b439cd 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E305_E30.py.snap @@ -1,611 +1,4 @@ --- source: crates/ruff/src/rules/pycodestyle/mod.rs --- -E30.py:8:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | - 8 | def b(): - 9 | pass -10 | #: E301:6:5 - | ^^^^^^^^^^^ E305 -11 | class X: - | - = help: Add missing blank line(s) - -ℹ Suggested fix -5 5 | pass -6 6 | def b(): -7 7 | pass - 8 |+ - 9 |+ -8 10 | #: E301:6:5 -9 11 | class X: -10 12 | - -E30.py:16:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -16 | def b(): -17 | pass -18 | #: - | ^^ E305 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -13 13 | # comment -14 14 | def b(): -15 15 | pass - 16 |+ - 17 |+ -16 18 | #: -17 19 | -18 20 | - -E30.py:23:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -23 | def _main(): -24 | pass -25 | #: E302:2:1 - | ^^^^^^^^^^^ E305 -26 | import sys -27 | def get_sys_path(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -20 20 | """Main module.""" -21 21 | def _main(): -22 22 | pass - 23 |+ - 24 |+ -23 25 | #: E302:2:1 -24 26 | import sys -25 27 | def get_sys_path(): - -E30.py:27:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -27 | def get_sys_path(): -28 | return sys.path -29 | #: E302:4:1 - | ^^^^^^^^^^^ E305 -30 | def a(): -31 | pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -24 24 | import sys -25 25 | def get_sys_path(): -26 26 | return sys.path - 27 |+ - 28 |+ -27 29 | #: E302:4:1 -28 30 | def a(): -29 31 | pass - -E30.py:31:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -31 | pass -32 | -33 | def b(): - | E305 -34 | pass -35 | #: E302:6:1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -28 28 | def a(): -29 29 | pass -30 30 | - 31 |+ -31 32 | def b(): -32 33 | pass -33 34 | #: E302:6:1 - -E30.py:33:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -33 | def b(): -34 | pass -35 | #: E302:6:1 - | ^^^^^^^^^^^ E305 -36 | def a(): -37 | pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -30 30 | -31 31 | def b(): -32 32 | pass - 33 |+ - 34 |+ -33 35 | #: E302:6:1 -34 36 | def a(): -35 37 | pass - -E30.py:37:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -37 | pass -38 | -39 | # comment - | ^^^^^^^^^ E305 -40 | -41 | def b(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -34 34 | def a(): -35 35 | pass -36 36 | - 37 |+ -37 38 | # comment -38 39 | -39 40 | def b(): - -E30.py:41:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -41 | def b(): -42 | pass -43 | #: - | ^^ E305 -44 | #: E302:4:1 -45 | def a(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -38 38 | -39 39 | def b(): -40 40 | pass - 41 |+ - 42 |+ -41 43 | #: -42 44 | #: E302:4:1 -43 45 | def a(): - -E30.py:46:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -46 | pass -47 | -48 | async def b(): - | E305 -49 | pass -50 | #: - | - = help: Add missing blank line(s) - -ℹ Suggested fix -43 43 | def a(): -44 44 | pass -45 45 | - 46 |+ -46 47 | async def b(): -47 48 | pass -48 49 | #: - -E30.py:48:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -48 | async def b(): -49 | pass -50 | #: - | ^^ E305 -51 | -52 | #: E303:5:1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -45 45 | -46 46 | async def b(): -47 47 | pass - 48 |+ - 49 |+ -48 50 | #: -49 51 | -50 52 | #: E303:5:1 - -E30.py:75:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -75 | print -76 | #: - | ^^ E305 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -72 72 | # another comment -73 73 | -74 74 | print - 75 |+ - 76 |+ -75 77 | #: -76 78 | -77 79 | - -E30.py:83:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -83 | def function(): -84 | pass -85 | #: E303:5:1 - | ^^^^^^^^^^^ E305 -86 | #!python - | - = help: Add missing blank line(s) - -ℹ Suggested fix -80 80 | -81 81 | def function(): -82 82 | pass - 83 |+ - 84 |+ -83 85 | #: E303:5:1 -84 86 | #!python -85 87 | - -E30.py:100:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -100 | # another comment -101 | a() - | E305 -102 | #: E305:8:1 -103 | def a(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -97 97 | # comment -98 98 | -99 99 | # another comment - 100 |+ - 101 |+ -100 102 | a() -101 103 | #: E305:8:1 -102 104 | def a(): - -E30.py:109:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -109 | # another comment -110 | -111 | try: - | E305 -112 | a() -113 | except Exception: - | - = help: Add missing blank line(s) - -ℹ Suggested fix -106 106 | -107 107 | # another comment -108 108 | - 109 |+ -109 110 | try: -110 111 | a() -111 112 | except Exception: - -E30.py:117:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -117 | print -118 | -119 | # Two spaces before comments, too. - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E305 -120 | if a(): -121 | a() - | - = help: Add missing blank line(s) - -ℹ Suggested fix -114 114 | def a(): -115 115 | print -116 116 | - 117 |+ -117 118 | # Two spaces before comments, too. -118 119 | if a(): -119 120 | a() - -E30.py:127:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -127 | def b(): -128 | pass -129 | #: E306:3:5 - | ^^^^^^^^^^^ E305 -130 | async def a(): -131 | x = 1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -124 124 | x = 1 -125 125 | def b(): -126 126 | pass - 127 |+ - 128 |+ -127 129 | #: E306:3:5 -128 130 | async def a(): -129 131 | x = 1 - -E30.py:132:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -132 | def b(): -133 | pass -134 | #: E306:3:5 E306:5:9 - | ^^^^^^^^^^^^^^^^^^^^ E305 -135 | def a(): -136 | x = 2 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -129 129 | x = 1 -130 130 | def b(): -131 131 | pass - 132 |+ - 133 |+ -132 134 | #: E306:3:5 E306:5:9 -133 135 | def a(): -134 136 | x = 2 - -E30.py:139:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -139 | def c(): -140 | pass -141 | #: E306:3:5 E306:6:5 - | ^^^^^^^^^^^^^^^^^^^^ E305 -142 | def a(): -143 | x = 1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -136 136 | x = 1 -137 137 | def c(): -138 138 | pass - 139 |+ - 140 |+ -139 141 | #: E306:3:5 E306:6:5 -140 142 | def a(): -141 143 | x = 1 - -E30.py:147:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -147 | def b(): -148 | pass -149 | #: - | ^^ E305 -150 | -151 | #: E305:8:1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -144 144 | x = 2 -145 145 | def b(): -146 146 | pass - 147 |+ - 148 |+ -147 149 | #: -148 150 | -149 151 | #: E305:8:1 - -E30.py:157:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -157 | blah, blah -158 | -159 | if __name__ == '__main__': - | E305 -160 | main() -161 | # Previously just E272:1:6 E272:4:6 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -154 154 | def main(): -155 155 | blah, blah -156 156 | - 157 |+ -157 158 | if __name__ == '__main__': -158 159 | main() -159 160 | # Previously just E272:1:6 E272:4:6 - -E30.py:164:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -164 | pass -165 | -166 | async def x(y: int = 1): - | E305 -167 | pass -168 | #: E704:3:1 E302:3:1 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -161 161 | async def x(): -162 162 | pass -163 163 | - 164 |+ -164 165 | async def x(y: int = 1): -165 166 | pass -166 167 | #: E704:3:1 E302:3:1 - -E30.py:166:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -166 | async def x(y: int = 1): -167 | pass -168 | #: E704:3:1 E302:3:1 - | ^^^^^^^^^^^^^^^^^^^^ E305 -169 | def bar(): -170 | pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -163 163 | -164 164 | async def x(y: int = 1): -165 165 | pass - 166 |+ - 167 |+ -166 168 | #: E704:3:1 E302:3:1 -167 169 | def bar(): -168 170 | pass - -E30.py:169:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -169 | def bar(): -170 | pass -171 | def baz(): pass - | E305 -172 | #: E704:1:1 E302:2:1 -173 | def bar(): pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -166 166 | #: E704:3:1 E302:3:1 -167 167 | def bar(): -168 168 | pass - 169 |+ - 170 |+ -169 171 | def baz(): pass -170 172 | #: E704:1:1 E302:2:1 -171 173 | def bar(): pass - -E30.py:170:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -170 | pass -171 | def baz(): pass -172 | #: E704:1:1 E302:2:1 - | ^^^^^^^^^^^^^^^^^^^^ E305 -173 | def bar(): pass -174 | def baz(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -167 167 | def bar(): -168 168 | pass -169 169 | def baz(): pass - 170 |+ - 171 |+ -170 172 | #: E704:1:1 E302:2:1 -171 173 | def bar(): pass -172 174 | def baz(): - -E30.py:172:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -172 | #: E704:1:1 E302:2:1 -173 | def bar(): pass -174 | def baz(): - | ^^^ E305 -175 | pass -176 | #: E704:4:5 E306:4:5 - | - = help: Add missing blank line(s) - -ℹ Suggested fix -169 169 | def baz(): pass -170 170 | #: E704:1:1 E302:2:1 -171 171 | def bar(): pass - 172 |+ - 173 |+ -172 174 | def baz(): -173 175 | pass -174 176 | #: E704:4:5 E306:4:5 - -E30.py:174:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -174 | def baz(): -175 | pass -176 | #: E704:4:5 E306:4:5 - | ^^^^^^^^^^^^^^^^^^^^ E305 -177 | def foo(): -178 | def bar(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -171 171 | def bar(): pass -172 172 | def baz(): -173 173 | pass - 174 |+ - 175 |+ -174 176 | #: E704:4:5 E306:4:5 -175 177 | def foo(): -176 178 | def bar(): - -E30.py:179:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -179 | pass -180 | def baz(): pass -181 | #: E704:2:5 E306:3:5 - | ^^^^^^^^^^^^^^^^^^^^ E305 -182 | def foo(): -183 | def bar(): pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -176 176 | def bar(): -177 177 | pass -178 178 | def baz(): pass - 179 |+ - 180 |+ -179 181 | #: E704:2:5 E306:3:5 -180 182 | def foo(): -181 183 | def bar(): pass - -E30.py:184:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -184 | def baz(): -185 | pass -186 | #: E302:5:1 - | ^^^^^^^^^^^ E305 -187 | def f(): -188 | pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -181 181 | def bar(): pass -182 182 | def baz(): -183 183 | pass - 184 |+ - 185 |+ -184 186 | #: E302:5:1 -185 187 | def f(): -186 188 | pass - -E30.py:188:1: E305 [*] expected 2 blank lines after class or function definition, found (1) - | -188 | pass -189 | -190 | # wat - | ^^^^^ E305 -191 | @hi -192 | def g(): - | - = help: Add missing blank line(s) - -ℹ Suggested fix -185 185 | def f(): -186 186 | pass -187 187 | - 188 |+ -188 189 | # wat -189 190 | @hi -190 191 | def g(): - -E30.py:192:1: E305 [*] expected 2 blank lines after class or function definition, found (0) - | -192 | def g(): -193 | pass - | - = help: Add missing blank line(s) - -ℹ Suggested fix -189 189 | @hi -190 190 | def g(): -191 191 | pass - 192 |+ - 193 |+ - From 0b74e07ce573ca6d0c9e891b5c914b96d359d005 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Mon, 29 May 2023 00:57:04 +0900 Subject: [PATCH 31/47] Use breaks instead of returns to limit code repetition. --- .../rules/logical_lines/blank_lines.rs | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 1dc1e8d08943d..f19c8ddbc09ad 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -270,7 +270,7 @@ impl AlwaysAutofixableViolation for BlankLinesAfterFunctionOrClass { /// - Two blank lines are expected between functions and classes /// - One blank line is expected between methods of a class. /// -/// ## Example FIXME: The pycodestyle example does not trigger an error... +/// ## Example /// ```python /// def outer(): /// def inner(): @@ -308,7 +308,7 @@ impl AlwaysAutofixableViolation for BlankLinesBeforeNestedDefinition { } } -/// E301, E303 +/// E301, E302, E303, E304, E305, E306 pub(crate) fn blank_lines( line: &LogicalLine, prev_line: Option<&LogicalLine>, @@ -325,15 +325,15 @@ pub(crate) fn blank_lines( return; } - for (token_idx, token) in line.tokens().iter().enumerate() { - if indent_level <= tracked_vars.class_indent_level { - tracked_vars.is_in_class = false; - } + if indent_level <= tracked_vars.class_indent_level { + tracked_vars.is_in_class = false; + } - if indent_level <= tracked_vars.fn_indent_level { - tracked_vars.is_in_fn = false; - } + if indent_level <= tracked_vars.fn_indent_level { + tracked_vars.is_in_fn = false; + } + for (token_idx, token) in line.tokens().iter().enumerate() { // E301 if token.kind() == TokenKind::Def && tracked_vars.is_in_class @@ -453,15 +453,14 @@ pub(crate) fn blank_lines( tracked_vars.class_indent_level = indent_level; } tracked_vars.is_in_class = true; - return; + tracked_vars.follows_decorator = false; + tracked_vars.follows_def = false; + break; } TokenKind::At => { tracked_vars.follows_decorator = true; - tracked_vars.follows_def = false; - tracked_vars.blank_lines = 0; - tracked_vars.blank_characters = 0; - return; + break; } TokenKind::Def => { if !tracked_vars.is_in_fn { @@ -469,17 +468,16 @@ pub(crate) fn blank_lines( } tracked_vars.is_in_fn = true; tracked_vars.follows_def = true; - tracked_vars.follows_decorator = false; - tracked_vars.blank_lines = 0; - tracked_vars.blank_characters = 0; - return; + break; + } + _ => { + tracked_vars.follows_decorator = false; + tracked_vars.follows_def = false; } - _ => {} } } - tracked_vars.follows_decorator = false; - tracked_vars.follows_def = false; + tracked_vars.blank_lines = 0; tracked_vars.blank_characters = 0; } From f63ea5b5633895127698de67950f11a429729efb Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Mon, 29 May 2023 02:01:43 +0900 Subject: [PATCH 32/47] Do not enter the indention check for empty lines. --- crates/ruff/src/checkers/logical_lines.rs | 25 +++++++++++-------- .../rules/logical_lines/indentation.rs | 4 --- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 2d873cfcecd4d..88eaf19e57dbc 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -40,6 +40,7 @@ pub(crate) fn check_logical_lines( let mut context = LogicalLinesContext::new(settings); let should_fix_missing_whitespace = settings.rules.should_fix(Rule::MissingWhitespace); + let should_fix_whitespace_before_parameters = settings.rules.should_fix(Rule::WhitespaceBeforeParameters); @@ -47,6 +48,7 @@ pub(crate) fn check_logical_lines( let mut prev_line = None; let mut prev_indent_level = None; let indent_char = stylist.indentation().as_char(); + for line in &LogicalLines::from_tokens(tokens, locator) { if line.flags().contains(TokenFlags::OPERATOR) { space_around_operator(&line, &mut context); @@ -94,18 +96,21 @@ pub(crate) fn check_logical_lines( let indent_size = 4; - for kind in indentation( - &line, - prev_line.as_ref(), - indent_char, - indent_level, - prev_indent_level, - indent_size, - ) { - if settings.rules.enabled(kind.rule()) { - context.push(kind, range); + if !line.is_empty() { + for kind in indentation( + &line, + prev_line.as_ref(), + indent_char, + indent_level, + prev_indent_level, + indent_size, + ) { + if settings.rules.enabled(kind.rule()) { + context.push(kind, range); + } } } + blank_lines( &line, prev_line.as_ref(), diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs index 6a487db553277..a059ee9b6c306 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/indentation.rs @@ -246,10 +246,6 @@ pub(crate) fn indentation( ) -> Vec { let mut diagnostics = vec![]; - if logical_line.is_empty() { - return diagnostics; - } - if indent_level % indent_size != 0 { diagnostics.push(if logical_line.is_comment_only() { DiagnosticKind::from(IndentationWithInvalidMultipleComment { indent_size }) From fa3a30bae9e904c037aa287b8980338c60053d12 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Mon, 29 May 2023 02:55:03 +0900 Subject: [PATCH 33/47] Sorted KNOWN_FORMATTING_VIOLATIONS --- scripts/check_docs_formatted.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/check_docs_formatted.py b/scripts/check_docs_formatted.py index fd4d74a5fdda6..3751d730448f8 100755 --- a/scripts/check_docs_formatted.py +++ b/scripts/check_docs_formatted.py @@ -27,11 +27,11 @@ "bad-quotes-docstring", "bad-quotes-inline-string", "bad-quotes-multiline-string", + "blank-line-after-decorator", + "blank-line-between-methods", "blank-lines-after-function-or-class", "blank-lines-before-nested-definition", "blank-lines-top-level", - "blank-line-after-decorator", - "blank-line-between-methods", "explicit-string-concatenation", "indentation-with-invalid-multiple", "line-too-long", From 47063d4b7536e5624cf96b6cc150a62ad54a417f Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Tue, 30 May 2023 17:10:52 +0900 Subject: [PATCH 34/47] Count number of chars instead of number of bytes. --- .../src/rules/pycodestyle/rules/logical_lines/blank_lines.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index f19c8ddbc09ad..8cb1d79103835 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -320,7 +320,7 @@ pub(crate) fn blank_lines( ) { if line.is_empty() { tracked_vars.blank_lines += 1; - tracked_vars.blank_characters += u32::try_from(line.text().len()) + tracked_vars.blank_characters += u32::try_from(line.text().chars().count()) .expect("The number of blank characters should be relatively small"); return; } From 2b4e95954dd8f47317eaf7c3e46ca125bb133ffd Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Tue, 30 May 2023 17:13:38 +0900 Subject: [PATCH 35/47] Use Fix::automatic --- .../rules/logical_lines/blank_lines.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 8cb1d79103835..0b440ee5e0a8d 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -343,8 +343,7 @@ pub(crate) fn blank_lines( .map_or(false, |token| token.kind() != TokenKind::Class) { let mut diagnostic = Diagnostic::new(BlankLineBetweenMethods, token.range()); - #[allow(deprecated)] - diagnostic.set_fix(Fix::unspecified(Edit::insertion( + diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist.line_ending().as_str().to_string(), locator.line_start(token.range().start()), ))); @@ -362,8 +361,7 @@ pub(crate) fn blank_lines( BlankLinesTopLevel(tracked_vars.blank_lines as usize), token.range(), ); - #[allow(deprecated)] - diagnostic.set_fix(Fix::unspecified(Edit::insertion( + diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist .line_ending() .as_str() @@ -390,8 +388,7 @@ pub(crate) fn blank_lines( }; let end = locator.line_start(token.range().start()); let start = end - TextSize::new(chars_to_remove); - #[allow(deprecated)] - diagnostic.set_fix(Fix::suggested(Edit::deletion(start, end))); + diagnostic.set_fix(Fix::automatic(Edit::deletion(start, end))); context.push_diagnostic(diagnostic); } @@ -401,7 +398,7 @@ pub(crate) fn blank_lines( let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); let range = token.range(); - diagnostic.set_fix(Fix::suggested(Edit::deletion( + diagnostic.set_fix(Fix::automatic(Edit::deletion( locator.line_start(range.start()) - TextSize::new(tracked_vars.blank_characters), locator.line_start(range.start()), ))); @@ -417,8 +414,7 @@ pub(crate) fn blank_lines( BlankLinesAfterFunctionOrClass(tracked_vars.blank_lines as usize), token.range(), ); - #[allow(deprecated)] - diagnostic.set_fix(Fix::unspecified(Edit::insertion( + diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist .line_ending() .as_str() @@ -438,8 +434,7 @@ pub(crate) fn blank_lines( BlankLinesBeforeNestedDefinition(tracked_vars.blank_lines), token.range(), ); - #[allow(deprecated)] - diagnostic.set_fix(Fix::unspecified(Edit::insertion( + diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist.line_ending().as_str().to_string(), locator.line_start(token.range().start()), ))); From 2fc94f80fcaed9bc599842b91172c8a322671699 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Tue, 30 May 2023 18:04:54 +0900 Subject: [PATCH 36/47] Fixed some titles/docstring. --- .../rules/logical_lines/blank_lines.rs | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 0b440ee5e0a8d..e21e8ac5167b7 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -72,21 +72,25 @@ impl BlankLinesConfig { /// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) /// - [Flake 8 rule](https://www.flake8rules.com/rules/E301.html) #[violation] -pub struct BlankLineBetweenMethods; +pub struct BlankLineBetweenMethods(pub u32); impl AlwaysAutofixableViolation for BlankLineBetweenMethods { #[derive_message_formats] fn message(&self) -> String { - format!("Expected 1 blank line, found 0") + let BlankLineBetweenMethods(nb_blank_lines) = self; + format!( + "Expected {:?} blank line, found {nb_blank_lines}", + BlankLinesConfig::METHOD + ) } fn autofix_title(&self) -> String { - "Remove extraneous blank line(s)".to_string() + "Add missing blank line(s)".to_string() } } /// ## What it does -/// Checks for extraneous blank lines between top level functions and classes. +/// Checks for missing blank lines between top level functions and classes. /// /// ## Why is this bad? /// PEP 8 recommends the use of blank lines as follows: @@ -115,13 +119,16 @@ impl AlwaysAutofixableViolation for BlankLineBetweenMethods { /// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) /// - [Flake 8 rule](https://www.flake8rules.com/rules/E302.html) #[violation] -pub struct BlankLinesTopLevel(pub usize); +pub struct BlankLinesTopLevel(pub u32); impl AlwaysAutofixableViolation for BlankLinesTopLevel { #[derive_message_formats] fn message(&self) -> String { let BlankLinesTopLevel(nb_blank_lines) = self; - format!("Expected 2 blank lines, found {nb_blank_lines}") + format!( + "Expected {:?} blank lines, found {nb_blank_lines}", + BlankLinesConfig::TOP_LEVEL + ) } fn autofix_title(&self) -> String { @@ -221,7 +228,7 @@ impl AlwaysAutofixableViolation for BlankLineAfterDecorator { } /// ## What it does -/// Checks for blank lines after end of function or class. +/// Checks for missing blank lines after end of function or class. /// /// ## Why is this bad? /// PEP 8 recommends the using blank lines as following: @@ -248,7 +255,7 @@ impl AlwaysAutofixableViolation for BlankLineAfterDecorator { /// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines) /// - [Flake 8 rule](https://www.flake8rules.com/rules/E305.html) #[violation] -pub struct BlankLinesAfterFunctionOrClass(pub usize); +pub struct BlankLinesAfterFunctionOrClass(pub u32); impl AlwaysAutofixableViolation for BlankLinesAfterFunctionOrClass { #[derive_message_formats] @@ -342,7 +349,10 @@ pub(crate) fn blank_lines( .and_then(|prev_line| prev_line.tokens_trimmed().first()) .map_or(false, |token| token.kind() != TokenKind::Class) { - let mut diagnostic = Diagnostic::new(BlankLineBetweenMethods, token.range()); + let mut diagnostic = Diagnostic::new( + BlankLineBetweenMethods(tracked_vars.blank_lines), + token.range(), + ); diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist.line_ending().as_str().to_string(), locator.line_start(token.range().start()), @@ -357,10 +367,8 @@ pub(crate) fn blank_lines( && tracked_vars.blank_lines < 2 && prev_line.is_some() { - let mut diagnostic = Diagnostic::new( - BlankLinesTopLevel(tracked_vars.blank_lines as usize), - token.range(), - ); + let mut diagnostic = + Diagnostic::new(BlankLinesTopLevel(tracked_vars.blank_lines), token.range()); diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist .line_ending() @@ -411,7 +419,7 @@ pub(crate) fn blank_lines( && indent_level == 0 { let mut diagnostic = Diagnostic::new( - BlankLinesAfterFunctionOrClass(tracked_vars.blank_lines as usize), + BlankLinesAfterFunctionOrClass(tracked_vars.blank_lines), token.range(), ); diagnostic.set_fix(Fix::automatic(Edit::insertion( From da9d3eee9058c506f197d4c0247b2de6766b8d6b Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Tue, 30 May 2023 18:08:18 +0900 Subject: [PATCH 37/47] Updated the snapshots to reflect 2b4e959 --- ...ules__pycodestyle__tests__E301_E30.py.snap | 8 +-- ...ules__pycodestyle__tests__E302_E30.py.snap | 68 +++++++++---------- ...ules__pycodestyle__tests__E303_E30.py.snap | 10 +-- ...ules__pycodestyle__tests__E304_E30.py.snap | 2 +- ...ules__pycodestyle__tests__E306_E30.py.snap | 24 +++---- 5 files changed, 56 insertions(+), 56 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap index dd25813f8be9f..f31c96612de83 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap @@ -10,9 +10,9 @@ E30.py:6:5: E301 [*] Expected 1 blank line, found 0 9 | pass 10 | #: E301:6:5 | - = help: Remove extraneous blank line(s) + = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 3 3 | 4 4 | def a(): 5 5 | pass @@ -30,9 +30,9 @@ E30.py:14:5: E301 [*] Expected 1 blank line, found 0 17 | pass 18 | #: | - = help: Remove extraneous blank line(s) + = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 11 11 | def a(): 12 12 | pass 13 13 | # comment diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap index 796b43e30c3c6..924c4dea0cf70 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap @@ -12,7 +12,7 @@ E30.py:21:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 18 18 | 19 19 | #: E302:2:1 20 20 | """Main module.""" @@ -33,7 +33,7 @@ E30.py:25:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 22 22 | pass 23 23 | #: E302:2:1 24 24 | import sys @@ -53,7 +53,7 @@ E30.py:28:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 25 25 | def get_sys_path(): 26 26 | return sys.path 27 27 | #: E302:4:1 @@ -74,7 +74,7 @@ E30.py:31:1: E302 [*] Expected 2 blank lines, found 1 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 28 28 | def a(): 29 29 | pass 30 30 | @@ -93,7 +93,7 @@ E30.py:34:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 31 31 | def b(): 32 32 | pass 33 33 | #: E302:6:1 @@ -114,7 +114,7 @@ E30.py:39:1: E302 [*] Expected 2 blank lines, found 1 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 36 36 | 37 37 | # comment 38 38 | @@ -133,7 +133,7 @@ E30.py:43:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 40 40 | pass 41 41 | #: 42 42 | #: E302:4:1 @@ -154,7 +154,7 @@ E30.py:46:7: E302 [*] Expected 2 blank lines, found 1 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 43 43 | def a(): 44 44 | pass 45 45 | @@ -173,7 +173,7 @@ E30.py:65:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 62 62 | 63 63 | print 64 64 | #: E303:5:5 E303:8:5 @@ -192,7 +192,7 @@ E30.py:94:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 91 91 | #: 92 92 | 93 93 | #: E305:7:1 @@ -212,7 +212,7 @@ E30.py:102:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 99 99 | # another comment 100 100 | a() 101 101 | #: E305:8:1 @@ -232,7 +232,7 @@ E30.py:114:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 111 111 | except Exception: 112 112 | pass 113 113 | #: E305:5:1 @@ -252,7 +252,7 @@ E30.py:123:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 120 120 | #: 121 121 | 122 122 | #: E306:3:5 @@ -273,7 +273,7 @@ E30.py:125:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 122 122 | #: E306:3:5 123 123 | def a(): 124 124 | x = 1 @@ -294,7 +294,7 @@ E30.py:128:7: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 125 125 | def b(): 126 126 | pass 127 127 | #: E306:3:5 @@ -315,7 +315,7 @@ E30.py:130:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 127 127 | #: E306:3:5 128 128 | async def a(): 129 129 | x = 1 @@ -336,7 +336,7 @@ E30.py:133:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 130 130 | def b(): 131 131 | pass 132 132 | #: E306:3:5 E306:5:9 @@ -357,7 +357,7 @@ E30.py:135:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 132 132 | #: E306:3:5 E306:5:9 133 133 | def a(): 134 134 | x = 2 @@ -378,7 +378,7 @@ E30.py:137:9: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 134 134 | x = 2 135 135 | def b(): 136 136 | x = 1 @@ -399,7 +399,7 @@ E30.py:140:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 137 137 | def c(): 138 138 | pass 139 139 | #: E306:3:5 E306:6:5 @@ -420,7 +420,7 @@ E30.py:145:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 142 142 | class C: 143 143 | pass 144 144 | x = 2 @@ -440,7 +440,7 @@ E30.py:161:8: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 158 158 | main() 159 159 | # Previously just E272:1:6 E272:4:6 160 160 | #: E302:4:1 E271:1:6 E271:4:6 @@ -461,7 +461,7 @@ E30.py:164:8: E302 [*] Expected 2 blank lines, found 1 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 161 161 | async def x(): 162 162 | pass 163 163 | @@ -481,7 +481,7 @@ E30.py:167:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 164 164 | async def x(y: int = 1): 165 165 | pass 166 166 | #: E704:3:1 E302:3:1 @@ -502,7 +502,7 @@ E30.py:169:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 166 166 | #: E704:3:1 E302:3:1 167 167 | def bar(): 168 168 | pass @@ -523,7 +523,7 @@ E30.py:171:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 168 168 | pass 169 169 | def baz(): pass 170 170 | #: E704:1:1 E302:2:1 @@ -544,7 +544,7 @@ E30.py:172:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 169 169 | def baz(): pass 170 170 | #: E704:1:1 E302:2:1 171 171 | def bar(): pass @@ -565,7 +565,7 @@ E30.py:175:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 172 172 | def baz(): 173 173 | pass 174 174 | #: E704:4:5 E306:4:5 @@ -586,7 +586,7 @@ E30.py:176:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 173 173 | pass 174 174 | #: E704:4:5 E306:4:5 175 175 | def foo(): @@ -607,7 +607,7 @@ E30.py:178:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 175 175 | def foo(): 176 176 | def bar(): 177 177 | pass @@ -628,7 +628,7 @@ E30.py:180:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 177 177 | pass 178 178 | def baz(): pass 179 179 | #: E704:2:5 E306:3:5 @@ -649,7 +649,7 @@ E30.py:181:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 178 178 | def baz(): pass 179 179 | #: E704:2:5 E306:3:5 180 180 | def foo(): @@ -670,7 +670,7 @@ E30.py:182:5: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 179 179 | #: E704:2:5 E306:3:5 180 180 | def foo(): 181 181 | def bar(): pass @@ -690,7 +690,7 @@ E30.py:185:1: E302 [*] Expected 2 blank lines, found 0 | = help: Add missing blank line(s) -ℹ Suggested fix +ℹ Fix 182 182 | def baz(): 183 183 | pass 184 184 | #: E302:5:1 diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap index 371a666886a94..66ea47695798a 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E303_E30.py.snap @@ -10,7 +10,7 @@ E30.py:55:1: E303 [*] Too many blank lines (3) | = help: Remove extraneous blank line(s) -ℹ Suggested fix +ℹ Fix 51 51 | print 52 52 | 53 53 | @@ -28,7 +28,7 @@ E30.py:61:1: E303 [*] Too many blank lines (3) | = help: Remove extraneous blank line(s) -ℹ Suggested fix +ℹ Fix 57 57 | print 58 58 | 59 59 | @@ -44,7 +44,7 @@ E30.py:69:5: E303 [*] Too many blank lines (2) | = help: Remove extraneous blank line(s) -ℹ Suggested fix +ℹ Fix 65 65 | def a(): 66 66 | print 67 67 | @@ -62,7 +62,7 @@ E30.py:72:5: E303 [*] Too many blank lines (2) | = help: Remove extraneous blank line(s) -ℹ Suggested fix +ℹ Fix 68 68 | 69 69 | # comment 70 70 | @@ -80,7 +80,7 @@ E30.py:88:1: E303 [*] Too many blank lines (3) | = help: Remove extraneous blank line(s) -ℹ Suggested fix +ℹ Fix 84 84 | #!python 85 85 | 86 86 | diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap index aaf49037eff51..e8aa5231284bc 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap @@ -12,7 +12,7 @@ E30.py:81:1: E304 [*] blank lines found after function decorator | = help: Remove extraneous blank line(s) -ℹ Suggested fix +ℹ Fix 77 77 | 78 78 | #: E304:3:1 79 79 | @decorator diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap index b82be0b079c61..d5c7aaae3fb2e 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap @@ -12,7 +12,7 @@ E30.py:6:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 3 3 | 4 4 | def a(): 5 5 | pass @@ -32,7 +32,7 @@ E30.py:14:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 11 11 | def a(): 12 12 | pass 13 13 | # comment @@ -52,7 +52,7 @@ E30.py:125:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 122 122 | #: E306:3:5 123 123 | def a(): 124 124 | x = 1 @@ -72,7 +72,7 @@ E30.py:130:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 127 127 | #: E306:3:5 128 128 | async def a(): 129 129 | x = 1 @@ -92,7 +92,7 @@ E30.py:135:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 132 132 | #: E306:3:5 E306:5:9 133 133 | def a(): 134 134 | x = 2 @@ -112,7 +112,7 @@ E30.py:137:9: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 134 134 | x = 2 135 135 | def b(): 136 136 | x = 1 @@ -132,7 +132,7 @@ E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 139 139 | #: E306:3:5 E306:6:5 140 140 | def a(): 141 141 | x = 1 @@ -152,7 +152,7 @@ E30.py:145:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 142 142 | class C: 143 143 | pass 144 144 | x = 2 @@ -172,7 +172,7 @@ E30.py:176:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 173 173 | pass 174 174 | #: E704:4:5 E306:4:5 175 175 | def foo(): @@ -192,7 +192,7 @@ E30.py:178:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 175 175 | def foo(): 176 176 | def bar(): 177 177 | pass @@ -212,7 +212,7 @@ E30.py:181:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 178 178 | def baz(): pass 179 179 | #: E704:2:5 E306:3:5 180 180 | def foo(): @@ -232,7 +232,7 @@ E30.py:182:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | = help: Add missing blank line -ℹ Suggested fix +ℹ Fix 179 179 | #: E704:2:5 E306:3:5 180 180 | def foo(): 181 181 | def bar(): pass From 4cf44a3ae014275060e1c593f5d5cac674f529a0 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 12 Jun 2023 23:18:32 -0400 Subject: [PATCH 38/47] Update fixtures --- crates/ruff/src/registry.rs | 8 +- ...ules__pycodestyle__tests__E301_E30.py.snap | 28 +- ...ules__pycodestyle__tests__E302_E30.py.snap | 318 +++++++++--------- ...ules__pycodestyle__tests__E304_E30.py.snap | 10 +- ...ules__pycodestyle__tests__E306_E30.py.snap | 128 +++---- 5 files changed, 249 insertions(+), 243 deletions(-) diff --git a/crates/ruff/src/registry.rs b/crates/ruff/src/registry.rs index c89df825dd899..e8590216790d2 100644 --- a/crates/ruff/src/registry.rs +++ b/crates/ruff/src/registry.rs @@ -310,7 +310,12 @@ impl Rule { Rule::IOError => LintSource::Io, Rule::UnsortedImports | Rule::MissingRequiredImport => LintSource::Imports, Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => LintSource::Filesystem, - Rule::IndentationWithInvalidMultiple + Rule::BlankLineAfterDecorator + | Rule::BlankLineBetweenMethods + | Rule::BlankLinesAfterFunctionOrClass + | Rule::BlankLinesBeforeNestedDefinition + | Rule::BlankLinesTopLevel + | Rule::IndentationWithInvalidMultiple | Rule::IndentationWithInvalidMultipleComment | Rule::MissingWhitespace | Rule::MissingWhitespaceAfterKeyword @@ -334,6 +339,7 @@ impl Rule { | Rule::TabBeforeKeyword | Rule::TabBeforeOperator | Rule::TooFewSpacesBeforeInlineComment + | Rule::TooManyBlankLines | Rule::UnexpectedIndentation | Rule::UnexpectedIndentationComment | Rule::UnexpectedSpacesAroundKeywordParameterEquals diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap index f31c96612de83..91a46a731de68 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E301_E30.py.snap @@ -2,15 +2,15 @@ source: crates/ruff/src/rules/pycodestyle/mod.rs --- E30.py:6:5: E301 [*] Expected 1 blank line, found 0 - | - 6 | def a(): - 7 | pass - 8 | def b(): - | ^^^ E301 - 9 | pass -10 | #: E301:6:5 - | - = help: Add missing blank line(s) + | +4 | def a(): +5 | pass +6 | def b(): + | ^^^ E301 +7 | pass +8 | #: E301:6:5 + | + = help: Add missing blank line(s) ℹ Fix 3 3 | @@ -23,12 +23,12 @@ E30.py:6:5: E301 [*] Expected 1 blank line, found 0 E30.py:14:5: E301 [*] Expected 1 blank line, found 0 | -14 | pass -15 | # comment -16 | def b(): +12 | pass +13 | # comment +14 | def b(): | ^^^ E301 -17 | pass -18 | #: +15 | pass +16 | #: | = help: Add missing blank line(s) diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap index 924c4dea0cf70..efa45c412e2fd 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap @@ -3,12 +3,12 @@ source: crates/ruff/src/rules/pycodestyle/mod.rs --- E30.py:21:1: E302 [*] Expected 2 blank lines, found 0 | -21 | #: E302:2:1 -22 | """Main module.""" -23 | def _main(): +19 | #: E302:2:1 +20 | """Main module.""" +21 | def _main(): | ^^^ E302 -24 | pass -25 | #: E302:2:1 +22 | pass +23 | #: E302:2:1 | = help: Add missing blank line(s) @@ -24,12 +24,12 @@ E30.py:21:1: E302 [*] Expected 2 blank lines, found 0 E30.py:25:1: E302 [*] Expected 2 blank lines, found 0 | -25 | #: E302:2:1 -26 | import sys -27 | def get_sys_path(): +23 | #: E302:2:1 +24 | import sys +25 | def get_sys_path(): | ^^^ E302 -28 | return sys.path -29 | #: E302:4:1 +26 | return sys.path +27 | #: E302:4:1 | = help: Add missing blank line(s) @@ -45,11 +45,11 @@ E30.py:25:1: E302 [*] Expected 2 blank lines, found 0 E30.py:28:1: E302 [*] Expected 2 blank lines, found 0 | -28 | return sys.path -29 | #: E302:4:1 -30 | def a(): +26 | return sys.path +27 | #: E302:4:1 +28 | def a(): | ^^^ E302 -31 | pass +29 | pass | = help: Add missing blank line(s) @@ -65,12 +65,12 @@ E30.py:28:1: E302 [*] Expected 2 blank lines, found 0 E30.py:31:1: E302 [*] Expected 2 blank lines, found 1 | -31 | pass -32 | -33 | def b(): +29 | pass +30 | +31 | def b(): | ^^^ E302 -34 | pass -35 | #: E302:6:1 +32 | pass +33 | #: E302:6:1 | = help: Add missing blank line(s) @@ -85,11 +85,11 @@ E30.py:31:1: E302 [*] Expected 2 blank lines, found 1 E30.py:34:1: E302 [*] Expected 2 blank lines, found 0 | -34 | pass -35 | #: E302:6:1 -36 | def a(): +32 | pass +33 | #: E302:6:1 +34 | def a(): | ^^^ E302 -37 | pass +35 | pass | = help: Add missing blank line(s) @@ -105,12 +105,12 @@ E30.py:34:1: E302 [*] Expected 2 blank lines, found 0 E30.py:39:1: E302 [*] Expected 2 blank lines, found 1 | -39 | # comment -40 | -41 | def b(): +37 | # comment +38 | +39 | def b(): | ^^^ E302 -42 | pass -43 | #: +40 | pass +41 | #: | = help: Add missing blank line(s) @@ -125,11 +125,11 @@ E30.py:39:1: E302 [*] Expected 2 blank lines, found 1 E30.py:43:1: E302 [*] Expected 2 blank lines, found 0 | -43 | #: -44 | #: E302:4:1 -45 | def a(): +41 | #: +42 | #: E302:4:1 +43 | def a(): | ^^^ E302 -46 | pass +44 | pass | = help: Add missing blank line(s) @@ -145,12 +145,12 @@ E30.py:43:1: E302 [*] Expected 2 blank lines, found 0 E30.py:46:7: E302 [*] Expected 2 blank lines, found 1 | -46 | pass -47 | -48 | async def b(): +44 | pass +45 | +46 | async def b(): | ^^^ E302 -49 | pass -50 | #: +47 | pass +48 | #: | = help: Add missing blank line(s) @@ -165,11 +165,11 @@ E30.py:46:7: E302 [*] Expected 2 blank lines, found 1 E30.py:65:1: E302 [*] Expected 2 blank lines, found 0 | -65 | print -66 | #: E303:5:5 E303:8:5 -67 | def a(): +63 | print +64 | #: E303:5:5 E303:8:5 +65 | def a(): | ^^^ E302 -68 | print +66 | print | = help: Add missing blank line(s) @@ -185,10 +185,10 @@ E30.py:65:1: E302 [*] Expected 2 blank lines, found 0 E30.py:94:1: E302 [*] Expected 2 blank lines, found 0 | -94 | #: E305:7:1 -95 | def a(): +93 | #: E305:7:1 +94 | def a(): | ^^^ E302 -96 | print +95 | print | = help: Add missing blank line(s) @@ -204,11 +204,11 @@ E30.py:94:1: E302 [*] Expected 2 blank lines, found 0 E30.py:102:1: E302 [*] Expected 2 blank lines, found 0 | -102 | a() -103 | #: E305:8:1 -104 | def a(): +100 | a() +101 | #: E305:8:1 +102 | def a(): | ^^^ E302 -105 | print +103 | print | = help: Add missing blank line(s) @@ -224,11 +224,11 @@ E30.py:102:1: E302 [*] Expected 2 blank lines, found 0 E30.py:114:1: E302 [*] Expected 2 blank lines, found 0 | -114 | pass -115 | #: E305:5:1 -116 | def a(): +112 | pass +113 | #: E305:5:1 +114 | def a(): | ^^^ E302 -117 | print +115 | print | = help: Add missing blank line(s) @@ -244,11 +244,11 @@ E30.py:114:1: E302 [*] Expected 2 blank lines, found 0 E30.py:123:1: E302 [*] Expected 2 blank lines, found 0 | -123 | #: E306:3:5 -124 | def a(): +122 | #: E306:3:5 +123 | def a(): | ^^^ E302 -125 | x = 1 -126 | def b(): +124 | x = 1 +125 | def b(): | = help: Add missing blank line(s) @@ -264,12 +264,12 @@ E30.py:123:1: E302 [*] Expected 2 blank lines, found 0 E30.py:125:5: E302 [*] Expected 2 blank lines, found 0 | -125 | def a(): -126 | x = 1 -127 | def b(): +123 | def a(): +124 | x = 1 +125 | def b(): | ^^^ E302 -128 | pass -129 | #: E306:3:5 +126 | pass +127 | #: E306:3:5 | = help: Add missing blank line(s) @@ -285,12 +285,12 @@ E30.py:125:5: E302 [*] Expected 2 blank lines, found 0 E30.py:128:7: E302 [*] Expected 2 blank lines, found 0 | -128 | pass -129 | #: E306:3:5 -130 | async def a(): +126 | pass +127 | #: E306:3:5 +128 | async def a(): | ^^^ E302 -131 | x = 1 -132 | def b(): +129 | x = 1 +130 | def b(): | = help: Add missing blank line(s) @@ -306,12 +306,12 @@ E30.py:128:7: E302 [*] Expected 2 blank lines, found 0 E30.py:130:5: E302 [*] Expected 2 blank lines, found 0 | -130 | async def a(): -131 | x = 1 -132 | def b(): +128 | async def a(): +129 | x = 1 +130 | def b(): | ^^^ E302 -133 | pass -134 | #: E306:3:5 E306:5:9 +131 | pass +132 | #: E306:3:5 E306:5:9 | = help: Add missing blank line(s) @@ -327,12 +327,12 @@ E30.py:130:5: E302 [*] Expected 2 blank lines, found 0 E30.py:133:1: E302 [*] Expected 2 blank lines, found 0 | -133 | pass -134 | #: E306:3:5 E306:5:9 -135 | def a(): +131 | pass +132 | #: E306:3:5 E306:5:9 +133 | def a(): | ^^^ E302 -136 | x = 2 -137 | def b(): +134 | x = 2 +135 | def b(): | = help: Add missing blank line(s) @@ -348,12 +348,12 @@ E30.py:133:1: E302 [*] Expected 2 blank lines, found 0 E30.py:135:5: E302 [*] Expected 2 blank lines, found 0 | -135 | def a(): -136 | x = 2 -137 | def b(): +133 | def a(): +134 | x = 2 +135 | def b(): | ^^^ E302 -138 | x = 1 -139 | def c(): +136 | x = 1 +137 | def c(): | = help: Add missing blank line(s) @@ -369,12 +369,12 @@ E30.py:135:5: E302 [*] Expected 2 blank lines, found 0 E30.py:137:9: E302 [*] Expected 2 blank lines, found 0 | -137 | def b(): -138 | x = 1 -139 | def c(): +135 | def b(): +136 | x = 1 +137 | def c(): | ^^^ E302 -140 | pass -141 | #: E306:3:5 E306:6:5 +138 | pass +139 | #: E306:3:5 E306:6:5 | = help: Add missing blank line(s) @@ -390,12 +390,12 @@ E30.py:137:9: E302 [*] Expected 2 blank lines, found 0 E30.py:140:1: E302 [*] Expected 2 blank lines, found 0 | -140 | pass -141 | #: E306:3:5 E306:6:5 -142 | def a(): +138 | pass +139 | #: E306:3:5 E306:6:5 +140 | def a(): | ^^^ E302 -143 | x = 1 -144 | class C: +141 | x = 1 +142 | class C: | = help: Add missing blank line(s) @@ -411,12 +411,12 @@ E30.py:140:1: E302 [*] Expected 2 blank lines, found 0 E30.py:145:5: E302 [*] Expected 2 blank lines, found 0 | -145 | pass -146 | x = 2 -147 | def b(): +143 | pass +144 | x = 2 +145 | def b(): | ^^^ E302 -148 | pass -149 | #: +146 | pass +147 | #: | = help: Add missing blank line(s) @@ -432,11 +432,11 @@ E30.py:145:5: E302 [*] Expected 2 blank lines, found 0 E30.py:161:8: E302 [*] Expected 2 blank lines, found 0 | -161 | # Previously just E272:1:6 E272:4:6 -162 | #: E302:4:1 E271:1:6 E271:4:6 -163 | async def x(): +159 | # Previously just E272:1:6 E272:4:6 +160 | #: E302:4:1 E271:1:6 E271:4:6 +161 | async def x(): | ^^^ E302 -164 | pass +162 | pass | = help: Add missing blank line(s) @@ -452,12 +452,12 @@ E30.py:161:8: E302 [*] Expected 2 blank lines, found 0 E30.py:164:8: E302 [*] Expected 2 blank lines, found 1 | -164 | pass -165 | -166 | async def x(y: int = 1): +162 | pass +163 | +164 | async def x(y: int = 1): | ^^^ E302 -167 | pass -168 | #: E704:3:1 E302:3:1 +165 | pass +166 | #: E704:3:1 E302:3:1 | = help: Add missing blank line(s) @@ -472,12 +472,12 @@ E30.py:164:8: E302 [*] Expected 2 blank lines, found 1 E30.py:167:1: E302 [*] Expected 2 blank lines, found 0 | -167 | pass -168 | #: E704:3:1 E302:3:1 -169 | def bar(): +165 | pass +166 | #: E704:3:1 E302:3:1 +167 | def bar(): | ^^^ E302 -170 | pass -171 | def baz(): pass +168 | pass +169 | def baz(): pass | = help: Add missing blank line(s) @@ -493,12 +493,12 @@ E30.py:167:1: E302 [*] Expected 2 blank lines, found 0 E30.py:169:1: E302 [*] Expected 2 blank lines, found 0 | -169 | def bar(): -170 | pass -171 | def baz(): pass +167 | def bar(): +168 | pass +169 | def baz(): pass | ^^^ E302 -172 | #: E704:1:1 E302:2:1 -173 | def bar(): pass +170 | #: E704:1:1 E302:2:1 +171 | def bar(): pass | = help: Add missing blank line(s) @@ -514,12 +514,12 @@ E30.py:169:1: E302 [*] Expected 2 blank lines, found 0 E30.py:171:1: E302 [*] Expected 2 blank lines, found 0 | -171 | def baz(): pass -172 | #: E704:1:1 E302:2:1 -173 | def bar(): pass +169 | def baz(): pass +170 | #: E704:1:1 E302:2:1 +171 | def bar(): pass | ^^^ E302 -174 | def baz(): -175 | pass +172 | def baz(): +173 | pass | = help: Add missing blank line(s) @@ -535,12 +535,12 @@ E30.py:171:1: E302 [*] Expected 2 blank lines, found 0 E30.py:172:1: E302 [*] Expected 2 blank lines, found 0 | -172 | #: E704:1:1 E302:2:1 -173 | def bar(): pass -174 | def baz(): +170 | #: E704:1:1 E302:2:1 +171 | def bar(): pass +172 | def baz(): | ^^^ E302 -175 | pass -176 | #: E704:4:5 E306:4:5 +173 | pass +174 | #: E704:4:5 E306:4:5 | = help: Add missing blank line(s) @@ -556,12 +556,12 @@ E30.py:172:1: E302 [*] Expected 2 blank lines, found 0 E30.py:175:1: E302 [*] Expected 2 blank lines, found 0 | -175 | pass -176 | #: E704:4:5 E306:4:5 -177 | def foo(): +173 | pass +174 | #: E704:4:5 E306:4:5 +175 | def foo(): | ^^^ E302 -178 | def bar(): -179 | pass +176 | def bar(): +177 | pass | = help: Add missing blank line(s) @@ -577,12 +577,12 @@ E30.py:175:1: E302 [*] Expected 2 blank lines, found 0 E30.py:176:5: E302 [*] Expected 2 blank lines, found 0 | -176 | #: E704:4:5 E306:4:5 -177 | def foo(): -178 | def bar(): +174 | #: E704:4:5 E306:4:5 +175 | def foo(): +176 | def bar(): | ^^^ E302 -179 | pass -180 | def baz(): pass +177 | pass +178 | def baz(): pass | = help: Add missing blank line(s) @@ -598,12 +598,12 @@ E30.py:176:5: E302 [*] Expected 2 blank lines, found 0 E30.py:178:5: E302 [*] Expected 2 blank lines, found 0 | -178 | def bar(): -179 | pass -180 | def baz(): pass +176 | def bar(): +177 | pass +178 | def baz(): pass | ^^^ E302 -181 | #: E704:2:5 E306:3:5 -182 | def foo(): +179 | #: E704:2:5 E306:3:5 +180 | def foo(): | = help: Add missing blank line(s) @@ -619,12 +619,12 @@ E30.py:178:5: E302 [*] Expected 2 blank lines, found 0 E30.py:180:1: E302 [*] Expected 2 blank lines, found 0 | -180 | def baz(): pass -181 | #: E704:2:5 E306:3:5 -182 | def foo(): +178 | def baz(): pass +179 | #: E704:2:5 E306:3:5 +180 | def foo(): | ^^^ E302 -183 | def bar(): pass -184 | def baz(): +181 | def bar(): pass +182 | def baz(): | = help: Add missing blank line(s) @@ -640,12 +640,12 @@ E30.py:180:1: E302 [*] Expected 2 blank lines, found 0 E30.py:181:5: E302 [*] Expected 2 blank lines, found 0 | -181 | #: E704:2:5 E306:3:5 -182 | def foo(): -183 | def bar(): pass +179 | #: E704:2:5 E306:3:5 +180 | def foo(): +181 | def bar(): pass | ^^^ E302 -184 | def baz(): -185 | pass +182 | def baz(): +183 | pass | = help: Add missing blank line(s) @@ -661,12 +661,12 @@ E30.py:181:5: E302 [*] Expected 2 blank lines, found 0 E30.py:182:5: E302 [*] Expected 2 blank lines, found 0 | -182 | def foo(): -183 | def bar(): pass -184 | def baz(): +180 | def foo(): +181 | def bar(): pass +182 | def baz(): | ^^^ E302 -185 | pass -186 | #: E302:5:1 +183 | pass +184 | #: E302:5:1 | = help: Add missing blank line(s) @@ -682,11 +682,11 @@ E30.py:182:5: E302 [*] Expected 2 blank lines, found 0 E30.py:185:1: E302 [*] Expected 2 blank lines, found 0 | -185 | pass -186 | #: E302:5:1 -187 | def f(): +183 | pass +184 | #: E302:5:1 +185 | def f(): | ^^^ E302 -188 | pass +186 | pass | = help: Add missing blank line(s) diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap index e8aa5231284bc..d1e7385344733 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E304_E30.py.snap @@ -3,12 +3,12 @@ source: crates/ruff/src/rules/pycodestyle/mod.rs --- E30.py:81:1: E304 [*] blank lines found after function decorator | -81 | @decorator -82 | -83 | def function(): +79 | @decorator +80 | +81 | def function(): | ^^^ E304 -84 | pass -85 | #: E303:5:1 +82 | pass +83 | #: E303:5:1 | = help: Remove extraneous blank line(s) diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap index d5c7aaae3fb2e..98c66f652450f 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap @@ -2,15 +2,15 @@ source: crates/ruff/src/rules/pycodestyle/mod.rs --- E30.py:6:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | - 6 | def a(): - 7 | pass - 8 | def b(): - | ^^^ E306 - 9 | pass -10 | #: E301:6:5 - | - = help: Add missing blank line + | +4 | def a(): +5 | pass +6 | def b(): + | ^^^ E306 +7 | pass +8 | #: E301:6:5 + | + = help: Add missing blank line ℹ Fix 3 3 | @@ -23,12 +23,12 @@ E30.py:6:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:14:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -14 | pass -15 | # comment -16 | def b(): +12 | pass +13 | # comment +14 | def b(): | ^^^ E306 -17 | pass -18 | #: +15 | pass +16 | #: | = help: Add missing blank line @@ -43,12 +43,12 @@ E30.py:14:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:125:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -125 | def a(): -126 | x = 1 -127 | def b(): +123 | def a(): +124 | x = 1 +125 | def b(): | ^^^ E306 -128 | pass -129 | #: E306:3:5 +126 | pass +127 | #: E306:3:5 | = help: Add missing blank line @@ -63,12 +63,12 @@ E30.py:125:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:130:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -130 | async def a(): -131 | x = 1 -132 | def b(): +128 | async def a(): +129 | x = 1 +130 | def b(): | ^^^ E306 -133 | pass -134 | #: E306:3:5 E306:5:9 +131 | pass +132 | #: E306:3:5 E306:5:9 | = help: Add missing blank line @@ -83,12 +83,12 @@ E30.py:130:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:135:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -135 | def a(): -136 | x = 2 -137 | def b(): +133 | def a(): +134 | x = 2 +135 | def b(): | ^^^ E306 -138 | x = 1 -139 | def c(): +136 | x = 1 +137 | def c(): | = help: Add missing blank line @@ -103,12 +103,12 @@ E30.py:135:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:137:9: E306 [*] Expected 1 blank line before a nested definition, found 0 | -137 | def b(): -138 | x = 1 -139 | def c(): +135 | def b(): +136 | x = 1 +137 | def c(): | ^^^ E306 -140 | pass -141 | #: E306:3:5 E306:6:5 +138 | pass +139 | #: E306:3:5 E306:6:5 | = help: Add missing blank line @@ -123,12 +123,12 @@ E30.py:137:9: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -142 | def a(): -143 | x = 1 -144 | class C: +140 | def a(): +141 | x = 1 +142 | class C: | ^^^^^ E306 -145 | pass -146 | x = 2 +143 | pass +144 | x = 2 | = help: Add missing blank line @@ -143,12 +143,12 @@ E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:145:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -145 | pass -146 | x = 2 -147 | def b(): +143 | pass +144 | x = 2 +145 | def b(): | ^^^ E306 -148 | pass -149 | #: +146 | pass +147 | #: | = help: Add missing blank line @@ -163,12 +163,12 @@ E30.py:145:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:176:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -176 | #: E704:4:5 E306:4:5 -177 | def foo(): -178 | def bar(): +174 | #: E704:4:5 E306:4:5 +175 | def foo(): +176 | def bar(): | ^^^ E306 -179 | pass -180 | def baz(): pass +177 | pass +178 | def baz(): pass | = help: Add missing blank line @@ -183,12 +183,12 @@ E30.py:176:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:178:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -178 | def bar(): -179 | pass -180 | def baz(): pass +176 | def bar(): +177 | pass +178 | def baz(): pass | ^^^ E306 -181 | #: E704:2:5 E306:3:5 -182 | def foo(): +179 | #: E704:2:5 E306:3:5 +180 | def foo(): | = help: Add missing blank line @@ -203,12 +203,12 @@ E30.py:178:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:181:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -181 | #: E704:2:5 E306:3:5 -182 | def foo(): -183 | def bar(): pass +179 | #: E704:2:5 E306:3:5 +180 | def foo(): +181 | def bar(): pass | ^^^ E306 -184 | def baz(): -185 | pass +182 | def baz(): +183 | pass | = help: Add missing blank line @@ -223,12 +223,12 @@ E30.py:181:5: E306 [*] Expected 1 blank line before a nested definition, found 0 E30.py:182:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | -182 | def foo(): -183 | def bar(): pass -184 | def baz(): +180 | def foo(): +181 | def bar(): pass +182 | def baz(): | ^^^ E306 -185 | pass -186 | #: E302:5:1 +183 | pass +184 | #: E302:5:1 | = help: Add missing blank line From 6e8c1dccff056be3523e5ab40f4f8fa50e5b9c0b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 12 Jun 2023 23:22:07 -0400 Subject: [PATCH 39/47] One violation per line --- .../rules/logical_lines/blank_lines.rs | 32 +-- ...ules__pycodestyle__tests__E306_E30.py.snap | 220 ------------------ 2 files changed, 11 insertions(+), 241 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index e21e8ac5167b7..423d53fba833a 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -341,7 +341,6 @@ pub(crate) fn blank_lines( } for (token_idx, token) in line.tokens().iter().enumerate() { - // E301 if token.kind() == TokenKind::Def && tracked_vars.is_in_class && tracked_vars.blank_lines == 0 @@ -349,6 +348,7 @@ pub(crate) fn blank_lines( .and_then(|prev_line| prev_line.tokens_trimmed().first()) .map_or(false, |token| token.kind() != TokenKind::Class) { + // E301 let mut diagnostic = Diagnostic::new( BlankLineBetweenMethods(tracked_vars.blank_lines), token.range(), @@ -358,15 +358,13 @@ pub(crate) fn blank_lines( locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); - } - - // E302 - if token.kind() == TokenKind::Def + } else if token.kind() == TokenKind::Def && !tracked_vars.follows_decorator && !tracked_vars.is_in_class && tracked_vars.blank_lines < 2 && prev_line.is_some() { + // E302 let mut diagnostic = Diagnostic::new(BlankLinesTopLevel(tracked_vars.blank_lines), token.range()); diagnostic.set_fix(Fix::automatic(Edit::insertion( @@ -378,14 +376,12 @@ pub(crate) fn blank_lines( locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); - } - - // E303 - if token_idx == 0 + } else if token_idx == 0 && (tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL || ((tracked_vars.is_in_class || tracked_vars.is_in_fn) && tracked_vars.blank_lines > BlankLinesConfig::METHOD)) { + // E303 let mut diagnostic = Diagnostic::new(TooManyBlankLines(tracked_vars.blank_lines), token.range()); @@ -399,10 +395,8 @@ pub(crate) fn blank_lines( diagnostic.set_fix(Fix::automatic(Edit::deletion(start, end))); context.push_diagnostic(diagnostic); - } - - // E304 - if tracked_vars.follows_decorator && tracked_vars.blank_lines > 0 { + } else if tracked_vars.follows_decorator && tracked_vars.blank_lines > 0 { + // E304 let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); let range = token.range(); @@ -411,13 +405,11 @@ pub(crate) fn blank_lines( locator.line_start(range.start()), ))); context.push_diagnostic(diagnostic); - } - - // E305 - if tracked_vars.blank_lines < 2 + } else if tracked_vars.blank_lines < 2 && (tracked_vars.is_in_fn || tracked_vars.is_in_class) && indent_level == 0 { + // E305 let mut diagnostic = Diagnostic::new( BlankLinesAfterFunctionOrClass(tracked_vars.blank_lines), token.range(), @@ -431,13 +423,11 @@ pub(crate) fn blank_lines( locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); - } - - // E306 - if matches!(token.kind(), TokenKind::Def | TokenKind::Class) + } else if matches!(token.kind(), TokenKind::Def | TokenKind::Class) && (tracked_vars.is_in_class || tracked_vars.is_in_fn) && tracked_vars.blank_lines == 0 { + // E306 let mut diagnostic = Diagnostic::new( BlankLinesBeforeNestedDefinition(tracked_vars.blank_lines), token.range(), diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap index 98c66f652450f..902fae9a306bb 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap @@ -1,126 +1,6 @@ --- source: crates/ruff/src/rules/pycodestyle/mod.rs --- -E30.py:6:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -4 | def a(): -5 | pass -6 | def b(): - | ^^^ E306 -7 | pass -8 | #: E301:6:5 - | - = help: Add missing blank line - -ℹ Fix -3 3 | -4 4 | def a(): -5 5 | pass - 6 |+ -6 7 | def b(): -7 8 | pass -8 9 | #: E301:6:5 - -E30.py:14:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -12 | pass -13 | # comment -14 | def b(): - | ^^^ E306 -15 | pass -16 | #: - | - = help: Add missing blank line - -ℹ Fix -11 11 | def a(): -12 12 | pass -13 13 | # comment - 14 |+ -14 15 | def b(): -15 16 | pass -16 17 | #: - -E30.py:125:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -123 | def a(): -124 | x = 1 -125 | def b(): - | ^^^ E306 -126 | pass -127 | #: E306:3:5 - | - = help: Add missing blank line - -ℹ Fix -122 122 | #: E306:3:5 -123 123 | def a(): -124 124 | x = 1 - 125 |+ -125 126 | def b(): -126 127 | pass -127 128 | #: E306:3:5 - -E30.py:130:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -128 | async def a(): -129 | x = 1 -130 | def b(): - | ^^^ E306 -131 | pass -132 | #: E306:3:5 E306:5:9 - | - = help: Add missing blank line - -ℹ Fix -127 127 | #: E306:3:5 -128 128 | async def a(): -129 129 | x = 1 - 130 |+ -130 131 | def b(): -131 132 | pass -132 133 | #: E306:3:5 E306:5:9 - -E30.py:135:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -133 | def a(): -134 | x = 2 -135 | def b(): - | ^^^ E306 -136 | x = 1 -137 | def c(): - | - = help: Add missing blank line - -ℹ Fix -132 132 | #: E306:3:5 E306:5:9 -133 133 | def a(): -134 134 | x = 2 - 135 |+ -135 136 | def b(): -136 137 | x = 1 -137 138 | def c(): - -E30.py:137:9: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -135 | def b(): -136 | x = 1 -137 | def c(): - | ^^^ E306 -138 | pass -139 | #: E306:3:5 E306:6:5 - | - = help: Add missing blank line - -ℹ Fix -134 134 | x = 2 -135 135 | def b(): -136 136 | x = 1 - 137 |+ -137 138 | def c(): -138 139 | pass -139 140 | #: E306:3:5 E306:6:5 - E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | 140 | def a(): @@ -141,104 +21,4 @@ E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 143 144 | pass 144 145 | x = 2 -E30.py:145:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -143 | pass -144 | x = 2 -145 | def b(): - | ^^^ E306 -146 | pass -147 | #: - | - = help: Add missing blank line - -ℹ Fix -142 142 | class C: -143 143 | pass -144 144 | x = 2 - 145 |+ -145 146 | def b(): -146 147 | pass -147 148 | #: - -E30.py:176:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -174 | #: E704:4:5 E306:4:5 -175 | def foo(): -176 | def bar(): - | ^^^ E306 -177 | pass -178 | def baz(): pass - | - = help: Add missing blank line - -ℹ Fix -173 173 | pass -174 174 | #: E704:4:5 E306:4:5 -175 175 | def foo(): - 176 |+ -176 177 | def bar(): -177 178 | pass -178 179 | def baz(): pass - -E30.py:178:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -176 | def bar(): -177 | pass -178 | def baz(): pass - | ^^^ E306 -179 | #: E704:2:5 E306:3:5 -180 | def foo(): - | - = help: Add missing blank line - -ℹ Fix -175 175 | def foo(): -176 176 | def bar(): -177 177 | pass - 178 |+ -178 179 | def baz(): pass -179 180 | #: E704:2:5 E306:3:5 -180 181 | def foo(): - -E30.py:181:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -179 | #: E704:2:5 E306:3:5 -180 | def foo(): -181 | def bar(): pass - | ^^^ E306 -182 | def baz(): -183 | pass - | - = help: Add missing blank line - -ℹ Fix -178 178 | def baz(): pass -179 179 | #: E704:2:5 E306:3:5 -180 180 | def foo(): - 181 |+ -181 182 | def bar(): pass -182 183 | def baz(): -183 184 | pass - -E30.py:182:5: E306 [*] Expected 1 blank line before a nested definition, found 0 - | -180 | def foo(): -181 | def bar(): pass -182 | def baz(): - | ^^^ E306 -183 | pass -184 | #: E302:5:1 - | - = help: Add missing blank line - -ℹ Fix -179 179 | #: E704:2:5 E306:3:5 -180 180 | def foo(): -181 181 | def bar(): pass - 182 |+ -182 183 | def baz(): -183 184 | pass -184 185 | #: E302:5:1 - From 0b6e96266b29aefbd6ffbdaaab11765e99e0f2d4 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 16 Jun 2023 23:25:05 +0900 Subject: [PATCH 40/47] Track the number of preceding blank lines in the logical lines builder in order to not emit empty lines as logical lines. --- crates/ruff/src/checkers/logical_lines.rs | 24 ++++---- .../rules/logical_lines/blank_lines.rs | 57 ++++++++----------- .../pycodestyle/rules/logical_lines/mod.rs | 35 ++++++++---- 3 files changed, 59 insertions(+), 57 deletions(-) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 2f6b3274e7817..b6697b5c040dd 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -108,18 +108,16 @@ pub(crate) fn check_logical_lines( let indent_size = 4; - if !line.is_empty() { - for kind in indentation( - &line, - prev_line.as_ref(), - indent_char, - indent_level, - prev_indent_level, - indent_size, - ) { - if settings.rules.enabled(kind.rule()) { - context.push(kind, range); - } + for kind in indentation( + &line, + prev_line.as_ref(), + indent_char, + indent_level, + prev_indent_level, + indent_size, + ) { + if settings.rules.enabled(kind.rule()) { + context.push(kind, range); } } @@ -133,7 +131,7 @@ pub(crate) fn check_logical_lines( &mut context, ); - if !line.is_comment_only() && !line.is_empty() { + if !line.is_comment_only() { prev_line = Some(line); prev_indent_level = Some(indent_level); } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 423d53fba833a..52d59b5c736cc 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -17,10 +17,6 @@ use super::LogicalLine; #[derive(Default)] #[allow(clippy::struct_excessive_bools)] pub(crate) struct BlankLinesTrackingVars { - /// Number of consecutive blank lines. - blank_lines: u32, - /// Number of blank characters in the blank lines (\n vs \r\n for example). - blank_characters: u32, follows_decorator: bool, follows_def: bool, is_in_class: bool, @@ -325,13 +321,6 @@ pub(crate) fn blank_lines( stylist: &Stylist, context: &mut LogicalLinesContext, ) { - if line.is_empty() { - tracked_vars.blank_lines += 1; - tracked_vars.blank_characters += u32::try_from(line.text().chars().count()) - .expect("The number of blank characters should be relatively small"); - return; - } - if indent_level <= tracked_vars.class_indent_level { tracked_vars.is_in_class = false; } @@ -343,14 +332,14 @@ pub(crate) fn blank_lines( for (token_idx, token) in line.tokens().iter().enumerate() { if token.kind() == TokenKind::Def && tracked_vars.is_in_class - && tracked_vars.blank_lines == 0 + && line.line.preceding_blank_lines == 0 && prev_line .and_then(|prev_line| prev_line.tokens_trimmed().first()) .map_or(false, |token| token.kind() != TokenKind::Class) { // E301 let mut diagnostic = Diagnostic::new( - BlankLineBetweenMethods(tracked_vars.blank_lines), + BlankLineBetweenMethods(line.line.preceding_blank_lines), token.range(), ); diagnostic.set_fix(Fix::automatic(Edit::insertion( @@ -361,57 +350,62 @@ pub(crate) fn blank_lines( } else if token.kind() == TokenKind::Def && !tracked_vars.follows_decorator && !tracked_vars.is_in_class - && tracked_vars.blank_lines < 2 + && line.line.preceding_blank_lines < 2 && prev_line.is_some() { // E302 - let mut diagnostic = - Diagnostic::new(BlankLinesTopLevel(tracked_vars.blank_lines), token.range()); + let mut diagnostic = Diagnostic::new( + BlankLinesTopLevel(line.line.preceding_blank_lines), + token.range(), + ); diagnostic.set_fix(Fix::automatic(Edit::insertion( stylist .line_ending() .as_str() .to_string() - .repeat(2 - tracked_vars.blank_lines as usize), + .repeat(2 - line.line.preceding_blank_lines as usize), locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); } else if token_idx == 0 - && (tracked_vars.blank_lines > BlankLinesConfig::TOP_LEVEL + && (line.line.preceding_blank_lines > BlankLinesConfig::TOP_LEVEL || ((tracked_vars.is_in_class || tracked_vars.is_in_fn) - && tracked_vars.blank_lines > BlankLinesConfig::METHOD)) + && line.line.preceding_blank_lines > BlankLinesConfig::METHOD)) { // E303 - let mut diagnostic = - Diagnostic::new(TooManyBlankLines(tracked_vars.blank_lines), token.range()); + let mut diagnostic = Diagnostic::new( + TooManyBlankLines(line.line.preceding_blank_lines), + token.range(), + ); let chars_to_remove = if indent_level > 0 { - tracked_vars.blank_characters - BlankLinesConfig::METHOD + line.line.preceding_blank_characters - BlankLinesConfig::METHOD } else { - tracked_vars.blank_characters - BlankLinesConfig::TOP_LEVEL + line.line.preceding_blank_characters - BlankLinesConfig::TOP_LEVEL }; let end = locator.line_start(token.range().start()); let start = end - TextSize::new(chars_to_remove); diagnostic.set_fix(Fix::automatic(Edit::deletion(start, end))); context.push_diagnostic(diagnostic); - } else if tracked_vars.follows_decorator && tracked_vars.blank_lines > 0 { + } else if tracked_vars.follows_decorator && line.line.preceding_blank_lines > 0 { // E304 let mut diagnostic = Diagnostic::new(BlankLineAfterDecorator, token.range()); let range = token.range(); diagnostic.set_fix(Fix::automatic(Edit::deletion( - locator.line_start(range.start()) - TextSize::new(tracked_vars.blank_characters), + locator.line_start(range.start()) + - TextSize::new(line.line.preceding_blank_characters), locator.line_start(range.start()), ))); context.push_diagnostic(diagnostic); - } else if tracked_vars.blank_lines < 2 + } else if line.line.preceding_blank_lines < 2 && (tracked_vars.is_in_fn || tracked_vars.is_in_class) && indent_level == 0 { // E305 let mut diagnostic = Diagnostic::new( - BlankLinesAfterFunctionOrClass(tracked_vars.blank_lines), + BlankLinesAfterFunctionOrClass(line.line.preceding_blank_lines), token.range(), ); diagnostic.set_fix(Fix::automatic(Edit::insertion( @@ -419,17 +413,17 @@ pub(crate) fn blank_lines( .line_ending() .as_str() .to_string() - .repeat(2 - tracked_vars.blank_lines as usize), + .repeat(2 - line.line.preceding_blank_lines as usize), locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); } else if matches!(token.kind(), TokenKind::Def | TokenKind::Class) && (tracked_vars.is_in_class || tracked_vars.is_in_fn) - && tracked_vars.blank_lines == 0 + && line.line.preceding_blank_lines == 0 { // E306 let mut diagnostic = Diagnostic::new( - BlankLinesBeforeNestedDefinition(tracked_vars.blank_lines), + BlankLinesBeforeNestedDefinition(line.line.preceding_blank_lines), token.range(), ); diagnostic.set_fix(Fix::automatic(Edit::insertion( @@ -470,7 +464,4 @@ pub(crate) fn blank_lines( } } } - - tracked_vars.blank_lines = 0; - tracked_vars.blank_characters = 0; } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 18f9dffbc656d..32df51d79ecc0 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -138,11 +138,6 @@ impl<'a> LogicalLine<'a> { self.flags() == TokenFlags::COMMENT } - /// Returns `true` if this is a comment only line - pub(crate) fn is_empty(&self) -> bool { - self.tokens().iter().all(|token| token.kind.is_newline()) - } - /// Returns logical line's text including comments, indents, dedent and trailing new lines. pub(crate) fn text(&self) -> &'a str { let tokens = self.tokens(); @@ -430,6 +425,10 @@ struct LogicalLinesBuilder { tokens: Vec, lines: Vec, current_line: CurrentLine, + /// Number of consecutive blank lines. + current_blank_lines: u32, + /// Number of blank characters in the blank lines (\n vs \r\n for example). + current_blank_characters: u32, } impl LogicalLinesBuilder { @@ -490,11 +489,23 @@ impl LogicalLinesBuilder { fn finish_line(&mut self) { let end = self.tokens.len() as u32; if self.current_line.tokens_start < end { - self.lines.push(Line { - flags: self.current_line.flags, - tokens_start: self.current_line.tokens_start, - tokens_end: end, - }); + let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] + .iter() + .all(|token| token.kind.is_newline()); + if is_empty { + self.current_blank_lines += 1; + self.current_blank_characters += end - self.current_line.tokens_start; + } else { + self.lines.push(Line { + flags: self.current_line.flags, + preceding_blank_lines: self.current_blank_lines, + preceding_blank_characters: self.current_blank_characters, + tokens_start: self.current_line.tokens_start, + tokens_end: end, + }); + self.current_blank_lines = 0; + self.current_blank_characters = 0; + } self.current_line = CurrentLine { flags: TokenFlags::default(), @@ -517,6 +528,8 @@ impl LogicalLinesBuilder { #[derive(Debug, Clone)] struct Line { flags: TokenFlags, + preceding_blank_lines: u32, + preceding_blank_characters: u32, tokens_start: u32, tokens_end: u32, } @@ -604,7 +617,7 @@ if False: print() "# .trim(), - &["if False:", "", "print()", ""], + &["if False:", "print()", ""], ); } From 53e94f0ebc0cc7afa33f8581f75ad2487a21d65b Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 30 Jun 2023 00:10:57 +0900 Subject: [PATCH 41/47] Fix E302 not taking into account nested functions. --- .../rules/logical_lines/blank_lines.rs | 1 + ...ules__pycodestyle__tests__E302_E30.py.snap | 189 ------------------ ...ules__pycodestyle__tests__E306_E30.py.snap | 180 +++++++++++++++++ 3 files changed, 181 insertions(+), 189 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 52d59b5c736cc..4f8d3ad99218b 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -350,6 +350,7 @@ pub(crate) fn blank_lines( } else if token.kind() == TokenKind::Def && !tracked_vars.follows_decorator && !tracked_vars.is_in_class + && !tracked_vars.is_in_fn && line.line.preceding_blank_lines < 2 && prev_line.is_some() { diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap index efa45c412e2fd..a3de2d6144567 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E302_E30.py.snap @@ -262,27 +262,6 @@ E30.py:123:1: E302 [*] Expected 2 blank lines, found 0 124 126 | x = 1 125 127 | def b(): -E30.py:125:5: E302 [*] Expected 2 blank lines, found 0 - | -123 | def a(): -124 | x = 1 -125 | def b(): - | ^^^ E302 -126 | pass -127 | #: E306:3:5 - | - = help: Add missing blank line(s) - -ℹ Fix -122 122 | #: E306:3:5 -123 123 | def a(): -124 124 | x = 1 - 125 |+ - 126 |+ -125 127 | def b(): -126 128 | pass -127 129 | #: E306:3:5 - E30.py:128:7: E302 [*] Expected 2 blank lines, found 0 | 126 | pass @@ -304,27 +283,6 @@ E30.py:128:7: E302 [*] Expected 2 blank lines, found 0 129 131 | x = 1 130 132 | def b(): -E30.py:130:5: E302 [*] Expected 2 blank lines, found 0 - | -128 | async def a(): -129 | x = 1 -130 | def b(): - | ^^^ E302 -131 | pass -132 | #: E306:3:5 E306:5:9 - | - = help: Add missing blank line(s) - -ℹ Fix -127 127 | #: E306:3:5 -128 128 | async def a(): -129 129 | x = 1 - 130 |+ - 131 |+ -130 132 | def b(): -131 133 | pass -132 134 | #: E306:3:5 E306:5:9 - E30.py:133:1: E302 [*] Expected 2 blank lines, found 0 | 131 | pass @@ -346,48 +304,6 @@ E30.py:133:1: E302 [*] Expected 2 blank lines, found 0 134 136 | x = 2 135 137 | def b(): -E30.py:135:5: E302 [*] Expected 2 blank lines, found 0 - | -133 | def a(): -134 | x = 2 -135 | def b(): - | ^^^ E302 -136 | x = 1 -137 | def c(): - | - = help: Add missing blank line(s) - -ℹ Fix -132 132 | #: E306:3:5 E306:5:9 -133 133 | def a(): -134 134 | x = 2 - 135 |+ - 136 |+ -135 137 | def b(): -136 138 | x = 1 -137 139 | def c(): - -E30.py:137:9: E302 [*] Expected 2 blank lines, found 0 - | -135 | def b(): -136 | x = 1 -137 | def c(): - | ^^^ E302 -138 | pass -139 | #: E306:3:5 E306:6:5 - | - = help: Add missing blank line(s) - -ℹ Fix -134 134 | x = 2 -135 135 | def b(): -136 136 | x = 1 - 137 |+ - 138 |+ -137 139 | def c(): -138 140 | pass -139 141 | #: E306:3:5 E306:6:5 - E30.py:140:1: E302 [*] Expected 2 blank lines, found 0 | 138 | pass @@ -409,27 +325,6 @@ E30.py:140:1: E302 [*] Expected 2 blank lines, found 0 141 143 | x = 1 142 144 | class C: -E30.py:145:5: E302 [*] Expected 2 blank lines, found 0 - | -143 | pass -144 | x = 2 -145 | def b(): - | ^^^ E302 -146 | pass -147 | #: - | - = help: Add missing blank line(s) - -ℹ Fix -142 142 | class C: -143 143 | pass -144 144 | x = 2 - 145 |+ - 146 |+ -145 147 | def b(): -146 148 | pass -147 149 | #: - E30.py:161:8: E302 [*] Expected 2 blank lines, found 0 | 159 | # Previously just E272:1:6 E272:4:6 @@ -575,48 +470,6 @@ E30.py:175:1: E302 [*] Expected 2 blank lines, found 0 176 178 | def bar(): 177 179 | pass -E30.py:176:5: E302 [*] Expected 2 blank lines, found 0 - | -174 | #: E704:4:5 E306:4:5 -175 | def foo(): -176 | def bar(): - | ^^^ E302 -177 | pass -178 | def baz(): pass - | - = help: Add missing blank line(s) - -ℹ Fix -173 173 | pass -174 174 | #: E704:4:5 E306:4:5 -175 175 | def foo(): - 176 |+ - 177 |+ -176 178 | def bar(): -177 179 | pass -178 180 | def baz(): pass - -E30.py:178:5: E302 [*] Expected 2 blank lines, found 0 - | -176 | def bar(): -177 | pass -178 | def baz(): pass - | ^^^ E302 -179 | #: E704:2:5 E306:3:5 -180 | def foo(): - | - = help: Add missing blank line(s) - -ℹ Fix -175 175 | def foo(): -176 176 | def bar(): -177 177 | pass - 178 |+ - 179 |+ -178 180 | def baz(): pass -179 181 | #: E704:2:5 E306:3:5 -180 182 | def foo(): - E30.py:180:1: E302 [*] Expected 2 blank lines, found 0 | 178 | def baz(): pass @@ -638,48 +491,6 @@ E30.py:180:1: E302 [*] Expected 2 blank lines, found 0 181 183 | def bar(): pass 182 184 | def baz(): -E30.py:181:5: E302 [*] Expected 2 blank lines, found 0 - | -179 | #: E704:2:5 E306:3:5 -180 | def foo(): -181 | def bar(): pass - | ^^^ E302 -182 | def baz(): -183 | pass - | - = help: Add missing blank line(s) - -ℹ Fix -178 178 | def baz(): pass -179 179 | #: E704:2:5 E306:3:5 -180 180 | def foo(): - 181 |+ - 182 |+ -181 183 | def bar(): pass -182 184 | def baz(): -183 185 | pass - -E30.py:182:5: E302 [*] Expected 2 blank lines, found 0 - | -180 | def foo(): -181 | def bar(): pass -182 | def baz(): - | ^^^ E302 -183 | pass -184 | #: E302:5:1 - | - = help: Add missing blank line(s) - -ℹ Fix -179 179 | #: E704:2:5 E306:3:5 -180 180 | def foo(): -181 181 | def bar(): pass - 182 |+ - 183 |+ -182 184 | def baz(): -183 185 | pass -184 186 | #: E302:5:1 - E30.py:185:1: E302 [*] Expected 2 blank lines, found 0 | 183 | pass diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap index 902fae9a306bb..7f9f29fc1a626 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E306_E30.py.snap @@ -1,6 +1,86 @@ --- source: crates/ruff/src/rules/pycodestyle/mod.rs --- +E30.py:125:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +123 | def a(): +124 | x = 1 +125 | def b(): + | ^^^ E306 +126 | pass +127 | #: E306:3:5 + | + = help: Add missing blank line + +ℹ Fix +122 122 | #: E306:3:5 +123 123 | def a(): +124 124 | x = 1 + 125 |+ +125 126 | def b(): +126 127 | pass +127 128 | #: E306:3:5 + +E30.py:130:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +128 | async def a(): +129 | x = 1 +130 | def b(): + | ^^^ E306 +131 | pass +132 | #: E306:3:5 E306:5:9 + | + = help: Add missing blank line + +ℹ Fix +127 127 | #: E306:3:5 +128 128 | async def a(): +129 129 | x = 1 + 130 |+ +130 131 | def b(): +131 132 | pass +132 133 | #: E306:3:5 E306:5:9 + +E30.py:135:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +133 | def a(): +134 | x = 2 +135 | def b(): + | ^^^ E306 +136 | x = 1 +137 | def c(): + | + = help: Add missing blank line + +ℹ Fix +132 132 | #: E306:3:5 E306:5:9 +133 133 | def a(): +134 134 | x = 2 + 135 |+ +135 136 | def b(): +136 137 | x = 1 +137 138 | def c(): + +E30.py:137:9: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +135 | def b(): +136 | x = 1 +137 | def c(): + | ^^^ E306 +138 | pass +139 | #: E306:3:5 E306:6:5 + | + = help: Add missing blank line + +ℹ Fix +134 134 | x = 2 +135 135 | def b(): +136 136 | x = 1 + 137 |+ +137 138 | def c(): +138 139 | pass +139 140 | #: E306:3:5 E306:6:5 + E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 | 140 | def a(): @@ -21,4 +101,104 @@ E30.py:142:5: E306 [*] Expected 1 blank line before a nested definition, found 0 143 144 | pass 144 145 | x = 2 +E30.py:145:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +143 | pass +144 | x = 2 +145 | def b(): + | ^^^ E306 +146 | pass +147 | #: + | + = help: Add missing blank line + +ℹ Fix +142 142 | class C: +143 143 | pass +144 144 | x = 2 + 145 |+ +145 146 | def b(): +146 147 | pass +147 148 | #: + +E30.py:176:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +174 | #: E704:4:5 E306:4:5 +175 | def foo(): +176 | def bar(): + | ^^^ E306 +177 | pass +178 | def baz(): pass + | + = help: Add missing blank line + +ℹ Fix +173 173 | pass +174 174 | #: E704:4:5 E306:4:5 +175 175 | def foo(): + 176 |+ +176 177 | def bar(): +177 178 | pass +178 179 | def baz(): pass + +E30.py:178:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +176 | def bar(): +177 | pass +178 | def baz(): pass + | ^^^ E306 +179 | #: E704:2:5 E306:3:5 +180 | def foo(): + | + = help: Add missing blank line + +ℹ Fix +175 175 | def foo(): +176 176 | def bar(): +177 177 | pass + 178 |+ +178 179 | def baz(): pass +179 180 | #: E704:2:5 E306:3:5 +180 181 | def foo(): + +E30.py:181:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +179 | #: E704:2:5 E306:3:5 +180 | def foo(): +181 | def bar(): pass + | ^^^ E306 +182 | def baz(): +183 | pass + | + = help: Add missing blank line + +ℹ Fix +178 178 | def baz(): pass +179 179 | #: E704:2:5 E306:3:5 +180 180 | def foo(): + 181 |+ +181 182 | def bar(): pass +182 183 | def baz(): +183 184 | pass + +E30.py:182:5: E306 [*] Expected 1 blank line before a nested definition, found 0 + | +180 | def foo(): +181 | def bar(): pass +182 | def baz(): + | ^^^ E306 +183 | pass +184 | #: E302:5:1 + | + = help: Add missing blank line + +ℹ Fix +179 179 | #: E704:2:5 E306:3:5 +180 180 | def foo(): +181 181 | def bar(): pass + 182 |+ +182 183 | def baz(): +183 184 | pass +184 185 | #: E302:5:1 + From 071849ec3b8d09ff3c76fefea62d41d4903894f1 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 6 Jul 2023 18:20:29 +0900 Subject: [PATCH 42/47] Ignore comment only lines. --- .../pycodestyle/rules/logical_lines/mod.rs | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 32df51d79ecc0..286dcc2beb8d0 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -489,22 +489,26 @@ impl LogicalLinesBuilder { fn finish_line(&mut self) { let end = self.tokens.len() as u32; if self.current_line.tokens_start < end { - let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] - .iter() - .all(|token| token.kind.is_newline()); - if is_empty { - self.current_blank_lines += 1; - self.current_blank_characters += end - self.current_line.tokens_start; - } else { - self.lines.push(Line { - flags: self.current_line.flags, - preceding_blank_lines: self.current_blank_lines, - preceding_blank_characters: self.current_blank_characters, - tokens_start: self.current_line.tokens_start, - tokens_end: end, - }); - self.current_blank_lines = 0; - self.current_blank_characters = 0; + // Do not take comment only lines into account when it comes to empty lines. + if self.current_line.flags != TokenFlags::COMMENT { + let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] + .iter() + .all(|token| token.kind.is_newline()); + if is_empty { + // self.current_line.flags. + self.current_blank_lines += 1; + self.current_blank_characters += end - self.current_line.tokens_start; + } else { + self.lines.push(Line { + flags: self.current_line.flags, + preceding_blank_lines: self.current_blank_lines, + preceding_blank_characters: self.current_blank_characters, + tokens_start: self.current_line.tokens_start, + tokens_end: end, + }); + self.current_blank_lines = 0; + self.current_blank_characters = 0; + } } self.current_line = CurrentLine { From 75b11a9a62760a3cdc414d610e72c8ae6e817e38 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Thu, 6 Jul 2023 18:21:32 +0900 Subject: [PATCH 43/47] Fix E302 not detecting issues with classes --- .../src/rules/pycodestyle/rules/logical_lines/blank_lines.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 4f8d3ad99218b..023ba4d7ed89a 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -347,7 +347,7 @@ pub(crate) fn blank_lines( locator.line_start(token.range().start()), ))); context.push_diagnostic(diagnostic); - } else if token.kind() == TokenKind::Def + } else if matches!(token.kind(), TokenKind::Def | TokenKind::Class) && !tracked_vars.follows_decorator && !tracked_vars.is_in_class && !tracked_vars.is_in_fn From 9f748351ec50ce1d841a38131ea781c2e4a46263 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Fri, 7 Jul 2023 12:01:59 +0900 Subject: [PATCH 44/47] Revert "Ignore comment only lines." This reverts commit 071849ec3b8d09ff3c76fefea62d41d4903894f1. --- .../pycodestyle/rules/logical_lines/mod.rs | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index 286dcc2beb8d0..32df51d79ecc0 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -489,26 +489,22 @@ impl LogicalLinesBuilder { fn finish_line(&mut self) { let end = self.tokens.len() as u32; if self.current_line.tokens_start < end { - // Do not take comment only lines into account when it comes to empty lines. - if self.current_line.flags != TokenFlags::COMMENT { - let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] - .iter() - .all(|token| token.kind.is_newline()); - if is_empty { - // self.current_line.flags. - self.current_blank_lines += 1; - self.current_blank_characters += end - self.current_line.tokens_start; - } else { - self.lines.push(Line { - flags: self.current_line.flags, - preceding_blank_lines: self.current_blank_lines, - preceding_blank_characters: self.current_blank_characters, - tokens_start: self.current_line.tokens_start, - tokens_end: end, - }); - self.current_blank_lines = 0; - self.current_blank_characters = 0; - } + let is_empty = self.tokens[self.current_line.tokens_start as usize..end as usize] + .iter() + .all(|token| token.kind.is_newline()); + if is_empty { + self.current_blank_lines += 1; + self.current_blank_characters += end - self.current_line.tokens_start; + } else { + self.lines.push(Line { + flags: self.current_line.flags, + preceding_blank_lines: self.current_blank_lines, + preceding_blank_characters: self.current_blank_characters, + tokens_start: self.current_line.tokens_start, + tokens_end: end, + }); + self.current_blank_lines = 0; + self.current_blank_characters = 0; } self.current_line = CurrentLine { From 10c9571deed6d5ce827d20cb75efd1613c30ac6f Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Tue, 22 Aug 2023 15:24:17 +0900 Subject: [PATCH 45/47] Update E30 fixture --- .../test/fixtures/pycodestyle/E30.py | 532 +++++++++++++++--- 1 file changed, 452 insertions(+), 80 deletions(-) diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/E30.py b/crates/ruff/resources/test/fixtures/pycodestyle/E30.py index ebe4e9d254690..2b89de8548e57 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/E30.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/E30.py @@ -1,36 +1,317 @@ -#: E301:5:5 -class X: +"""Fixtures for the errors E301, E302, E303, E304, E305 and E306. - def a(): +Since these errors are about new lines, each test starts with either "No error" or "# E30X". +Each test's end is signaled by a "# end" line. + +There should be no E30X error outside of a test's bound. +""" + + +# No error +class Class: + pass +# end + + +# No error +def func(): + pass +# end + + +# No error +# comment +class Class: + pass +# end + + +# No error +# comment +def func(): + pass +# end + + +# no error +def foo(): + pass + + +def bar(): + pass + + +class Foo(object): + pass + + +class Bar(object): + pass +# end + + +# No error +class Class(object): + + def func1(): pass - def b(): + + def func2(): pass -#: E301:6:5 -class X: +# end + - def a(): +# No error +class Class: + + def func1(): pass + # comment - def b(): + def func2(): + pass + + # This is a + # ... multi-line comment + + def func3(): + pass + + +# This is a +# ... multi-line comment + +@decorator +class Class: + + def func1(): + pass + + # comment + + def func2(): + pass + + @property + def func3(): + pass + +# end + + +# No error +try: + from nonexistent import Bar +except ImportError: + class Bar(object): + """This is a Bar replacement""" +# end + + +# No error +def with_feature(f): + """Some decorator""" + wrapper = f + if has_this_feature(f): + def wrapper(*args): + call_feature(args[0]) + return f(*args) + return wrapper +# end + + +# No error +try: + next +except NameError: + def next(iterator, default): + for item in iterator: + return item + return default +# end + + +# No error +def fn(): + pass + + +class Foo(): + """Class Foo""" + + def fn(): + + pass +# end + + +# No error +# comment +def c(): + pass + + +# comment + + +def d(): + pass + +# This is a +# ... multi-line comment + +# And this one is +# ... a second paragraph +# ... which spans on 3 lines + + +# Function `e` is below +# NOTE: Hey this is a testcase + +def e(): + pass + + +def fn(): + print() + + # comment + + print() + + print() + +# Comment 1 + +# Comment 2 + + +# Comment 3 + +def fn2(): + + pass +# end + + +# no error +if __name__ == '__main__': + foo() +# end + + +# no error +defaults = {} +defaults.update({}) +# end + + +# no error +def foo(x): + classification = x + definitely = not classification +# end + + +# no error +def bar(): pass +def baz(): pass +# end + + +# no error +def foo(): + def bar(): pass + def baz(): pass +# end + + +# no error +from typing import overload +from typing import Union +# end + + +# no error +@overload +def f(x: int) -> int: ... +@overload +def f(x: str) -> str: ... +# end + + +# no error +def f(x: Union[int, str]) -> Union[int, str]: + return x +# end + + +# no error +from typing import Protocol + + +class C(Protocol): + @property + def f(self) -> int: ... + @property + def g(self) -> str: ... +# end + + +# no error +def f( + a, +): + pass +# end + + +# E301 +class Class(object): + + def func1(): + pass + def func2(): + pass +# end + + +# E301 +class Class: + + def fn1(): + pass + # comment + def fn2(): pass -#: +# end -#: E302:2:1 +# E302 """Main module.""" -def _main(): +def fn(): pass -#: E302:2:1 +# end + + +# E302 import sys def get_sys_path(): return sys.path -#: E302:4:1 +# end + + +# E302 def a(): pass def b(): pass -#: E302:6:1 +# end + + +# E302 def a(): pass @@ -38,32 +319,93 @@ def a(): def b(): pass -#: -#: E302:4:1 +# end + + +# E302 def a(): pass async def b(): pass -#: +# end + + +# E302 +async def x(): + pass + +async def x(y: int = 1): + pass +# end + + +# E302 +def bar(): + pass +def baz(): pass +# end + + +# E302 +def bar(): pass +def baz(): + pass +# end + + +# E302 +def f(): + pass +# end + + +# E303 +def fn(): + _ = None -#: E303:5:1 -print + # arbitrary comment + + def inner(): # E306 not expected + pass +# end -print -#: E303:5:1 -print +# E303 +def fn(): + _ = None + + + # arbitrary comment + def inner(): # E306 not expected + pass +# end + + +# E303 +print() + + + +print() +# end + + +# E303:5:1 +print() # comment -print -#: E303:5:5 E303:8:5 +print() +# end + + +# E303:5:5 E303:8:5 def a(): - print + print() # comment @@ -71,16 +413,11 @@ def a(): # another comment - print -#: - + print() +# end -#: E304:3:1 -@decorator -def function(): - pass -#: E303:5:1 +# E303 #!python @@ -88,47 +425,93 @@ def function(): """This class docstring comes on line 5. It gives error E303: too many blank lines (3) """ -#: +# end -#: E305:7:1 -def a(): - print + +# E304 +@decorator + +def function(): + pass +# end + + +# E305:7:1 +def fn(): + print() # comment # another comment -a() -#: E305:8:1 -def a(): - print +fn() +# end + + +# E305 +class Class(): + pass + + # comment + + # another comment +a = 1 +# end + + +# E305:8:1 +def fn(): + print() # comment # another comment try: - a() + fn() except Exception: pass -#: E305:5:1 +# end + + +# E305:5:1 def a(): print # Two spaces before comments, too. if a(): a() -#: +# end -#: E306:3:5 + +#: E305:8:1 +# Example from https://github.com/PyCQA/pycodestyle/issues/400 +import stuff + + +def main(): + blah, blah + +if __name__ == '__main__': + main() +# end + + +# E306:3:5 def a(): x = 1 def b(): pass +# end + + #: E306:3:5 async def a(): x = 1 def b(): pass +# end + + #: E306:3:5 E306:5:9 def a(): x = 2 @@ -136,7 +519,10 @@ def b(): x = 1 def c(): pass -#: E306:3:5 E306:6:5 +# end + + +# E306:3:5 E306:6:5 def a(): x = 1 class C: @@ -144,48 +530,34 @@ class C: x = 2 def b(): pass -#: - -#: E305:8:1 -# Example from https://github.com/PyCQA/pycodestyle/issues/400 -import stuff - - -def main(): - blah, blah +# end -if __name__ == '__main__': - main() -# Previously just E272:1:6 E272:4:6 -#: E302:4:1 E271:1:6 E271:4:6 -async def x(): - pass -async def x(y: int = 1): - pass -#: E704:3:1 E302:3:1 -def bar(): - pass -def baz(): pass -#: E704:1:1 E302:2:1 -def bar(): pass -def baz(): - pass -#: E704:4:5 E306:4:5 +# E306:4:5 def foo(): def bar(): pass def baz(): pass -#: E704:2:5 E306:3:5 +# end + + +# E306:3:5 def foo(): def bar(): pass def baz(): pass -#: E302:5:1 -def f(): - pass +# end -# wat -@hi -def g(): - pass + +# E306 +class C: + def f(): + pass +# end + + +# E306 +def f(): + def f(): + pass +# end From a12a57c5132b506b37957cb0d786f74ff69915c5 Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sat, 26 Aug 2023 20:13:43 +0900 Subject: [PATCH 46/47] Fix false positive 301 on def following @ and class definition (E306). --- .../src/rules/pycodestyle/rules/logical_lines/blank_lines.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index 023ba4d7ed89a..e2824c7ff1004 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -333,9 +333,12 @@ pub(crate) fn blank_lines( if token.kind() == TokenKind::Def && tracked_vars.is_in_class && line.line.preceding_blank_lines == 0 + && !tracked_vars.follows_decorator && prev_line .and_then(|prev_line| prev_line.tokens_trimmed().first()) - .map_or(false, |token| token.kind() != TokenKind::Class) + .map_or(false, |token| { + !matches!(token.kind(), TokenKind::Def | TokenKind::Class) + }) { // E301 let mut diagnostic = Diagnostic::new( From 30724189de4281d556a1cfeab126ee52e485d15e Mon Sep 17 00:00:00 2001 From: Hoel Bagard Date: Sat, 26 Aug 2023 21:02:16 +0900 Subject: [PATCH 47/47] Fix non-comment related E302 errors. --- .../resources/test/fixtures/pycodestyle/E30.py | 5 +++++ .../pycodestyle/rules/logical_lines/blank_lines.rs | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/E30.py b/crates/ruff/resources/test/fixtures/pycodestyle/E30.py index 2b89de8548e57..084ecb091d7c2 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/E30.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/E30.py @@ -357,6 +357,11 @@ def baz(): # E302 def f(): pass + +# comment +@decorator +def g(): + pass # end diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs index e2824c7ff1004..a64f5e9dbc514 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/blank_lines.rs @@ -351,9 +351,17 @@ pub(crate) fn blank_lines( ))); context.push_diagnostic(diagnostic); } else if matches!(token.kind(), TokenKind::Def | TokenKind::Class) - && !tracked_vars.follows_decorator - && !tracked_vars.is_in_class - && !tracked_vars.is_in_fn + && !(tracked_vars.follows_decorator + || tracked_vars.is_in_class + || tracked_vars.is_in_fn + || tracked_vars.follows_def + && line + .tokens_trimmed() + .last() + .map_or(false, |token| !matches!(token.kind(), TokenKind::Colon))) + && prev_line + .and_then(|prev_line| prev_line.tokens_trimmed().first()) + .map_or(false, |token| !matches!(token.kind(), TokenKind::Except)) && line.line.preceding_blank_lines < 2 && prev_line.is_some() {