diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E23.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E23.py index 37d8a282a3282e..51ea101fb0b866 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E23.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E23.py @@ -104,3 +104,37 @@ def main() -> None: ] } ] + +# Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + x:A = "foo"[::-1], + y:B = [[["foo", "bar"]]], + z:object = "fooo", +): + pass + +class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + pass + +class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + pass + +class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + pass + +# Should be no E231 errors on any of these: +def pep_696_good[A: object="foo"[::-1], B: object =[[["foo", "bar"]]], C: object= bytes]( + x: A = "foo"[::-1], + y: B = [[["foo", "bar"]]], + z: object = "fooo", +): + pass + +class PEP696Good[A: object="foo"[::-1], B: object =[[["foo", "bar"]]], C: object= bytes]: + pass + +class PEP696GoodWithEmptyBases[A: object="foo"[::-1], B: object =[[["foo", "bar"]]], C: object= bytes](): + pass + +class PEP696GoodWithNonEmptyBases[A: object="foo"[::-1], B: object =[[["foo", "bar"]]], C: object= bytes](object, something_dynamic[x::-1]): + pass diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py index 9d8bddac4234cd..549d0f571bee78 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py @@ -59,3 +59,18 @@ def add(a: int = _default(name='f')): print(f"{foo = }") # ...but then it creates false negatives for now print(f"{foo(a = 1)}") + +# There should be at least one E251 diagnostic for each type parameter here: +def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + pass + +class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + pass + +# The last of these should cause us to emit E231, +# but E231 isn't tested by this fixture: +def pep_696_good[A = int, B: object = str, C:object = memoryview](): + pass + +class PEP696Good[A = int, B: object = str, C:object = memoryview]: + pass diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs index b9a7eb8aab6e4e..951e38540c7925 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs @@ -6,7 +6,7 @@ use ruff_text_size::Ranged; use crate::checkers::logical_lines::LogicalLinesContext; -use super::LogicalLine; +use super::{LogicalLine, TypeParamsState}; /// ## What it does /// Checks for missing whitespace after `,`, `;`, and `:`. @@ -28,22 +28,10 @@ pub struct MissingWhitespace { token: TokenKind, } -impl MissingWhitespace { - fn token_text(&self) -> char { - match self.token { - TokenKind::Colon => ':', - TokenKind::Semi => ';', - TokenKind::Comma => ',', - _ => unreachable!(), - } - } -} - impl AlwaysFixableViolation for MissingWhitespace { #[derive_message_formats] fn message(&self) -> String { - let token = self.token_text(); - format!("Missing whitespace after '{token}'") + format!("Missing whitespace after {}", self.token) } fn fix_title(&self) -> String { @@ -54,11 +42,13 @@ impl AlwaysFixableViolation for MissingWhitespace { /// E231 pub(crate) fn missing_whitespace(line: &LogicalLine, context: &mut LogicalLinesContext) { let mut fstrings = 0u32; + let mut class_or_function_state = TypeParamsState::new(); let mut brackets = Vec::new(); let mut iter = line.tokens().iter().peekable(); while let Some(token) = iter.next() { let kind = token.kind(); + class_or_function_state.visit_token_kind(kind); match kind { TokenKind::FStringStart => fstrings += 1, TokenKind::FStringEnd => fstrings = fstrings.saturating_sub(1), @@ -97,7 +87,9 @@ pub(crate) fn missing_whitespace(line: &LogicalLine, context: &mut LogicalLinesC if let Some(next_token) = iter.peek() { match (kind, next_token.kind()) { (TokenKind::Colon, _) - if matches!(brackets.last(), Some(TokenKind::Lsqb)) => + if matches!(brackets.last(), Some(TokenKind::Lsqb)) + && !(class_or_function_state.in_type_params() + && brackets.len() == 1) => { continue; // Slice syntax, no space required } @@ -111,13 +103,10 @@ pub(crate) fn missing_whitespace(line: &LogicalLine, context: &mut LogicalLinesC } } - let mut diagnostic = + let diagnostic = Diagnostic::new(MissingWhitespace { token: kind }, token.range()); - diagnostic.set_fix(Fix::safe_edit(Edit::insertion( - " ".to_string(), - token.end(), - ))); - context.push_diagnostic(diagnostic); + let fix = Fix::safe_edit(Edit::insertion(" ".to_string(), token.end())); + context.push_diagnostic(diagnostic.with_fix(fix)); } } _ => {} diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs index 69fa5d96dfcab9..a83fb652eb1d45 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -470,6 +470,74 @@ struct Line { tokens_end: u32, } +/// Keeps track of whether we are currently visiting the [type parameters] +/// of a class or function definition in a [`LogicalLine`]. +/// +/// Call [`TypeParamsState::visit_token_kind`] on the [`TokenKind`] of each +/// successive [`LogicalLineToken`] to ensure the state remains up to date. +/// +/// [type parameters]: https://docs.python.org/3/reference/compound_stmts.html#type-params +#[derive(Debug, Clone, Copy)] +enum TypeParamsState { + BeforeClassOrDefKeyword, + BeforeTypeParams, + InTypeParams { inner_square_brackets: u32 }, + TypeParamsEnded, +} + +impl TypeParamsState { + const fn new() -> Self { + Self::BeforeClassOrDefKeyword + } + + const fn in_class_or_function_def(self) -> bool { + !matches!(self, Self::BeforeClassOrDefKeyword) + } + + const fn before_type_params(self) -> bool { + matches!(self, Self::BeforeTypeParams) + } + + const fn in_type_params(self) -> bool { + matches!(self, Self::InTypeParams { .. }) + } + + fn visit_token_kind(&mut self, token: TokenKind) { + match token { + TokenKind::Class | TokenKind::Def if !self.in_class_or_function_def() => { + *self = TypeParamsState::BeforeTypeParams; + } + TokenKind::Lpar if self.before_type_params() => { + *self = TypeParamsState::TypeParamsEnded; + } + TokenKind::Lsqb => match self { + TypeParamsState::BeforeClassOrDefKeyword | TypeParamsState::TypeParamsEnded => {} + TypeParamsState::BeforeTypeParams => { + *self = TypeParamsState::InTypeParams { + inner_square_brackets: 0, + }; + } + TypeParamsState::InTypeParams { + inner_square_brackets, + } => *inner_square_brackets += 1, + }, + TokenKind::Rsqb => { + if let TypeParamsState::InTypeParams { + inner_square_brackets, + } = self + { + if *inner_square_brackets == 0 { + *self = TypeParamsState::TypeParamsEnded; + } else { + *inner_square_brackets -= 1; + } + } + } + _ => {} + } + } +} + #[cfg(test)] mod tests { use ruff_python_parser::parse_module; diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs index a0c4f49bf22505..1384de1c837d96 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs @@ -4,7 +4,9 @@ use ruff_python_parser::TokenKind; use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::checkers::logical_lines::LogicalLinesContext; -use crate::rules::pycodestyle::rules::logical_lines::{LogicalLine, LogicalLineToken}; +use crate::rules::pycodestyle::rules::logical_lines::{ + LogicalLine, LogicalLineToken, TypeParamsState, +}; /// ## What it does /// Checks for missing whitespace around the equals sign in an unannotated @@ -106,17 +108,15 @@ pub(crate) fn whitespace_around_named_parameter_equals( let mut annotated_func_arg = false; let mut prev_end = TextSize::default(); + let mut type_params_state = TypeParamsState::new(); let in_def = is_in_def(line.tokens()); let mut iter = line.tokens().iter().peekable(); while let Some(token) = iter.next() { - let kind = token.kind(); - - if kind == TokenKind::NonLogicalNewline { - continue; - } - - match kind { + let token_kind = token.kind(); + type_params_state.visit_token_kind(token_kind); + match token_kind { + TokenKind::NonLogicalNewline => continue, TokenKind::FStringStart => fstrings += 1, TokenKind::FStringEnd => fstrings = fstrings.saturating_sub(1), TokenKind::Lpar | TokenKind::Lsqb => { @@ -128,15 +128,16 @@ pub(crate) fn whitespace_around_named_parameter_equals( annotated_func_arg = false; } } - TokenKind::Colon if parens == 1 && in_def => { annotated_func_arg = true; } TokenKind::Comma if parens == 1 => { annotated_func_arg = false; } - TokenKind::Equal if parens > 0 && fstrings == 0 => { - if annotated_func_arg && parens == 1 { + TokenKind::Equal + if type_params_state.in_type_params() || (parens > 0 && fstrings == 0) => + { + if type_params_state.in_type_params() || (annotated_func_arg && parens == 1) { let start = token.start(); if start == prev_end && prev_end != TextSize::new(0) { let mut diagnostic = diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E231_E23.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E231_E23.py.snap index 62abb9df58ccbe..a83055ba436cd0 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E231_E23.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E231_E23.py.snap @@ -476,3 +476,306 @@ E23.py:102:24: E231 [*] Missing whitespace after ',' 103 103 | }, 104 104 | ] 105 105 | } + +E23.py:109:18: E231 [*] Missing whitespace after ':' + | +108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + | ^ E231 +110 | x:A = "foo"[::-1], +111 | y:B = [[["foo", "bar"]]], + | + = help: Add missing whitespace + +ℹ Safe fix +106 106 | ] +107 107 | +108 108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 |-def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + 109 |+def pep_696_bad[A: object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( +110 110 | x:A = "foo"[::-1], +111 111 | y:B = [[["foo", "bar"]]], +112 112 | z:object = "fooo", + +E23.py:109:40: E231 [*] Missing whitespace after ':' + | +108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + | ^ E231 +110 | x:A = "foo"[::-1], +111 | y:B = [[["foo", "bar"]]], + | + = help: Add missing whitespace + +ℹ Safe fix +106 106 | ] +107 107 | +108 108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 |-def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + 109 |+def pep_696_bad[A:object="foo"[::-1], B: object =[[["foo", "bar"]]], C:object= bytes]( +110 110 | x:A = "foo"[::-1], +111 111 | y:B = [[["foo", "bar"]]], +112 112 | z:object = "fooo", + +E23.py:109:70: E231 [*] Missing whitespace after ':' + | +108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + | ^ E231 +110 | x:A = "foo"[::-1], +111 | y:B = [[["foo", "bar"]]], + | + = help: Add missing whitespace + +ℹ Safe fix +106 106 | ] +107 107 | +108 108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 |-def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( + 109 |+def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C: object= bytes]( +110 110 | x:A = "foo"[::-1], +111 111 | y:B = [[["foo", "bar"]]], +112 112 | z:object = "fooo", + +E23.py:110:6: E231 [*] Missing whitespace after ':' + | +108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( +110 | x:A = "foo"[::-1], + | ^ E231 +111 | y:B = [[["foo", "bar"]]], +112 | z:object = "fooo", + | + = help: Add missing whitespace + +ℹ Safe fix +107 107 | +108 108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( +110 |- x:A = "foo"[::-1], + 110 |+ x: A = "foo"[::-1], +111 111 | y:B = [[["foo", "bar"]]], +112 112 | z:object = "fooo", +113 113 | ): + +E23.py:111:6: E231 [*] Missing whitespace after ':' + | +109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( +110 | x:A = "foo"[::-1], +111 | y:B = [[["foo", "bar"]]], + | ^ E231 +112 | z:object = "fooo", +113 | ): + | + = help: Add missing whitespace + +ℹ Safe fix +108 108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults +109 109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( +110 110 | x:A = "foo"[::-1], +111 |- y:B = [[["foo", "bar"]]], + 111 |+ y: B = [[["foo", "bar"]]], +112 112 | z:object = "fooo", +113 113 | ): +114 114 | pass + +E23.py:112:6: E231 [*] Missing whitespace after ':' + | +110 | x:A = "foo"[::-1], +111 | y:B = [[["foo", "bar"]]], +112 | z:object = "fooo", + | ^ E231 +113 | ): +114 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +109 109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]( +110 110 | x:A = "foo"[::-1], +111 111 | y:B = [[["foo", "bar"]]], +112 |- z:object = "fooo", + 112 |+ z: object = "fooo", +113 113 | ): +114 114 | pass +115 115 | + +E23.py:116:18: E231 [*] Missing whitespace after ':' + | +114 | pass +115 | +116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + | ^ E231 +117 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +113 113 | ): +114 114 | pass +115 115 | +116 |-class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + 116 |+class PEP696Bad[A: object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: +117 117 | pass +118 118 | +119 119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + +E23.py:116:40: E231 [*] Missing whitespace after ':' + | +114 | pass +115 | +116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + | ^ E231 +117 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +113 113 | ): +114 114 | pass +115 115 | +116 |-class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + 116 |+class PEP696Bad[A:object="foo"[::-1], B: object =[[["foo", "bar"]]], C:object= bytes]: +117 117 | pass +118 118 | +119 119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + +E23.py:116:70: E231 [*] Missing whitespace after ':' + | +114 | pass +115 | +116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + | ^ E231 +117 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +113 113 | ): +114 114 | pass +115 115 | +116 |-class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: + 116 |+class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C: object= bytes]: +117 117 | pass +118 118 | +119 119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + +E23.py:119:32: E231 [*] Missing whitespace after ':' + | +117 | pass +118 | +119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + | ^ E231 +120 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +116 116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: +117 117 | pass +118 118 | +119 |-class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + 119 |+class PEP696BadWithEmptyBases[A: object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): +120 120 | pass +121 121 | +122 122 | class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + +E23.py:119:54: E231 [*] Missing whitespace after ':' + | +117 | pass +118 | +119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + | ^ E231 +120 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +116 116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: +117 117 | pass +118 118 | +119 |-class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + 119 |+class PEP696BadWithEmptyBases[A:object="foo"[::-1], B: object =[[["foo", "bar"]]], C:object= bytes](): +120 120 | pass +121 121 | +122 122 | class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + +E23.py:119:84: E231 [*] Missing whitespace after ':' + | +117 | pass +118 | +119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + | ^ E231 +120 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +116 116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]: +117 117 | pass +118 118 | +119 |-class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): + 119 |+class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C: object= bytes](): +120 120 | pass +121 121 | +122 122 | class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + +E23.py:122:35: E231 [*] Missing whitespace after ':' + | +120 | pass +121 | +122 | class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + | ^ E231 +123 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +119 119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): +120 120 | pass +121 121 | +122 |-class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + 122 |+class PEP696BadWithNonEmptyBases[A: object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): +123 123 | pass +124 124 | +125 125 | # Should be no E231 errors on any of these: + +E23.py:122:57: E231 [*] Missing whitespace after ':' + | +120 | pass +121 | +122 | class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + | ^ E231 +123 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +119 119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): +120 120 | pass +121 121 | +122 |-class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + 122 |+class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B: object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): +123 123 | pass +124 124 | +125 125 | # Should be no E231 errors on any of these: + +E23.py:122:87: E231 [*] Missing whitespace after ':' + | +120 | pass +121 | +122 | class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + | ^ E231 +123 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +119 119 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](): +120 120 | pass +121 121 | +122 |-class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](object, something_dynamic[x::-1]): + 122 |+class PEP696BadWithNonEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C: object= bytes](object, something_dynamic[x::-1]): +123 123 | pass +124 124 | +125 125 | # Should be no E231 errors on any of these: diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E252_E25.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E252_E25.py.snap index 54c129811470fe..2fbc8575d72d65 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E252_E25.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E252_E25.py.snap @@ -85,4 +85,392 @@ E25.py:46:36: E252 [*] Missing whitespace around parameter equals 48 48 | #: Okay 49 49 | def add(a: int = _default(name='f')): +E25.py:64:18: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A =int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:18: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A= int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:26: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B = str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:33: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C = bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:49: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C= bool, D:object =int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:49: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C= bool, D:object= int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:64: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object =str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:64: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object= str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:80: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object = bool, G: object= bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + +E25.py:64:96: E252 [*] Missing whitespace around parameter equals + | +63 | # There should be at least one E251 diagnostic for each type parameter here: +64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + | ^ E252 +65 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +61 61 | print(f"{foo(a = 1)}") +62 62 | +63 63 | # There should be at least one E251 diagnostic for each type parameter here: +64 |-def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): + 64 |+def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object = bytes](): +65 65 | pass +66 66 | +67 67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: +E25.py:67:18: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A =int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:18: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A= int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:26: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B = str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:33: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C = bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:49: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C= bool, D:object =int, E: object=str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:49: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C= bool, D:object= int, E: object=str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:64: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object =str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:64: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object= str, F: object =bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:80: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object = bool, G: object= bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231, + +E25.py:67:96: E252 [*] Missing whitespace around parameter equals + | +65 | pass +66 | +67 | class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + | ^ E252 +68 | pass + | + = help: Add missing whitespace + +ℹ Safe fix +64 64 | def pep_696_bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes](): +65 65 | pass +66 66 | +67 |-class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object= bytes]: + 67 |+class PEP696Bad[A=int, B =str, C= bool, D:object=int, E: object=str, F: object =bool, G: object = bytes]: +68 68 | pass +69 69 | +70 70 | # The last of these should cause us to emit E231,