Skip to content

Commit d9ac170

Browse files
Fix E231 bug: Inconsistent catch compared to pycodestyle, such as when dict nested in list (#10469)
<!-- Thank you for contributing to Ruff! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary Fix `E231` bug: Inconsistent catch compared to pycodestyle, such as when dict nested in list. Resolves #10113. ## Test Plan Example from #10113 added to test fixture.
1 parent c5ea420 commit d9ac170

File tree

3 files changed

+401
-11
lines changed

3 files changed

+401
-11
lines changed

crates/ruff_linter/resources/test/fixtures/pycodestyle/E23.py

+57-1
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,60 @@ def foo() -> None:
4747
{len(f's3://{self.s3_bucket_name}/'):1}
4848

4949
#: Okay
50-
a = (1,
50+
a = (1,)
51+
52+
53+
# https://github.com/astral-sh/ruff/issues/10113
54+
"""Minimal repo."""
55+
56+
def main() -> None:
57+
"""Primary function."""
58+
results = {
59+
"k1": [1],
60+
"k2":[2],
61+
}
62+
results_in_tuple = (
63+
{
64+
"k1": [1],
65+
"k2":[2],
66+
},
67+
)
68+
results_in_list = [
69+
{
70+
"k1": [1],
71+
"k2":[2],
72+
}
73+
]
74+
results_in_list_first = [
75+
{
76+
"k2":[2],
77+
}
78+
]
79+
80+
x = [
81+
{
82+
"k1":[2], # E231
83+
"k2": [2:4],
84+
"k3":[2], # E231
85+
"k4": [2],
86+
"k5": [2],
87+
"k6": [1, 2, 3, 4,5,6,7] # E231
88+
},
89+
{
90+
"k1": [
91+
{
92+
"ka":[2,3], # E231
93+
},
94+
{
95+
"kb": [2,3], # E231
96+
},
97+
{
98+
"ka":[2, 3], # E231
99+
"kb": [2, 3], # Ok
100+
"kc": [2, 3], # Ok
101+
"kd": [2,3], # E231
102+
"ke":[2,3], # E231
103+
},
104+
]
105+
}
106+
]

crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use ruff_diagnostics::Edit;
22
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
33
use ruff_macros::{derive_message_formats, violation};
44
use ruff_python_parser::TokenKind;
5-
use ruff_text_size::{Ranged, TextSize};
5+
use ruff_text_size::Ranged;
66

77
use crate::checkers::logical_lines::LogicalLinesContext;
88

@@ -53,10 +53,8 @@ impl AlwaysFixableViolation for MissingWhitespace {
5353

5454
/// E231
5555
pub(crate) fn missing_whitespace(line: &LogicalLine, context: &mut LogicalLinesContext) {
56-
let mut open_parentheses = 0u32;
5756
let mut fstrings = 0u32;
58-
let mut prev_lsqb = TextSize::default();
59-
let mut prev_lbrace = TextSize::default();
57+
let mut brackets = Vec::new();
6058
let mut iter = line.tokens().iter().peekable();
6159

6260
while let Some(token) = iter.next() {
@@ -65,14 +63,16 @@ pub(crate) fn missing_whitespace(line: &LogicalLine, context: &mut LogicalLinesC
6563
TokenKind::FStringStart => fstrings += 1,
6664
TokenKind::FStringEnd => fstrings = fstrings.saturating_sub(1),
6765
TokenKind::Lsqb if fstrings == 0 => {
68-
open_parentheses = open_parentheses.saturating_add(1);
69-
prev_lsqb = token.start();
66+
brackets.push(kind);
7067
}
7168
TokenKind::Rsqb if fstrings == 0 => {
72-
open_parentheses = open_parentheses.saturating_sub(1);
69+
brackets.pop();
7370
}
7471
TokenKind::Lbrace if fstrings == 0 => {
75-
prev_lbrace = token.start();
72+
brackets.push(kind);
73+
}
74+
TokenKind::Rbrace if fstrings == 0 => {
75+
brackets.pop();
7676
}
7777
TokenKind::Colon if fstrings > 0 => {
7878
// Colon in f-string, no space required. This will yield false
@@ -97,7 +97,7 @@ pub(crate) fn missing_whitespace(line: &LogicalLine, context: &mut LogicalLinesC
9797
if let Some(next_token) = iter.peek() {
9898
match (kind, next_token.kind()) {
9999
(TokenKind::Colon, _)
100-
if open_parentheses > 0 && prev_lsqb > prev_lbrace =>
100+
if matches!(brackets.last(), Some(TokenKind::Lsqb)) =>
101101
{
102102
continue; // Slice syntax, no space required
103103
}

0 commit comments

Comments
 (0)