[ruff] Implement unnecessary-nested-literal (RUF041) (#14323)

Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Simon Brugman 2024-11-27 11:01:50 +01:00 committed by GitHub
parent 187974eff4
commit 11a2929ed7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 770 additions and 1 deletions

View file

@ -0,0 +1,31 @@
from typing import Literal
import typing as t
import typing_extensions
y: Literal[1, print("hello"), 3, Literal[4, 1]]
Literal[1, Literal[1]]
Literal[1, 2, Literal[1, 2]]
Literal[1, Literal[1], Literal[1]]
Literal[1, Literal[2], Literal[2]]
t.Literal[1, t.Literal[2, t.Literal[1]]]
Literal[
1, # comment 1
Literal[ # another comment
1 # yet annother comment
]
] # once
# Ensure issue is only raised once, even on nested literals
MyType = Literal["foo", Literal[True, False, True], "bar"]
# nested literals, all equivalent to `Literal[1]`
Literal[Literal[1]]
Literal[Literal[Literal[1], Literal[1]]]
Literal[Literal[1], Literal[Literal[Literal[1]]]]
# OK
x: Literal[True, False, True, False]
z: Literal[{1, 3, 5}, "foobar", {1,3,5}]
typing_extensions.Literal[1, 1, 1]
n: Literal["No", "duplicates", "here", 1, "1"]

View file

@ -0,0 +1,31 @@
from typing import Literal
import typing as t
import typing_extensions
y: Literal[1, print("hello"), 3, Literal[4, 1]]
Literal[1, Literal[1]]
Literal[1, 2, Literal[1, 2]]
Literal[1, Literal[1], Literal[1]]
Literal[1, Literal[2], Literal[2]]
t.Literal[1, t.Literal[2, t.Literal[1]]]
Literal[
1, # comment 1
Literal[ # another comment
1 # yet annother comment
]
] # once
# Ensure issue is only raised once, even on nested literals
MyType = Literal["foo", Literal[True, False, True], "bar"]
# nested literals, all equivalent to `Literal[1]`
Literal[Literal[1]]
Literal[Literal[Literal[1], Literal[1]]]
Literal[Literal[1], Literal[Literal[Literal[1]]]]
# OK
x: Literal[True, False, True, False]
z: Literal[{1, 3, 5}, "foobar", {1,3,5}]
typing_extensions.Literal[1, 1, 1]
n: Literal["No", "duplicates", "here", 1, "1"]

View file

@ -108,6 +108,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
Rule::DuplicateLiteralMember,
Rule::RedundantBoolLiteral,
Rule::RedundantNoneLiteral,
Rule::UnnecessaryNestedLiteral,
]) {
if !checker.semantic.in_nested_literal() {
if checker.enabled(Rule::DuplicateLiteralMember) {
@ -119,6 +120,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::RedundantNoneLiteral) {
flake8_pyi::rules::redundant_none_literal(checker, expr);
}
if checker.enabled(Rule::UnnecessaryNestedLiteral) {
ruff::rules::unnecessary_nested_literal(checker, expr);
}
}
}

View file

@ -980,9 +980,10 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "035") => (RuleGroup::Preview, rules::ruff::rules::UnsafeMarkupUse),
(Ruff, "036") => (RuleGroup::Preview, rules::ruff::rules::NoneNotAtEndOfUnion),
(Ruff, "038") => (RuleGroup::Preview, rules::ruff::rules::RedundantBoolLiteral),
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "039") => (RuleGroup::Preview, rules::ruff::rules::UnrawRePattern),
(Ruff, "040") => (RuleGroup::Preview, rules::ruff::rules::InvalidAssertMessageLiteralArgument),
(Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),

View file

@ -67,6 +67,8 @@ mod tests {
#[test_case(Rule::RedundantBoolLiteral, Path::new("RUF038.py"))]
#[test_case(Rule::RedundantBoolLiteral, Path::new("RUF038.pyi"))]
#[test_case(Rule::InvalidAssertMessageLiteralArgument, Path::new("RUF040.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.pyi"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(

View file

@ -32,6 +32,7 @@ pub(crate) use static_key_dict_comprehension::*;
pub(crate) use test_rules::*;
pub(crate) use unnecessary_iterable_allocation_for_first_element::*;
pub(crate) use unnecessary_key_check::*;
pub(crate) use unnecessary_nested_literal::*;
pub(crate) use unraw_re_pattern::*;
pub(crate) use unsafe_markup_use::*;
pub(crate) use unused_async::*;
@ -77,6 +78,7 @@ mod suppression_comment_visitor;
pub(crate) mod test_rules;
mod unnecessary_iterable_allocation_for_first_element;
mod unnecessary_key_check;
mod unnecessary_nested_literal;
mod unraw_re_pattern;
mod unsafe_markup_use;
mod unused_async;

View file

@ -0,0 +1,139 @@
use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::{AnyNodeRef, Expr, ExprContext, ExprSubscript, ExprTuple};
use ruff_python_semantic::analyze::typing::traverse_literal;
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for unnecessary nested `Literal`.
///
/// ## Why is this bad?
/// Prefer using a single `Literal`, which is equivalent and more concise.
///
/// Parameterization of literals by other literals is supported as an ergonomic
/// feature as proposed in [PEP 586], to enable patterns such as:
/// ```python
/// ReadOnlyMode = Literal["r", "r+"]
/// WriteAndTruncateMode = Literal["w", "w+", "wt", "w+t"]
/// WriteNoTruncateMode = Literal["r+", "r+t"]
/// AppendMode = Literal["a", "a+", "at", "a+t"]
///
/// AllModes = Literal[ReadOnlyMode, WriteAndTruncateMode,
/// WriteNoTruncateMode, AppendMode]
/// ```
///
/// As a consequence, type checkers also support nesting of literals
/// which is less readable than a flat `Literal`:
/// ```python
/// AllModes = Literal[Literal["r", "r+"], Literal["w", "w+", "wt", "w+t"],
/// Literal["r+", "r+t"], Literal["a", "a+", "at", "a+t"]]
/// ```
///
/// ## Example
/// ```python
/// AllModes = Literal[
/// Literal["r", "r+"],
/// Literal["w", "w+", "wt", "w+t"],
/// Literal["r+", "r+t"],
/// Literal["a", "a+", "at", "a+t"],
/// ]
/// ```
///
/// Use instead:
/// ```python
/// AllModes = Literal[
/// "r", "r+", "w", "w+", "wt", "w+t", "r+", "r+t", "a", "a+", "at", "a+t"
/// ]
/// ```
///
/// or assign the literal to a variable as in the first example.
///
/// ## Fix safety
/// The fix for this rule is marked as unsafe when the `Literal` slice is split
/// across multiple lines and some of the lines have trailing comments.
///
/// ## References
/// - [Typing documentation: Legal parameters for `Literal` at type check time](https://typing.readthedocs.io/en/latest/spec/literal.html#legal-parameters-for-literal-at-type-check-time)
///
/// [PEP 586](https://peps.python.org/pep-0586/)
#[derive(ViolationMetadata)]
pub(crate) struct UnnecessaryNestedLiteral;
impl Violation for UnnecessaryNestedLiteral {
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
#[derive_message_formats]
fn message(&self) -> String {
"Unnecessary nested `Literal`".to_string()
}
fn fix_title(&self) -> Option<String> {
Some("Replace with flattened `Literal`".to_string())
}
}
/// RUF039
pub(crate) fn unnecessary_nested_literal<'a>(checker: &mut Checker, literal_expr: &'a Expr) {
let mut is_nested = false;
// Traverse the type expressions in the `Literal`.
traverse_literal(
&mut |_: &'a Expr, parent: &'a Expr| {
// If the parent is not equal to the `literal_expr` then we know we are traversing recursively.
if !AnyNodeRef::ptr_eq(parent.into(), literal_expr.into()) {
is_nested = true;
};
},
checker.semantic(),
literal_expr,
);
if !is_nested {
return;
}
// Collect the literal nodes for the fix
let mut nodes: Vec<&Expr> = Vec::new();
traverse_literal(
&mut |expr, _| {
nodes.push(expr);
},
checker.semantic(),
literal_expr,
);
let mut diagnostic = Diagnostic::new(UnnecessaryNestedLiteral, literal_expr.range());
// Create a [`Fix`] that flattens all nodes.
if let Expr::Subscript(subscript) = literal_expr {
let subscript = Expr::Subscript(ExprSubscript {
slice: Box::new(if let [elt] = nodes.as_slice() {
(*elt).clone()
} else {
Expr::Tuple(ExprTuple {
elts: nodes.into_iter().cloned().collect(),
range: TextRange::default(),
ctx: ExprContext::Load,
parenthesized: false,
})
}),
value: subscript.value.clone(),
range: TextRange::default(),
ctx: ExprContext::Load,
});
let fix = Fix::applicable_edit(
Edit::range_replacement(checker.generator().expr(&subscript), literal_expr.range()),
if checker.comment_ranges().intersects(literal_expr.range()) {
Applicability::Unsafe
} else {
Applicability::Safe
},
);
diagnostic.set_fix(fix);
};
checker.diagnostics.push(diagnostic);
}

View file

@ -0,0 +1,279 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
snapshot_kind: text
---
RUF041.py:6:4: RUF041 [*] Unnecessary nested `Literal`
|
6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
7 | Literal[1, Literal[1]]
8 | Literal[1, 2, Literal[1, 2]]
|
= help: Replace with flattened `Literal`
Safe fix
3 3 | import typing_extensions
4 4 |
5 5 |
6 |-y: Literal[1, print("hello"), 3, Literal[4, 1]]
6 |+y: Literal[1, print("hello"), 3, 4, 1]
7 7 | Literal[1, Literal[1]]
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
RUF041.py:7:1: RUF041 [*] Unnecessary nested `Literal`
|
6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 | Literal[1, Literal[1]]
| ^^^^^^^^^^^^^^^^^^^^^^ RUF041
8 | Literal[1, 2, Literal[1, 2]]
9 | Literal[1, Literal[1], Literal[1]]
|
= help: Replace with flattened `Literal`
Safe fix
4 4 |
5 5 |
6 6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 |-Literal[1, Literal[1]]
7 |+Literal[1, 1]
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
RUF041.py:8:1: RUF041 [*] Unnecessary nested `Literal`
|
6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 | Literal[1, Literal[1]]
8 | Literal[1, 2, Literal[1, 2]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
9 | Literal[1, Literal[1], Literal[1]]
10 | Literal[1, Literal[2], Literal[2]]
|
= help: Replace with flattened `Literal`
Safe fix
5 5 |
6 6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 7 | Literal[1, Literal[1]]
8 |-Literal[1, 2, Literal[1, 2]]
8 |+Literal[1, 2, 1, 2]
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
RUF041.py:9:1: RUF041 [*] Unnecessary nested `Literal`
|
7 | Literal[1, Literal[1]]
8 | Literal[1, 2, Literal[1, 2]]
9 | Literal[1, Literal[1], Literal[1]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
10 | Literal[1, Literal[2], Literal[2]]
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
|
= help: Replace with flattened `Literal`
Safe fix
6 6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 7 | Literal[1, Literal[1]]
8 8 | Literal[1, 2, Literal[1, 2]]
9 |-Literal[1, Literal[1], Literal[1]]
9 |+Literal[1, 1, 1]
10 10 | Literal[1, Literal[2], Literal[2]]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 12 | Literal[
RUF041.py:10:1: RUF041 [*] Unnecessary nested `Literal`
|
8 | Literal[1, 2, Literal[1, 2]]
9 | Literal[1, Literal[1], Literal[1]]
10 | Literal[1, Literal[2], Literal[2]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 | Literal[
|
= help: Replace with flattened `Literal`
Safe fix
7 7 | Literal[1, Literal[1]]
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
10 |-Literal[1, Literal[2], Literal[2]]
10 |+Literal[1, 2, 2]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 12 | Literal[
13 13 | 1, # comment 1
RUF041.py:11:1: RUF041 [*] Unnecessary nested `Literal`
|
9 | Literal[1, Literal[1], Literal[1]]
10 | Literal[1, Literal[2], Literal[2]]
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
12 | Literal[
13 | 1, # comment 1
|
= help: Replace with flattened `Literal`
Safe fix
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
11 |-t.Literal[1, t.Literal[2, t.Literal[1]]]
11 |+t.Literal[1, 2, 1]
12 12 | Literal[
13 13 | 1, # comment 1
14 14 | Literal[ # another comment
RUF041.py:12:1: RUF041 [*] Unnecessary nested `Literal`
|
10 | Literal[1, Literal[2], Literal[2]]
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 | / Literal[
13 | | 1, # comment 1
14 | | Literal[ # another comment
15 | | 1 # yet annother comment
16 | | ]
17 | | ] # once
| |_^ RUF041
18 |
19 | # Ensure issue is only raised once, even on nested literals
|
= help: Replace with flattened `Literal`
Unsafe fix
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 |-Literal[
13 |- 1, # comment 1
14 |- Literal[ # another comment
15 |- 1 # yet annother comment
16 |- ]
17 |-] # once
12 |+Literal[1, 1] # once
18 13 |
19 14 | # Ensure issue is only raised once, even on nested literals
20 15 | MyType = Literal["foo", Literal[True, False, True], "bar"]
RUF041.py:20:10: RUF041 [*] Unnecessary nested `Literal`
|
19 | # Ensure issue is only raised once, even on nested literals
20 | MyType = Literal["foo", Literal[True, False, True], "bar"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
21 |
22 | # nested literals, all equivalent to `Literal[1]`
|
= help: Replace with flattened `Literal`
Safe fix
17 17 | ] # once
18 18 |
19 19 | # Ensure issue is only raised once, even on nested literals
20 |-MyType = Literal["foo", Literal[True, False, True], "bar"]
20 |+MyType = Literal["foo", True, False, True, "bar"]
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
RUF041.py:23:1: RUF041 [*] Unnecessary nested `Literal`
|
22 | # nested literals, all equivalent to `Literal[1]`
23 | Literal[Literal[1]]
| ^^^^^^^^^^^^^^^^^^^ RUF041
24 | Literal[Literal[Literal[1], Literal[1]]]
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
|
= help: Replace with flattened `Literal`
Safe fix
20 20 | MyType = Literal["foo", Literal[True, False, True], "bar"]
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 |-Literal[Literal[1]]
23 |+Literal[1]
24 24 | Literal[Literal[Literal[1], Literal[1]]]
25 25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
26 26 |
RUF041.py:24:1: RUF041 [*] Unnecessary nested `Literal`
|
22 | # nested literals, all equivalent to `Literal[1]`
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
|
= help: Replace with flattened `Literal`
Safe fix
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 |-Literal[Literal[Literal[1], Literal[1]]]
24 |+Literal[1, 1]
25 25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
26 26 |
27 27 | # OK
RUF041.py:24:9: RUF041 [*] Unnecessary nested `Literal`
|
22 | # nested literals, all equivalent to `Literal[1]`
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
|
= help: Replace with flattened `Literal`
Safe fix
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 |-Literal[Literal[Literal[1], Literal[1]]]
24 |+Literal[Literal[1, 1]]
25 25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
26 26 |
27 27 | # OK
RUF041.py:25:1: RUF041 [*] Unnecessary nested `Literal`
|
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
26 |
27 | # OK
|
= help: Replace with flattened `Literal`
Safe fix
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 24 | Literal[Literal[Literal[1], Literal[1]]]
25 |-Literal[Literal[1], Literal[Literal[Literal[1]]]]
25 |+Literal[1, 1]
26 26 |
27 27 | # OK
28 28 | x: Literal[True, False, True, False]
RUF041.py:25:29: RUF041 [*] Unnecessary nested `Literal`
|
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
| ^^^^^^^^^^^^^^^^^^^ RUF041
26 |
27 | # OK
|
= help: Replace with flattened `Literal`
Safe fix
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 24 | Literal[Literal[Literal[1], Literal[1]]]
25 |-Literal[Literal[1], Literal[Literal[Literal[1]]]]
25 |+Literal[Literal[1], Literal[Literal[1]]]
26 26 |
27 27 | # OK
28 28 | x: Literal[True, False, True, False]

View file

@ -0,0 +1,279 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
snapshot_kind: text
---
RUF041.pyi:6:4: RUF041 [*] Unnecessary nested `Literal`
|
6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
7 | Literal[1, Literal[1]]
8 | Literal[1, 2, Literal[1, 2]]
|
= help: Replace with flattened `Literal`
Safe fix
3 3 | import typing_extensions
4 4 |
5 5 |
6 |-y: Literal[1, print("hello"), 3, Literal[4, 1]]
6 |+y: Literal[1, print("hello"), 3, 4, 1]
7 7 | Literal[1, Literal[1]]
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
RUF041.pyi:7:1: RUF041 [*] Unnecessary nested `Literal`
|
6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 | Literal[1, Literal[1]]
| ^^^^^^^^^^^^^^^^^^^^^^ RUF041
8 | Literal[1, 2, Literal[1, 2]]
9 | Literal[1, Literal[1], Literal[1]]
|
= help: Replace with flattened `Literal`
Safe fix
4 4 |
5 5 |
6 6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 |-Literal[1, Literal[1]]
7 |+Literal[1, 1]
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
RUF041.pyi:8:1: RUF041 [*] Unnecessary nested `Literal`
|
6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 | Literal[1, Literal[1]]
8 | Literal[1, 2, Literal[1, 2]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
9 | Literal[1, Literal[1], Literal[1]]
10 | Literal[1, Literal[2], Literal[2]]
|
= help: Replace with flattened `Literal`
Safe fix
5 5 |
6 6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 7 | Literal[1, Literal[1]]
8 |-Literal[1, 2, Literal[1, 2]]
8 |+Literal[1, 2, 1, 2]
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
RUF041.pyi:9:1: RUF041 [*] Unnecessary nested `Literal`
|
7 | Literal[1, Literal[1]]
8 | Literal[1, 2, Literal[1, 2]]
9 | Literal[1, Literal[1], Literal[1]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
10 | Literal[1, Literal[2], Literal[2]]
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
|
= help: Replace with flattened `Literal`
Safe fix
6 6 | y: Literal[1, print("hello"), 3, Literal[4, 1]]
7 7 | Literal[1, Literal[1]]
8 8 | Literal[1, 2, Literal[1, 2]]
9 |-Literal[1, Literal[1], Literal[1]]
9 |+Literal[1, 1, 1]
10 10 | Literal[1, Literal[2], Literal[2]]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 12 | Literal[
RUF041.pyi:10:1: RUF041 [*] Unnecessary nested `Literal`
|
8 | Literal[1, 2, Literal[1, 2]]
9 | Literal[1, Literal[1], Literal[1]]
10 | Literal[1, Literal[2], Literal[2]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 | Literal[
|
= help: Replace with flattened `Literal`
Safe fix
7 7 | Literal[1, Literal[1]]
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
10 |-Literal[1, Literal[2], Literal[2]]
10 |+Literal[1, 2, 2]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 12 | Literal[
13 13 | 1, # comment 1
RUF041.pyi:11:1: RUF041 [*] Unnecessary nested `Literal`
|
9 | Literal[1, Literal[1], Literal[1]]
10 | Literal[1, Literal[2], Literal[2]]
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
12 | Literal[
13 | 1, # comment 1
|
= help: Replace with flattened `Literal`
Safe fix
8 8 | Literal[1, 2, Literal[1, 2]]
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
11 |-t.Literal[1, t.Literal[2, t.Literal[1]]]
11 |+t.Literal[1, 2, 1]
12 12 | Literal[
13 13 | 1, # comment 1
14 14 | Literal[ # another comment
RUF041.pyi:12:1: RUF041 [*] Unnecessary nested `Literal`
|
10 | Literal[1, Literal[2], Literal[2]]
11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 | / Literal[
13 | | 1, # comment 1
14 | | Literal[ # another comment
15 | | 1 # yet annother comment
16 | | ]
17 | | ] # once
| |_^ RUF041
18 |
19 | # Ensure issue is only raised once, even on nested literals
|
= help: Replace with flattened `Literal`
Unsafe fix
9 9 | Literal[1, Literal[1], Literal[1]]
10 10 | Literal[1, Literal[2], Literal[2]]
11 11 | t.Literal[1, t.Literal[2, t.Literal[1]]]
12 |-Literal[
13 |- 1, # comment 1
14 |- Literal[ # another comment
15 |- 1 # yet annother comment
16 |- ]
17 |-] # once
12 |+Literal[1, 1] # once
18 13 |
19 14 | # Ensure issue is only raised once, even on nested literals
20 15 | MyType = Literal["foo", Literal[True, False, True], "bar"]
RUF041.pyi:20:10: RUF041 [*] Unnecessary nested `Literal`
|
19 | # Ensure issue is only raised once, even on nested literals
20 | MyType = Literal["foo", Literal[True, False, True], "bar"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
21 |
22 | # nested literals, all equivalent to `Literal[1]`
|
= help: Replace with flattened `Literal`
Safe fix
17 17 | ] # once
18 18 |
19 19 | # Ensure issue is only raised once, even on nested literals
20 |-MyType = Literal["foo", Literal[True, False, True], "bar"]
20 |+MyType = Literal["foo", True, False, True, "bar"]
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
RUF041.pyi:23:1: RUF041 [*] Unnecessary nested `Literal`
|
22 | # nested literals, all equivalent to `Literal[1]`
23 | Literal[Literal[1]]
| ^^^^^^^^^^^^^^^^^^^ RUF041
24 | Literal[Literal[Literal[1], Literal[1]]]
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
|
= help: Replace with flattened `Literal`
Safe fix
20 20 | MyType = Literal["foo", Literal[True, False, True], "bar"]
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 |-Literal[Literal[1]]
23 |+Literal[1]
24 24 | Literal[Literal[Literal[1], Literal[1]]]
25 25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
26 26 |
RUF041.pyi:24:1: RUF041 [*] Unnecessary nested `Literal`
|
22 | # nested literals, all equivalent to `Literal[1]`
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
|
= help: Replace with flattened `Literal`
Safe fix
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 |-Literal[Literal[Literal[1], Literal[1]]]
24 |+Literal[1, 1]
25 25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
26 26 |
27 27 | # OK
RUF041.pyi:24:9: RUF041 [*] Unnecessary nested `Literal`
|
22 | # nested literals, all equivalent to `Literal[1]`
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
|
= help: Replace with flattened `Literal`
Safe fix
21 21 |
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 |-Literal[Literal[Literal[1], Literal[1]]]
24 |+Literal[Literal[1, 1]]
25 25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
26 26 |
27 27 | # OK
RUF041.pyi:25:1: RUF041 [*] Unnecessary nested `Literal`
|
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF041
26 |
27 | # OK
|
= help: Replace with flattened `Literal`
Safe fix
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 24 | Literal[Literal[Literal[1], Literal[1]]]
25 |-Literal[Literal[1], Literal[Literal[Literal[1]]]]
25 |+Literal[1, 1]
26 26 |
27 27 | # OK
28 28 | x: Literal[True, False, True, False]
RUF041.pyi:25:29: RUF041 [*] Unnecessary nested `Literal`
|
23 | Literal[Literal[1]]
24 | Literal[Literal[Literal[1], Literal[1]]]
25 | Literal[Literal[1], Literal[Literal[Literal[1]]]]
| ^^^^^^^^^^^^^^^^^^^ RUF041
26 |
27 | # OK
|
= help: Replace with flattened `Literal`
Safe fix
22 22 | # nested literals, all equivalent to `Literal[1]`
23 23 | Literal[Literal[1]]
24 24 | Literal[Literal[Literal[1], Literal[1]]]
25 |-Literal[Literal[1], Literal[Literal[Literal[1]]]]
25 |+Literal[Literal[1], Literal[Literal[1]]]
26 26 |
27 27 | # OK
28 28 | x: Literal[True, False, True, False]

1
ruff.schema.json generated
View file

@ -3841,6 +3841,7 @@
"RUF039",
"RUF04",
"RUF040",
"RUF041",
"RUF048",
"RUF1",
"RUF10",