From 33216f3235076f6ae03ae72f15655c22d20f1b93 Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Fri, 21 Jun 2024 13:30:07 +0200 Subject: [PATCH 01/11] Feat: created file whitespace_after_decorator with the struct and violation tag --- .../src/rules/pycodestyle/rules/whitespace_after_decorator.rs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs new file mode 100644 index 0000000000000..499b80c170065 --- /dev/null +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs @@ -0,0 +1,2 @@ +#[violation] +pub struct WhitespaceAfterDecorator; From 17e902d3078a1f2d6319b6ab9a0fd7dfebe4ff01 Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Sun, 23 Jun 2024 18:20:17 +0200 Subject: [PATCH 02/11] Feat: implementaiton of the function whitespace_after_decorator --- .../pycodestyle/rules/whitespace_after_decorator.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs index 499b80c170065..9265ba7abc8eb 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs @@ -1,2 +1,15 @@ +use ruff_diagnostic::AlwaysFixableViolation; + #[violation] pub struct WhitespaceAfterDecorator; + +impl AlwaysFixableViolation for WhitespaceAfterDecorator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Whitespace after decorator") + } + + fn fix_title(&self) -> String { + "Remove whitespace after decorator".to_string() + } +} From a3cbd5484ce3022eae7d20b251817f1814ec6a98 Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Sun, 23 Jun 2024 18:21:25 +0200 Subject: [PATCH 03/11] Feat: implementation of function --- .../rules/whitespace_after_decorator.rs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs index 9265ba7abc8eb..fa4786cc22c88 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs @@ -1,4 +1,7 @@ -use ruff_diagnostic::AlwaysFixableViolation; +use ruff_diagnostic::{AlwaysFixableViolation, Diagnostic, DiagnosticKind}; +use ruff_python_ast::ast::{self, Visitor}; +use ruff_python_ast::node::Node; +use ruff_python_ast::source_code::Locator; #[violation] pub struct WhitespaceAfterDecorator; @@ -13,3 +16,25 @@ impl AlwaysFixableViolation for WhitespaceAfterDecorator { "Remove whitespace after decorator".to_string() } } + +pub(crate) fn whitespace_after_decorator( + node: &ast::Stmt, + locator: &Locator, +) -> Option { + if let ast::Stmt::FunctionDef { decorators, .. } = node { + for decorator in decorators { + let decorator_end = decorator.end(); + + if let Some(char_after) = locator.get_char(decorator_end) { + if char_after.is_whitespace() { + return Some(Diagnostic::new( + DiagnosticKind::AlwaysFixable(WhitespaceAfterDecorator), + decorator_end, + "Whitespace after decorator".to_string(), + )); + } + } + } + } + None +} From 93ea4fab96eb3958a2a29f40d522224ee69d73ab Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Sun, 23 Jun 2024 18:21:39 +0200 Subject: [PATCH 04/11] Feat: added function to mod.rs --- crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs index 178dd13b5be43..f921ffc7a3fe5 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs @@ -20,6 +20,7 @@ pub(crate) use tab_indentation::*; pub(crate) use too_many_newlines_at_end_of_file::*; pub(crate) use trailing_whitespace::*; pub(crate) use type_comparison::*; +pub(crate) use whitespace_after_decorator::*; mod ambiguous_class_name; mod ambiguous_function_name; From fc32d1c0a596e62256d84bd3ef4f48e15b2ae158 Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Mon, 1 Jul 2024 10:41:15 +0200 Subject: [PATCH 05/11] Feat: finished a working implementation of rule E204 --- .../rules/whitespace_after_decorator.rs | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs index fa4786cc22c88..c64cdfbb73007 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs @@ -1,7 +1,27 @@ -use ruff_diagnostic::{AlwaysFixableViolation, Diagnostic, DiagnosticKind}; -use ruff_python_ast::ast::{self, Visitor}; -use ruff_python_ast::node::Node; -use ruff_python_ast::source_code::Locator; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Decorator; +use ruff_python_trivia::is_python_whitespace; +use ruff_text_size::{TextLen, TextRange}; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for whitespace after a decorator. +/// +/// ## Why is this bad? +/// +/// +/// +/// ## Formatter compatibility +/// +/// +/// +/// +/// +/// +/// +/// #[violation] pub struct WhitespaceAfterDecorator; @@ -17,24 +37,28 @@ impl AlwaysFixableViolation for WhitespaceAfterDecorator { } } -pub(crate) fn whitespace_after_decorator( - node: &ast::Stmt, - locator: &Locator, -) -> Option { - if let ast::Stmt::FunctionDef { decorators, .. } = node { - for decorator in decorators { - let decorator_end = decorator.end(); - - if let Some(char_after) = locator.get_char(decorator_end) { - if char_after.is_whitespace() { - return Some(Diagnostic::new( - DiagnosticKind::AlwaysFixable(WhitespaceAfterDecorator), - decorator_end, - "Whitespace after decorator".to_string(), - )); - } - } +// Function that checks weather there is a whitespace after a decorator using +// the provided `Decorator` list and the functions +// You can use locator.slice(decorator) to get the text of the decorator. +// The last step is to find the @ and then test if whatever comes after is_python_whitespace. +pub(crate) fn whitespace_after_decorator(checker: &mut Checker, decorator_list: &[Decorator]) { + // Get the locator from the checker + let locator = checker.locator(); + + // Iterate over the list of decorators + for decorator in decorator_list { + // Obtain the text of the decorator using lactor.slice(decorator) + let decorator_text = locator.slice(decorator); + + // Get the text after the @ symbol + let after_at = &decorator_text[1..]; + + // Check if there is a whitespace after the @ symbol by using is_python_whitespace + if is_python_whitespace(after_at.chars().next().unwrap()) { + let range = TextRange::empty(locator.contents().text_len()); + checker + .diagnostics + .push(Diagnostic::new(WhitespaceAfterDecorator, range)); } } - None } From b463d2d8798e907cff4a0296e2d8bbd58f75c55c Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Mon, 1 Jul 2024 10:42:51 +0200 Subject: [PATCH 06/11] Feat: added the correct export for the function --- crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 89a0c7e5c7e89..867ffae8cbef7 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -91,6 +91,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pycodestyle, "E202") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceBeforeCloseBracket), #[allow(deprecated)] (Pycodestyle, "E203") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceBeforePunctuation), + (Pycodestyle, "E204") => (RuleGroup::Preview, rules::pycodestyle::rules::WhitespaceAfterDecorator), #[allow(deprecated)] (Pycodestyle, "E211") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceBeforeParameters), #[allow(deprecated)] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs index f921ffc7a3fe5..3d553518ed748 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/mod.rs @@ -44,3 +44,4 @@ mod tab_indentation; mod too_many_newlines_at_end_of_file; mod trailing_whitespace; mod type_comparison; +mod whitespace_after_decorator; From 4a81eb81a9a6796351b65d2330bbad027cb0afbd Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Mon, 1 Jul 2024 10:43:43 +0200 Subject: [PATCH 07/11] Feat: invoking the function in the AST checker --- crates/ruff_linter/src/checkers/ast/analyze/statement.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 552fb66844b6b..6bfb0dbac27a9 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -368,6 +368,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::UnusedAsync) { ruff::rules::unused_async(checker, function_def); } + if checker.enabled(Rule::WhitespaceAfterDecorator) { + pycodestyle::rules::whitespace_after_decorator(checker, decorator_list); + } } Stmt::Return(_) => { if checker.enabled(Rule::ReturnOutsideFunction) { @@ -531,6 +534,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::MetaClassABCMeta) { refurb::rules::metaclass_abcmeta(checker, class_def); } + if checker.enabled(Rule::WhitespaceAfterDecorator) { + pycodestyle::rules::whitespace_after_decorator(checker, decorator_list); + } } Stmt::Import(ast::StmtImport { names, range: _ }) => { if checker.enabled(Rule::MultipleImportsOnOneLine) { From 2a92b0235852fb032ef17c8a2bf46cf7ad7a538e Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Mon, 1 Jul 2024 10:44:04 +0200 Subject: [PATCH 08/11] Test: created test file --- .../test/fixtures/pycodestyle/E204.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py new file mode 100644 index 0000000000000..0dd7d30fb7384 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py @@ -0,0 +1,27 @@ +def foo(fun): + def wrapper(): + print('before') + fun() + print('after') + return wrapper + +# No error +@foo +def bar(): + print('bar') + +# E204 +@ foo +def baz(): + print('baz') + +class Test: + # No error + @foo + def bar(self): + print('bar') + + # E204 + @ foo + def baz(self): + print('baz') \ No newline at end of file From 7053727ba6e6ea770c3392b95c2e68b4e776c0c7 Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Mon, 1 Jul 2024 10:46:38 +0200 Subject: [PATCH 09/11] Docs: added correct documentation --- .../rules/whitespace_after_decorator.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs index c64cdfbb73007..b82fe4a804861 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs @@ -10,18 +10,21 @@ use crate::checkers::ast::Checker; /// Checks for whitespace after a decorator. /// /// ## Why is this bad? +/// Whitespace after a decorator is not PEP8 compliant. /// +/// ## Example /// -/// -/// ## Formatter compatibility -/// -/// -/// -/// -/// -/// -/// -/// +/// ```python +/// @ decorator +/// def foo(): +/// pass +/// ``` +/// Use instead: +/// ``` python +/// @decorator +/// def foo(): +/// pass +/// ``` #[violation] pub struct WhitespaceAfterDecorator; @@ -37,10 +40,7 @@ impl AlwaysFixableViolation for WhitespaceAfterDecorator { } } -// Function that checks weather there is a whitespace after a decorator using -// the provided `Decorator` list and the functions -// You can use locator.slice(decorator) to get the text of the decorator. -// The last step is to find the @ and then test if whatever comes after is_python_whitespace. +/// E204 pub(crate) fn whitespace_after_decorator(checker: &mut Checker, decorator_list: &[Decorator]) { // Get the locator from the checker let locator = checker.locator(); From 61728539562fff85793c7a332121c302de544aa4 Mon Sep 17 00:00:00 2001 From: Javier Kauer Date: Mon, 1 Jul 2024 11:14:15 +0200 Subject: [PATCH 10/11] Feat: updated snapshot --- ruff.schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/ruff.schema.json b/ruff.schema.json index 349889ac705cd..08661067de289 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2870,6 +2870,7 @@ "E201", "E202", "E203", + "E204", "E21", "E211", "E22", From 33cd37090a82a2a8e588cb2c50a47673ceffa061 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 4 Jul 2024 19:21:25 -0400 Subject: [PATCH 11/11] Add a fix --- .../test/fixtures/pycodestyle/E204.py | 9 ++- .../ruff_linter/src/rules/pycodestyle/mod.rs | 1 + .../rules/whitespace_after_decorator.rs | 51 ++++++++------- ...les__pycodestyle__tests__E204_E204.py.snap | 63 ++++++++++++++++++ ..._pycodestyle__tests__E204_E204.py.snap.new | 65 +++++++++++++++++++ 5 files changed, 166 insertions(+), 23 deletions(-) create mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap create mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap.new diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py index 0dd7d30fb7384..60d218a17bf49 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E204.py @@ -24,4 +24,11 @@ def bar(self): # E204 @ foo def baz(self): - print('baz') \ No newline at end of file + print('baz') + + +# E204 +@ \ +foo +def baz(): + print('baz') diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index dbb9a293b8735..f792f3e4bae7d 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -58,6 +58,7 @@ mod tests { #[test_case(Rule::TypeComparison, Path::new("E721.py"))] #[test_case(Rule::UselessSemicolon, Path::new("E70.py"))] #[test_case(Rule::UselessSemicolon, Path::new("E703.ipynb"))] + #[test_case(Rule::WhitespaceAfterDecorator, Path::new("E204.py"))] fn rules(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_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs index b82fe4a804861..f820b5f1ecd4b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/whitespace_after_decorator.rs @@ -1,30 +1,34 @@ -use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic}; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::Decorator; use ruff_python_trivia::is_python_whitespace; -use ruff_text_size::{TextLen, TextRange}; +use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::checkers::ast::Checker; /// ## What it does -/// Checks for whitespace after a decorator. +/// Checks for trailing whitespace after a decorator's opening `@`. /// /// ## Why is this bad? -/// Whitespace after a decorator is not PEP8 compliant. +/// Including whitespace after the `@` symbol is not compliant with +/// [PEP 8]. /// /// ## Example /// /// ```python /// @ decorator -/// def foo(): +/// def func(): /// pass /// ``` +/// /// Use instead: -/// ``` python +/// ```python /// @decorator -/// def foo(): +/// def func(): /// pass /// ``` +/// +/// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length #[violation] pub struct WhitespaceAfterDecorator; @@ -36,29 +40,32 @@ impl AlwaysFixableViolation for WhitespaceAfterDecorator { } fn fix_title(&self) -> String { - "Remove whitespace after decorator".to_string() + "Remove whitespace".to_string() } } /// E204 pub(crate) fn whitespace_after_decorator(checker: &mut Checker, decorator_list: &[Decorator]) { - // Get the locator from the checker - let locator = checker.locator(); - - // Iterate over the list of decorators for decorator in decorator_list { - // Obtain the text of the decorator using lactor.slice(decorator) - let decorator_text = locator.slice(decorator); + let decorator_text = checker.locator().slice(decorator); + + // Determine whether the `@` is followed by whitespace. + if let Some(trailing) = decorator_text.strip_prefix('@') { + // Collect the whitespace characters after the `@`. + if trailing.chars().next().is_some_and(is_python_whitespace) { + let end = trailing + .chars() + .position(|c| !(is_python_whitespace(c) || matches!(c, '\n' | '\r' | '\\'))) + .unwrap_or(trailing.len()); - // Get the text after the @ symbol - let after_at = &decorator_text[1..]; + let start = decorator.start() + TextSize::from(1); + let end = start + TextSize::try_from(end).unwrap(); + let range = TextRange::new(start, end); - // Check if there is a whitespace after the @ symbol by using is_python_whitespace - if is_python_whitespace(after_at.chars().next().unwrap()) { - let range = TextRange::empty(locator.contents().text_len()); - checker - .diagnostics - .push(Diagnostic::new(WhitespaceAfterDecorator, range)); + let mut diagnostic = Diagnostic::new(WhitespaceAfterDecorator, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(range))); + checker.diagnostics.push(diagnostic); + } } } } diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap new file mode 100644 index 0000000000000..d942156f88466 --- /dev/null +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap @@ -0,0 +1,63 @@ +--- +source: crates/ruff_linter/src/rules/pycodestyle/mod.rs +--- +E204.py:14:1: E204 [*] Whitespace after decorator + | +13 | # E204 +14 | @ foo + | ^^^^^ E204 +15 | def baz(): +16 | print('baz') + | + = help: Remove whitespace + +ℹ Safe fix +11 11 | print('bar') +12 12 | +13 13 | # E204 +14 |-@ foo + 14 |+@foo +15 15 | def baz(): +16 16 | print('baz') +17 17 | + +E204.py:25:5: E204 [*] Whitespace after decorator + | +24 | # E204 +25 | @ foo + | ^^^^^ E204 +26 | def baz(self): +27 | print('baz') + | + = help: Remove whitespace + +ℹ Safe fix +22 22 | print('bar') +23 23 | +24 24 | # E204 +25 |- @ foo + 25 |+ @foo +26 26 | def baz(self): +27 27 | print('baz') +28 28 | + +E204.py:31:1: E204 [*] Whitespace after decorator + | +30 | # E204 +31 | / @ \ +32 | | foo + | |___^ E204 +33 | def baz(): +34 | print('baz') + | + = help: Remove whitespace + +ℹ Safe fix +28 28 | +29 29 | +30 30 | # E204 +31 |-@ \ +32 |-foo + 31 |+@foo +33 32 | def baz(): +34 33 | print('baz') diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap.new b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap.new new file mode 100644 index 0000000000000..77aa00266bf22 --- /dev/null +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E204_E204.py.snap.new @@ -0,0 +1,65 @@ +--- +source: crates/ruff_linter/src/rules/pycodestyle/mod.rs +assertion_line: 68 +--- +E204.py:14:2: E204 [*] Whitespace after decorator + | +13 | # E204 +14 | @ foo + | ^ E204 +15 | def baz(): +16 | print('baz') + | + = help: Remove whitespace + +ℹ Safe fix +11 11 | print('bar') +12 12 | +13 13 | # E204 +14 |-@ foo + 14 |+@foo +15 15 | def baz(): +16 16 | print('baz') +17 17 | + +E204.py:25:6: E204 [*] Whitespace after decorator + | +24 | # E204 +25 | @ foo + | ^ E204 +26 | def baz(self): +27 | print('baz') + | + = help: Remove whitespace + +ℹ Safe fix +22 22 | print('bar') +23 23 | +24 24 | # E204 +25 |- @ foo + 25 |+ @foo +26 26 | def baz(self): +27 27 | print('baz') +28 28 | + +E204.py:31:2: E204 [*] Whitespace after decorator + | +30 | # E204 +31 | @ \ + | __^ +32 | | foo + | |_^ E204 +33 | def baz(): +34 | print('baz') + | + = help: Remove whitespace + +ℹ Safe fix +28 28 | +29 29 | +30 30 | # E204 +31 |-@ \ +32 |-foo + 31 |+@foo +33 32 | def baz(): +34 33 | print('baz')