mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-22 03:14:41 +00:00
[ruff] Implement incorrectly-parenthesized-tuple-in-subscript
(RUF031
) (#12480)
Implements the new fixable lint rule `RUF031` which checks for the use or omission of parentheses around tuples in subscripts, depending on the setting `lint.ruff.parenthesize-tuple-in-getitem`. By default, the use of parentheses is considered a violation.
This commit is contained in:
parent
d380b37a09
commit
7997da47f5
15 changed files with 552 additions and 3 deletions
|
@ -370,6 +370,7 @@ linter.pylint.max_statements = 50
|
|||
linter.pylint.max_public_methods = 20
|
||||
linter.pylint.max_locals = 15
|
||||
linter.pyupgrade.keep_runtime_typing = false
|
||||
linter.ruff.parenthesize_tuple_in_subscript = false
|
||||
|
||||
# Formatter Settings
|
||||
formatter.exclude = []
|
||||
|
|
28
crates/ruff_linter/resources/test/fixtures/ruff/RUF031.py
vendored
Normal file
28
crates/ruff_linter/resources/test/fixtures/ruff/RUF031.py
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
d = {(1,2):"a",(3,4):"b",(5,6,7):"c",(8,):"d"}
|
||||
d[(1,2)]
|
||||
d[(
|
||||
1,
|
||||
2
|
||||
)]
|
||||
d[
|
||||
1,
|
||||
2
|
||||
]
|
||||
d[(2,4)]
|
||||
d[(5,6,7)]
|
||||
d[(8,)]
|
||||
d[tuple(1,2)]
|
||||
d[tuple(8)]
|
||||
d[1,2]
|
||||
d[3,4]
|
||||
d[5,6,7]
|
||||
e = {((1,2),(3,4)):"a"}
|
||||
e[((1,2),(3,4))]
|
||||
e[(1,2),(3,4)]
|
||||
|
||||
token_features[
|
||||
(window_position, feature_name)
|
||||
] = self._extract_raw_features_from_token
|
||||
|
||||
d[1,]
|
||||
d[(1,)]
|
27
crates/ruff_linter/resources/test/fixtures/ruff/RUF031_prefer_parens.py
vendored
Normal file
27
crates/ruff_linter/resources/test/fixtures/ruff/RUF031_prefer_parens.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
d = {(1,2):"a",(3,4):"b",(5,6,7):"c",(8,):"d"}
|
||||
d[(1,2)]
|
||||
d[(
|
||||
1,
|
||||
2
|
||||
)]
|
||||
d[
|
||||
1,
|
||||
2
|
||||
]
|
||||
d[(2,4)]
|
||||
d[(5,6,7)]
|
||||
d[(8,)]
|
||||
d[tuple(1,2)]
|
||||
d[tuple(8)]
|
||||
d[1,2]
|
||||
d[3,4]
|
||||
d[5,6,7]
|
||||
e = {((1,2),(3,4)):"a"}
|
||||
e[((1,2),(3,4))]
|
||||
e[(1,2),(3,4)]
|
||||
|
||||
token_features[
|
||||
(window_position, feature_name)
|
||||
] = self._extract_raw_features_from_token
|
||||
d[1,]
|
||||
d[(1,)]
|
|
@ -146,6 +146,10 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
refurb::rules::fstring_number_format(checker, subscript);
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::IncorrectlyParenthesizedTupleInSubscript) {
|
||||
ruff::rules::subscript_with_parenthesized_tuple(checker, subscript);
|
||||
}
|
||||
|
||||
pandas_vet::rules::subscript(checker, value, expr);
|
||||
}
|
||||
Expr::Tuple(ast::ExprTuple {
|
||||
|
|
|
@ -957,6 +957,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Ruff, "028") => (RuleGroup::Preview, rules::ruff::rules::InvalidFormatterSuppressionComment),
|
||||
(Ruff, "029") => (RuleGroup::Preview, rules::ruff::rules::UnusedAsync),
|
||||
(Ruff, "030") => (RuleGroup::Preview, rules::ruff::rules::AssertWithPrintMessage),
|
||||
(Ruff, "031") => (RuleGroup::Preview, rules::ruff::rules::IncorrectlyParenthesizedTupleInSubscript),
|
||||
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
||||
(Ruff, "101") => (RuleGroup::Preview, rules::ruff::rules::RedirectedNOQA),
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Ruff-specific rules.
|
||||
|
||||
pub(crate) mod rules;
|
||||
pub mod settings;
|
||||
pub(crate) mod typing;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -19,6 +20,7 @@ mod tests {
|
|||
use crate::settings::types::{
|
||||
CompiledPerFileIgnoreList, PerFileIgnore, PreviewMode, PythonVersion,
|
||||
};
|
||||
use crate::settings::LinterSettings;
|
||||
use crate::test::{test_path, test_resource_path};
|
||||
use crate::{assert_messages, settings};
|
||||
|
||||
|
@ -55,6 +57,7 @@ mod tests {
|
|||
#[test_case(Rule::InvalidFormatterSuppressionComment, Path::new("RUF028.py"))]
|
||||
#[test_case(Rule::UnusedAsync, Path::new("RUF029.py"))]
|
||||
#[test_case(Rule::AssertWithPrintMessage, Path::new("RUF030.py"))]
|
||||
#[test_case(Rule::IncorrectlyParenthesizedTupleInSubscript, Path::new("RUF031.py"))]
|
||||
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
|
@ -66,6 +69,21 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prefer_parentheses_getitem_tuple() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("ruff/RUF031_prefer_parens.py"),
|
||||
&LinterSettings {
|
||||
ruff: super::settings::Settings {
|
||||
parenthesize_tuple_in_subscript: true,
|
||||
},
|
||||
..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<()> {
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::ExprSubscript;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for consistent style regarding whether tuples in subscripts
|
||||
/// are parenthesized.
|
||||
///
|
||||
/// The exact nature of this violation depends on the setting
|
||||
/// [`lint.ruff.parenthesize-tuple-in-subscript`]. By default, the use of
|
||||
/// parentheses is considered a violation.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// It is good to be consistent and, depending on the codebase, one or the other
|
||||
/// convention may be preferred.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```python
|
||||
/// directions = {(0, 1): "North", (-1, 0): "East", (0, -1): "South", (1, 0): "West"}
|
||||
/// directions[(0, 1)]
|
||||
/// ```
|
||||
///
|
||||
/// Use instead (with default setting):
|
||||
///
|
||||
/// ```python
|
||||
/// directions = {(0, 1): "North", (-1, 0): "East", (0, -1): "South", (1, 0): "West"}
|
||||
/// directions[0, 1]
|
||||
/// ```
|
||||
|
||||
#[violation]
|
||||
pub struct IncorrectlyParenthesizedTupleInSubscript {
|
||||
prefer_parentheses: bool,
|
||||
}
|
||||
|
||||
impl AlwaysFixableViolation for IncorrectlyParenthesizedTupleInSubscript {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
if self.prefer_parentheses {
|
||||
format!("Use parentheses for tuples in subscripts.")
|
||||
} else {
|
||||
format!("Avoid parentheses for tuples in subscripts.")
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> String {
|
||||
if self.prefer_parentheses {
|
||||
"Parenthesize the tuple.".to_string()
|
||||
} else {
|
||||
"Remove the parentheses.".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// RUF031
|
||||
pub(crate) fn subscript_with_parenthesized_tuple(checker: &mut Checker, subscript: &ExprSubscript) {
|
||||
let prefer_parentheses = checker.settings.ruff.parenthesize_tuple_in_subscript;
|
||||
let Some(tuple_subscript) = subscript.slice.as_tuple_expr() else {
|
||||
return;
|
||||
};
|
||||
if tuple_subscript.parenthesized == prefer_parentheses {
|
||||
return;
|
||||
}
|
||||
let locator = checker.locator();
|
||||
let source_range = subscript.slice.range();
|
||||
let new_source = if prefer_parentheses {
|
||||
format!("({})", locator.slice(source_range))
|
||||
} else {
|
||||
locator.slice(source_range)[1..source_range.len().to_usize() - 1].to_string()
|
||||
};
|
||||
let edit = Edit::range_replacement(new_source, source_range);
|
||||
checker.diagnostics.push(
|
||||
Diagnostic::new(
|
||||
IncorrectlyParenthesizedTupleInSubscript { prefer_parentheses },
|
||||
source_range,
|
||||
)
|
||||
.with_fix(Fix::safe_edit(edit)),
|
||||
);
|
||||
}
|
|
@ -7,6 +7,7 @@ pub(crate) use default_factory_kwarg::*;
|
|||
pub(crate) use explicit_f_string_type_conversion::*;
|
||||
pub(crate) use function_call_in_dataclass_default::*;
|
||||
pub(crate) use implicit_optional::*;
|
||||
pub(crate) use incorrectly_parenthesized_tuple_in_subscript::*;
|
||||
pub(crate) use invalid_formatter_suppression_comment::*;
|
||||
pub(crate) use invalid_index_type::*;
|
||||
pub(crate) use invalid_pyproject_toml::*;
|
||||
|
@ -41,6 +42,7 @@ mod explicit_f_string_type_conversion;
|
|||
mod function_call_in_dataclass_default;
|
||||
mod helpers;
|
||||
mod implicit_optional;
|
||||
mod incorrectly_parenthesized_tuple_in_subscript;
|
||||
mod invalid_formatter_suppression_comment;
|
||||
mod invalid_index_type;
|
||||
mod invalid_pyproject_toml;
|
||||
|
|
23
crates/ruff_linter/src/rules/ruff/settings.rs
Normal file
23
crates/ruff_linter/src/rules/ruff/settings.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
//! Settings for the `ruff` plugin.
|
||||
|
||||
use crate::display_settings;
|
||||
use ruff_macros::CacheKey;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, CacheKey, Default)]
|
||||
pub struct Settings {
|
||||
pub parenthesize_tuple_in_subscript: bool,
|
||||
}
|
||||
|
||||
impl fmt::Display for Settings {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
display_settings! {
|
||||
formatter = f,
|
||||
namespace = "linter.ruff",
|
||||
fields = [
|
||||
self.parenthesize_tuple_in_subscript
|
||||
]
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
---
|
||||
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
|
||||
|
|
||||
= 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,]
|
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||
---
|
||||
RUF031_prefer_parens.py:8:5: RUF031 [*] Use parentheses for tuples in subscripts.
|
||||
|
|
||||
6 | )]
|
||||
7 | d[
|
||||
8 | 1,
|
||||
| _____^
|
||||
9 | | 2
|
||||
| |_____^ RUF031
|
||||
10 | ]
|
||||
11 | d[(2,4)]
|
||||
|
|
||||
= help: Parenthesize the tuple.
|
||||
|
||||
ℹ Safe fix
|
||||
5 5 | 2
|
||||
6 6 | )]
|
||||
7 7 | d[
|
||||
8 |- 1,
|
||||
9 |- 2
|
||||
8 |+ (1,
|
||||
9 |+ 2)
|
||||
10 10 | ]
|
||||
11 11 | d[(2,4)]
|
||||
12 12 | d[(5,6,7)]
|
||||
|
||||
RUF031_prefer_parens.py:16:3: RUF031 [*] Use parentheses for tuples in subscripts.
|
||||
|
|
||||
14 | d[tuple(1,2)]
|
||||
15 | d[tuple(8)]
|
||||
16 | d[1,2]
|
||||
| ^^^ RUF031
|
||||
17 | d[3,4]
|
||||
18 | d[5,6,7]
|
||||
|
|
||||
= help: Parenthesize the tuple.
|
||||
|
||||
ℹ Safe fix
|
||||
13 13 | d[(8,)]
|
||||
14 14 | d[tuple(1,2)]
|
||||
15 15 | d[tuple(8)]
|
||||
16 |-d[1,2]
|
||||
16 |+d[(1,2)]
|
||||
17 17 | d[3,4]
|
||||
18 18 | d[5,6,7]
|
||||
19 19 | e = {((1,2),(3,4)):"a"}
|
||||
|
||||
RUF031_prefer_parens.py:17:3: RUF031 [*] Use parentheses for tuples in subscripts.
|
||||
|
|
||||
15 | d[tuple(8)]
|
||||
16 | d[1,2]
|
||||
17 | d[3,4]
|
||||
| ^^^ RUF031
|
||||
18 | d[5,6,7]
|
||||
19 | e = {((1,2),(3,4)):"a"}
|
||||
|
|
||||
= help: Parenthesize the tuple.
|
||||
|
||||
ℹ Safe fix
|
||||
14 14 | d[tuple(1,2)]
|
||||
15 15 | d[tuple(8)]
|
||||
16 16 | d[1,2]
|
||||
17 |-d[3,4]
|
||||
17 |+d[(3,4)]
|
||||
18 18 | d[5,6,7]
|
||||
19 19 | e = {((1,2),(3,4)):"a"}
|
||||
20 20 | e[((1,2),(3,4))]
|
||||
|
||||
RUF031_prefer_parens.py:18:3: RUF031 [*] Use parentheses for tuples in subscripts.
|
||||
|
|
||||
16 | d[1,2]
|
||||
17 | d[3,4]
|
||||
18 | d[5,6,7]
|
||||
| ^^^^^ RUF031
|
||||
19 | e = {((1,2),(3,4)):"a"}
|
||||
20 | e[((1,2),(3,4))]
|
||||
|
|
||||
= help: Parenthesize the tuple.
|
||||
|
||||
ℹ Safe fix
|
||||
15 15 | d[tuple(8)]
|
||||
16 16 | d[1,2]
|
||||
17 17 | d[3,4]
|
||||
18 |-d[5,6,7]
|
||||
18 |+d[(5,6,7)]
|
||||
19 19 | e = {((1,2),(3,4)):"a"}
|
||||
20 20 | e[((1,2),(3,4))]
|
||||
21 21 | e[(1,2),(3,4)]
|
||||
|
||||
RUF031_prefer_parens.py:21:3: RUF031 [*] Use parentheses for tuples in subscripts.
|
||||
|
|
||||
19 | e = {((1,2),(3,4)):"a"}
|
||||
20 | e[((1,2),(3,4))]
|
||||
21 | e[(1,2),(3,4)]
|
||||
| ^^^^^^^^^^^ RUF031
|
||||
22 |
|
||||
23 | token_features[
|
||||
|
|
||||
= help: Parenthesize the tuple.
|
||||
|
||||
ℹ Safe fix
|
||||
18 18 | d[5,6,7]
|
||||
19 19 | e = {((1,2),(3,4)):"a"}
|
||||
20 20 | e[((1,2),(3,4))]
|
||||
21 |-e[(1,2),(3,4)]
|
||||
21 |+e[((1,2),(3,4))]
|
||||
22 22 |
|
||||
23 23 | token_features[
|
||||
24 24 | (window_position, feature_name)
|
||||
|
||||
RUF031_prefer_parens.py:26:3: RUF031 [*] Use parentheses for tuples in subscripts.
|
||||
|
|
||||
24 | (window_position, feature_name)
|
||||
25 | ] = self._extract_raw_features_from_token
|
||||
26 | d[1,]
|
||||
| ^^ RUF031
|
||||
27 | d[(1,)]
|
||||
|
|
||||
= help: Parenthesize the tuple.
|
||||
|
||||
ℹ Safe fix
|
||||
23 23 | token_features[
|
||||
24 24 | (window_position, feature_name)
|
||||
25 25 | ] = self._extract_raw_features_from_token
|
||||
26 |-d[1,]
|
||||
27 26 | d[(1,)]
|
||||
27 |+d[(1,)]
|
|
@ -20,7 +20,7 @@ use crate::rules::{
|
|||
flake8_comprehensions, flake8_copyright, flake8_errmsg, flake8_gettext,
|
||||
flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes,
|
||||
flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe,
|
||||
pep8_naming, pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade,
|
||||
pep8_naming, pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade, ruff,
|
||||
};
|
||||
use crate::settings::types::{
|
||||
CompiledPerFileIgnoreList, ExtensionMapping, FilePatternSet, PythonVersion,
|
||||
|
@ -265,6 +265,7 @@ pub struct LinterSettings {
|
|||
pub pyflakes: pyflakes::settings::Settings,
|
||||
pub pylint: pylint::settings::Settings,
|
||||
pub pyupgrade: pyupgrade::settings::Settings,
|
||||
pub ruff: ruff::settings::Settings,
|
||||
}
|
||||
|
||||
impl Display for LinterSettings {
|
||||
|
@ -328,6 +329,7 @@ impl Display for LinterSettings {
|
|||
self.pyflakes | nested,
|
||||
self.pylint | nested,
|
||||
self.pyupgrade | nested,
|
||||
self.ruff | nested,
|
||||
]
|
||||
}
|
||||
Ok(())
|
||||
|
@ -428,6 +430,7 @@ impl LinterSettings {
|
|||
pyflakes: pyflakes::settings::Settings::default(),
|
||||
pylint: pylint::settings::Settings::default(),
|
||||
pyupgrade: pyupgrade::settings::Settings::default(),
|
||||
ruff: ruff::settings::Settings::default(),
|
||||
preview: PreviewMode::default(),
|
||||
explicit_preview_rules: false,
|
||||
extension: ExtensionMapping::default(),
|
||||
|
|
|
@ -47,7 +47,7 @@ use crate::options::{
|
|||
Flake8SelfOptions, Flake8TidyImportsOptions, Flake8TypeCheckingOptions,
|
||||
Flake8UnusedArgumentsOptions, FormatOptions, IsortOptions, LintCommonOptions, LintOptions,
|
||||
McCabeOptions, Options, Pep8NamingOptions, PyUpgradeOptions, PycodestyleOptions,
|
||||
PydocstyleOptions, PyflakesOptions, PylintOptions,
|
||||
PydocstyleOptions, PyflakesOptions, PylintOptions, RuffOptions,
|
||||
};
|
||||
use crate::settings::{
|
||||
FileResolverSettings, FormatterSettings, LineEnding, Settings, EXCLUDE, INCLUDE,
|
||||
|
@ -402,6 +402,10 @@ impl Configuration {
|
|||
.pyupgrade
|
||||
.map(PyUpgradeOptions::into_settings)
|
||||
.unwrap_or_default(),
|
||||
ruff: lint
|
||||
.ruff
|
||||
.map(RuffOptions::into_settings)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
|
||||
formatter,
|
||||
|
@ -631,6 +635,7 @@ pub struct LintConfiguration {
|
|||
pub pyflakes: Option<PyflakesOptions>,
|
||||
pub pylint: Option<PylintOptions>,
|
||||
pub pyupgrade: Option<PyUpgradeOptions>,
|
||||
pub ruff: Option<RuffOptions>,
|
||||
}
|
||||
|
||||
impl LintConfiguration {
|
||||
|
@ -741,6 +746,7 @@ impl LintConfiguration {
|
|||
pyflakes: options.common.pyflakes,
|
||||
pylint: options.common.pylint,
|
||||
pyupgrade: options.common.pyupgrade,
|
||||
ruff: options.ruff,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1118,6 +1124,7 @@ impl LintConfiguration {
|
|||
pyflakes: self.pyflakes.combine(config.pyflakes),
|
||||
pylint: self.pylint.combine(config.pylint),
|
||||
pyupgrade: self.pyupgrade.combine(config.pyupgrade),
|
||||
ruff: self.ruff.combine(config.ruff),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use ruff_linter::rules::{
|
|||
flake8_copyright, flake8_errmsg, flake8_gettext, flake8_implicit_str_concat,
|
||||
flake8_import_conventions, flake8_pytest_style, flake8_quotes, flake8_self,
|
||||
flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming,
|
||||
pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade,
|
||||
pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade, ruff,
|
||||
};
|
||||
use ruff_linter::settings::types::{
|
||||
IdentifierPattern, OutputFormat, PreviewMode, PythonVersion, RequiredVersion,
|
||||
|
@ -455,6 +455,10 @@ pub struct LintOptions {
|
|||
)]
|
||||
pub exclude: Option<Vec<String>>,
|
||||
|
||||
/// Options for the `ruff` plugin
|
||||
#[option_group]
|
||||
pub ruff: Option<RuffOptions>,
|
||||
|
||||
/// Whether to enable preview mode. When preview mode is enabled, Ruff will
|
||||
/// use unstable rules and fixes.
|
||||
#[option(
|
||||
|
@ -2969,6 +2973,35 @@ impl PyUpgradeOptions {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, OptionsMetadata, CombineOptions,
|
||||
)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct RuffOptions {
|
||||
/// Whether to prefer accessing items keyed by tuples with
|
||||
/// parentheses around the tuple (see `RUF031`).
|
||||
#[option(
|
||||
default = r#"false"#,
|
||||
value_type = "bool",
|
||||
example = r#"
|
||||
# Make it a violation to use a tuple in a subscript without parentheses.
|
||||
parenthesize-tuple-in-subscript = true
|
||||
"#
|
||||
)]
|
||||
pub parenthesize_tuple_in_subscript: Option<bool>,
|
||||
}
|
||||
|
||||
impl RuffOptions {
|
||||
pub fn into_settings(self) -> ruff::settings::Settings {
|
||||
ruff::settings::Settings {
|
||||
parenthesize_tuple_in_subscript: self
|
||||
.parenthesize_tuple_in_subscript
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configures the way Ruff formats your code.
|
||||
#[derive(
|
||||
Clone, Debug, PartialEq, Eq, Default, Deserialize, Serialize, OptionsMetadata, CombineOptions,
|
||||
|
|
25
ruff.schema.json
generated
25
ruff.schema.json
generated
|
@ -2245,6 +2245,17 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"ruff": {
|
||||
"description": "Options for the `ruff` plugin",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RuffOptions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"select": {
|
||||
"description": "A list of rule codes or prefixes to enable. Prefixes can specify exact rules (like `F841`), entire categories (like `F`), or anything in between.\n\nWhen breaking ties between enabled and disabled rules (via `select` and `ignore`, respectively), more specific prefixes override less specific prefixes.",
|
||||
"type": [
|
||||
|
@ -2670,6 +2681,19 @@
|
|||
"RequiredVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"RuffOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"parenthesize-tuple-in-subscript": {
|
||||
"description": "Whether to prefer accessing items keyed by tuples with parentheses around the tuple (see `RUF031`).",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RuleSelector": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -3711,6 +3735,7 @@
|
|||
"RUF029",
|
||||
"RUF03",
|
||||
"RUF030",
|
||||
"RUF031",
|
||||
"RUF1",
|
||||
"RUF10",
|
||||
"RUF100",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue