Skip to content

Commit

Permalink
[ruff] Do not remove parens for tuples with starred expressions in Py…
Browse files Browse the repository at this point in the history
…thon <=3.10 `RUF031` (#12784)
  • Loading branch information
dylwil3 committed Aug 9, 2024
1 parent 253474b commit b595346
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 3 deletions.
7 changes: 6 additions & 1 deletion crates/ruff_linter/resources/test/fixtures/ruff/RUF031.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@
d[(1,)]
d[()] # empty tuples should be ignored
d[:,] # slices in the subscript lead to syntax error if parens are added
d[1,2,:]
d[1,2,:]

# Should keep these parentheses in
# Python <=3.10 to avoid syntax error.
# https://github.com/astral-sh/ruff/issues/12776
d[(*foo,bar)]
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@
d[()] # empty tuples should be ignored

d[:,] # slices in the subscript lead to syntax error if parens are added
d[1,2,:]
d[1,2,:]

# Should keep these parentheses in
# Python <=3.10 to avoid syntax error.
# https://github.com/astral-sh/ruff/issues/12776
d[(*foo,bar)]
16 changes: 16 additions & 0 deletions crates/ruff_linter/src/rules/ruff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ mod tests {
Ok(())
}

#[test]
fn no_remove_parentheses_starred_expr_py310() -> Result<()> {
let diagnostics = test_path(
Path::new("ruff/RUF031.py"),
&LinterSettings {
ruff: super::settings::Settings {
parenthesize_tuple_in_subscript: false,
},
target_version: PythonVersion::Py310,
..LinterSettings::for_rule(Rule::IncorrectlyParenthesizedTupleInSubscript)
},
)?;
assert_messages!(diagnostics);
Ok(())
}

#[test_case(Path::new("RUF013_0.py"))]
#[test_case(Path::new("RUF013_1.py"))]
fn implicit_optional_py39(path: &Path) -> Result<()> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{Expr, ExprSubscript};
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;
use crate::{checkers::ast::Checker, settings::types::PythonVersion};

/// ## What it does
/// Checks for consistent style regarding whether nonempty tuples in subscripts
Expand Down Expand Up @@ -68,6 +68,16 @@ pub(crate) fn subscript_with_parenthesized_tuple(checker: &mut Checker, subscrip
if prefer_parentheses && tuple_subscript.elts.iter().any(Expr::is_slice_expr) {
return;
}
// Removing parentheses in the presence of unpacking leads
// to a syntax error in Python 3.10.
// This is no longer a syntax error starting in Python 3.11
// see https://peps.python.org/pep-0646/#change-1-star-expressions-in-indexes
if checker.settings.target_version <= PythonVersion::Py310
&& !prefer_parentheses
&& tuple_subscript.elts.iter().any(Expr::is_starred_expr)
{
return;
}
let locator = checker.locator();
let source_range = subscript.slice.range();
let new_source = if prefer_parentheses {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,19 @@ RUF031.py:28:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
29 29 | d[()] # empty tuples should be ignored
30 30 | d[:,] # slices in the subscript lead to syntax error if parens are added
31 31 | d[1,2,:]

RUF031.py:36:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
34 | # Python <=3.10 to avoid syntax error.
35 | # https://github.com/astral-sh/ruff/issues/12776
36 | d[(*foo,bar)]
| ^^^^^^^^^^ RUF031
|
= help: Remove the parentheses.

Safe fix
33 33 | # Should keep these parentheses in
34 34 | # Python <=3.10 to avoid syntax error.
35 35 | # https://github.com/astral-sh/ruff/issues/12776
36 |-d[(*foo,bar)]
36 |+d[*foo,bar]
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
---
RUF031.py:2:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
1 | d = {(1,2):"a",(3,4):"b",(5,6,7):"c",(8,):"d"}
2 | d[(1,2)]
| ^^^^^ RUF031
3 | d[(
4 | 1,
|
= help: Remove the parentheses.

Safe fix
1 1 | d = {(1,2):"a",(3,4):"b",(5,6,7):"c",(8,):"d"}
2 |-d[(1,2)]
2 |+d[1,2]
3 3 | d[(
4 4 | 1,
5 5 | 2

RUF031.py:3:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
1 | d = {(1,2):"a",(3,4):"b",(5,6,7):"c",(8,):"d"}
2 | d[(1,2)]
3 | d[(
| ___^
4 | | 1,
5 | | 2
6 | | )]
| |_^ RUF031
7 | d[
8 | 1,
|
= help: Remove the parentheses.

Safe fix
1 1 | d = {(1,2):"a",(3,4):"b",(5,6,7):"c",(8,):"d"}
2 2 | d[(1,2)]
3 |-d[(
3 |+d[
4 4 | 1,
5 5 | 2
6 |-)]
6 |+]
7 7 | d[
8 8 | 1,
9 9 | 2

RUF031.py:11:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
9 | 2
10 | ]
11 | d[(2,4)]
| ^^^^^ RUF031
12 | d[(5,6,7)]
13 | d[(8,)]
|
= help: Remove the parentheses.

Safe fix
8 8 | 1,
9 9 | 2
10 10 | ]
11 |-d[(2,4)]
11 |+d[2,4]
12 12 | d[(5,6,7)]
13 13 | d[(8,)]
14 14 | d[tuple(1,2)]

RUF031.py:12:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
10 | ]
11 | d[(2,4)]
12 | d[(5,6,7)]
| ^^^^^^^ RUF031
13 | d[(8,)]
14 | d[tuple(1,2)]
|
= help: Remove the parentheses.

Safe fix
9 9 | 2
10 10 | ]
11 11 | d[(2,4)]
12 |-d[(5,6,7)]
12 |+d[5,6,7]
13 13 | d[(8,)]
14 14 | d[tuple(1,2)]
15 15 | d[tuple(8)]

RUF031.py:13:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
11 | d[(2,4)]
12 | d[(5,6,7)]
13 | d[(8,)]
| ^^^^ RUF031
14 | d[tuple(1,2)]
15 | d[tuple(8)]
|
= help: Remove the parentheses.

Safe fix
10 10 | ]
11 11 | d[(2,4)]
12 12 | d[(5,6,7)]
13 |-d[(8,)]
13 |+d[8,]
14 14 | d[tuple(1,2)]
15 15 | d[tuple(8)]
16 16 | d[1,2]

RUF031.py:20:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
18 | d[5,6,7]
19 | e = {((1,2),(3,4)):"a"}
20 | e[((1,2),(3,4))]
| ^^^^^^^^^^^^^ RUF031
21 | e[(1,2),(3,4)]
|
= help: Remove the parentheses.

Safe fix
17 17 | d[3,4]
18 18 | d[5,6,7]
19 19 | e = {((1,2),(3,4)):"a"}
20 |-e[((1,2),(3,4))]
21 20 | e[(1,2),(3,4)]
21 |+e[(1,2),(3,4)]
22 22 |
23 23 | token_features[
24 24 | (window_position, feature_name)

RUF031.py:24:5: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
23 | token_features[
24 | (window_position, feature_name)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF031
25 | ] = self._extract_raw_features_from_token
|
= help: Remove the parentheses.

Safe fix
21 21 | e[(1,2),(3,4)]
22 22 |
23 23 | token_features[
24 |- (window_position, feature_name)
24 |+ window_position, feature_name
25 25 | ] = self._extract_raw_features_from_token
26 26 |
27 27 | d[1,]

RUF031.py:28:3: RUF031 [*] Avoid parentheses for tuples in subscripts.
|
27 | d[1,]
28 | d[(1,)]
| ^^^^ RUF031
29 | d[()] # empty tuples should be ignored
30 | d[:,] # slices in the subscript lead to syntax error if parens are added
|
= help: Remove the parentheses.

Safe fix
25 25 | ] = self._extract_raw_features_from_token
26 26 |
27 27 | d[1,]
28 |-d[(1,)]
28 |+d[1,]
29 29 | d[()] # empty tuples should be ignored
30 30 | d[:,] # slices in the subscript lead to syntax error if parens are added
31 31 | d[1,2,:]

0 comments on commit b595346

Please sign in to comment.