diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/duplicate_literal_member.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/duplicate_literal_member.rs index 4c3a8001dc..c3c1d7225b 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/duplicate_literal_member.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/duplicate_literal_member.rs @@ -2,12 +2,12 @@ use std::collections::HashSet; use rustc_hash::FxHashSet; -use ruff_diagnostics::{Diagnostic, FixAvailability, Violation}; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::comparable::ComparableExpr; -use ruff_python_ast::Expr; +use ruff_python_ast::{self as ast, Expr, ExprContext}; use ruff_python_semantic::analyze::typing::traverse_literal; -use ruff_text_size::Ranged; +use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; @@ -27,6 +27,10 @@ use crate::checkers::ast::Checker; /// foo: Literal["a", "b"] /// ``` /// +/// ## Fix safety +/// This rule's fix is marked as safe; however, the fix will flatten nested +/// literals into a single top-level literal. +/// /// ## References /// - [Python documentation: `typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal) #[violation] @@ -34,24 +38,29 @@ pub struct DuplicateLiteralMember { duplicate_name: String, } -impl Violation for DuplicateLiteralMember { - const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; - +impl AlwaysFixableViolation for DuplicateLiteralMember { #[derive_message_formats] fn message(&self) -> String { format!("Duplicate literal member `{}`", self.duplicate_name) } + + fn fix_title(&self) -> String { + "Remove duplicates".to_string() + } } /// PYI062 pub(crate) fn duplicate_literal_member<'a>(checker: &mut Checker, expr: &'a Expr) { let mut seen_nodes: HashSet, _> = FxHashSet::default(); + let mut unique_nodes: Vec<&Expr> = Vec::new(); let mut diagnostics: Vec = Vec::new(); // Adds a member to `literal_exprs` if it is a `Literal` annotation let mut check_for_duplicate_members = |expr: &'a Expr, _: &'a Expr| { // If we've already seen this literal member, raise a violation. - if !seen_nodes.insert(expr.into()) { + if seen_nodes.insert(expr.into()) { + unique_nodes.push(expr); + } else { diagnostics.push(Diagnostic::new( DuplicateLiteralMember { duplicate_name: checker.generator().expr(expr), @@ -61,7 +70,36 @@ pub(crate) fn duplicate_literal_member<'a>(checker: &mut Checker, expr: &'a Expr } }; - // Traverse the literal, collect all diagnostic members + // Traverse the literal, collect all diagnostic members. traverse_literal(&mut check_for_duplicate_members, checker.semantic(), expr); + + // If there's at least one diagnostic, create a fix to remove the duplicate members. + if !diagnostics.is_empty() { + if let Expr::Subscript(subscript) = expr { + let subscript = Expr::Subscript(ast::ExprSubscript { + slice: Box::new(if let [elt] = unique_nodes.as_slice() { + (*elt).clone() + } else { + Expr::Tuple(ast::ExprTuple { + elts: unique_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::safe_edit(Edit::range_replacement( + checker.generator().expr(&subscript), + expr.range(), + )); + for diagnostic in &mut diagnostics { + diagnostic.set_fix(fix.clone()); + } + } + } + checker.diagnostics.append(&mut diagnostics); } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap index 2ed8215957..c73ae4f46e 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI062.py:5:25: PYI062 Duplicate literal member `True` +PYI062.py:5:25: PYI062 [*] Duplicate literal member `True` | 3 | import typing_extensions 4 | @@ -10,8 +10,19 @@ PYI062.py:5:25: PYI062 Duplicate literal member `True` 6 | 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 | + = help: Remove duplicates -PYI062.py:5:31: PYI062 Duplicate literal member `False` +ℹ Safe fix +2 2 | import typing as t +3 3 | import typing_extensions +4 4 | +5 |-x: Literal[True, False, True, False] # PYI062 twice here + 5 |+x: Literal[True, False] # PYI062 twice here +6 6 | +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 +8 8 | + +PYI062.py:5:31: PYI062 [*] Duplicate literal member `False` | 3 | import typing_extensions 4 | @@ -20,8 +31,19 @@ PYI062.py:5:31: PYI062 Duplicate literal member `False` 6 | 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 | + = help: Remove duplicates -PYI062.py:7:45: PYI062 Duplicate literal member `1` +ℹ Safe fix +2 2 | import typing as t +3 3 | import typing_extensions +4 4 | +5 |-x: Literal[True, False, True, False] # PYI062 twice here + 5 |+x: Literal[True, False] # PYI062 twice here +6 6 | +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 +8 8 | + +PYI062.py:7:45: PYI062 [*] Duplicate literal member `1` | 5 | x: Literal[True, False, True, False] # PYI062 twice here 6 | @@ -30,8 +52,19 @@ PYI062.py:7:45: PYI062 Duplicate literal member `1` 8 | 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal | + = help: Remove duplicates -PYI062.py:9:33: PYI062 Duplicate literal member `{1, 3, 5}` +ℹ Safe fix +4 4 | +5 5 | x: Literal[True, False, True, False] # PYI062 twice here +6 6 | +7 |-y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 + 7 |+y: Literal[1, print("hello"), 3, 4] # PYI062 on the last 1 +8 8 | +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal +10 10 | + +PYI062.py:9:33: PYI062 [*] Duplicate literal member `{1, 3, 5}` | 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 8 | @@ -40,8 +73,19 @@ PYI062.py:9:33: PYI062 Duplicate literal member `{1, 3, 5}` 10 | 11 | Literal[1, Literal[1]] # once | + = help: Remove duplicates -PYI062.py:11:20: PYI062 Duplicate literal member `1` +ℹ Safe fix +6 6 | +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 +8 8 | +9 |-z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal + 9 |+z: Literal[{1, 3, 5}, "foobar"] # PYI062 on the set literal +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice + +PYI062.py:11:20: PYI062 [*] Duplicate literal member `1` | 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal 10 | @@ -50,8 +94,19 @@ PYI062.py:11:20: PYI062 Duplicate literal member `1` 12 | Literal[1, 2, Literal[1, 2]] # twice 13 | Literal[1, Literal[1], Literal[1]] # twice | + = help: Remove duplicates -PYI062.py:12:23: PYI062 Duplicate literal member `1` +ℹ Safe fix +8 8 | +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal +10 10 | +11 |-Literal[1, Literal[1]] # once + 11 |+Literal[1] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once + +PYI062.py:12:23: PYI062 [*] Duplicate literal member `1` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -59,8 +114,19 @@ PYI062.py:12:23: PYI062 Duplicate literal member `1` 13 | Literal[1, Literal[1], Literal[1]] # twice 14 | Literal[1, Literal[2], Literal[2]] # once | + = help: Remove duplicates -PYI062.py:12:26: PYI062 Duplicate literal member `2` +ℹ Safe fix +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 |-Literal[1, 2, Literal[1, 2]] # twice + 12 |+Literal[1, 2] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once + +PYI062.py:12:26: PYI062 [*] Duplicate literal member `2` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -68,8 +134,19 @@ PYI062.py:12:26: PYI062 Duplicate literal member `2` 13 | Literal[1, Literal[1], Literal[1]] # twice 14 | Literal[1, Literal[2], Literal[2]] # once | + = help: Remove duplicates -PYI062.py:13:20: PYI062 Duplicate literal member `1` +ℹ Safe fix +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 |-Literal[1, 2, Literal[1, 2]] # twice + 12 |+Literal[1, 2] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once + +PYI062.py:13:20: PYI062 [*] Duplicate literal member `1` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -78,8 +155,19 @@ PYI062.py:13:20: PYI062 Duplicate literal member `1` 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once | + = help: Remove duplicates -PYI062.py:13:32: PYI062 Duplicate literal member `1` +ℹ Safe fix +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 |-Literal[1, Literal[1], Literal[1]] # twice + 13 |+Literal[1] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice + +PYI062.py:13:32: PYI062 [*] Duplicate literal member `1` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -88,8 +176,19 @@ PYI062.py:13:32: PYI062 Duplicate literal member `1` 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once | + = help: Remove duplicates -PYI062.py:14:32: PYI062 Duplicate literal member `2` +ℹ Safe fix +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 |-Literal[1, Literal[1], Literal[1]] # twice + 13 |+Literal[1] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice + +PYI062.py:14:32: PYI062 [*] Duplicate literal member `2` | 12 | Literal[1, 2, Literal[1, 2]] # twice 13 | Literal[1, Literal[1], Literal[1]] # twice @@ -98,8 +197,19 @@ PYI062.py:14:32: PYI062 Duplicate literal member `2` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 | typing_extensions.Literal[1, 1, 1] # twice | + = help: Remove duplicates -PYI062.py:15:37: PYI062 Duplicate literal member `1` +ℹ Safe fix +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 |-Literal[1, Literal[2], Literal[2]] # once + 14 |+Literal[1, 2] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice +17 17 | + +PYI062.py:15:37: PYI062 [*] Duplicate literal member `1` | 13 | Literal[1, Literal[1], Literal[1]] # twice 14 | Literal[1, Literal[2], Literal[2]] # once @@ -107,8 +217,19 @@ PYI062.py:15:37: PYI062 Duplicate literal member `1` | ^ PYI062 16 | typing_extensions.Literal[1, 1, 1] # twice | + = help: Remove duplicates -PYI062.py:16:30: PYI062 Duplicate literal member `1` +ℹ Safe fix +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 |-t.Literal[1, t.Literal[2, t.Literal[1]]] # once + 15 |+t.Literal[1, 2] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals + +PYI062.py:16:30: PYI062 [*] Duplicate literal member `1` | 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once @@ -117,8 +238,19 @@ PYI062.py:16:30: PYI062 Duplicate literal member `1` 17 | 18 | # Ensure issue is only raised once, even on nested literals | + = help: Remove duplicates -PYI062.py:16:33: PYI062 Duplicate literal member `1` +ℹ Safe fix +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 |-typing_extensions.Literal[1, 1, 1] # twice + 16 |+typing_extensions.Literal[1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals +19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + +PYI062.py:16:33: PYI062 [*] Duplicate literal member `1` | 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once @@ -127,8 +259,19 @@ PYI062.py:16:33: PYI062 Duplicate literal member `1` 17 | 18 | # Ensure issue is only raised once, even on nested literals | + = help: Remove duplicates -PYI062.py:19:46: PYI062 Duplicate literal member `True` +ℹ Safe fix +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 |-typing_extensions.Literal[1, 1, 1] # twice + 16 |+typing_extensions.Literal[1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals +19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + +PYI062.py:19:46: PYI062 [*] Duplicate literal member `True` | 18 | # Ensure issue is only raised once, even on nested literals 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 @@ -136,3 +279,13 @@ PYI062.py:19:46: PYI062 Duplicate literal member `True` 20 | 21 | n: Literal["No", "duplicates", "here", 1, "1"] | + = help: Remove duplicates + +ℹ Safe fix +16 16 | typing_extensions.Literal[1, 1, 1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals +19 |-MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + 19 |+MyType = Literal["foo", True, False, "bar"] # PYI062 +20 20 | +21 21 | n: Literal["No", "duplicates", "here", 1, "1"] diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap index 069024753f..0a96dea0ce 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI062.pyi:5:25: PYI062 Duplicate literal member `True` +PYI062.pyi:5:25: PYI062 [*] Duplicate literal member `True` | 3 | import typing_extensions 4 | @@ -10,8 +10,19 @@ PYI062.pyi:5:25: PYI062 Duplicate literal member `True` 6 | 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 | + = help: Remove duplicates -PYI062.pyi:5:31: PYI062 Duplicate literal member `False` +ℹ Safe fix +2 2 | import typing as t +3 3 | import typing_extensions +4 4 | +5 |-x: Literal[True, False, True, False] # PY062 twice here + 5 |+x: Literal[True, False] # PY062 twice here +6 6 | +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +8 8 | + +PYI062.pyi:5:31: PYI062 [*] Duplicate literal member `False` | 3 | import typing_extensions 4 | @@ -20,8 +31,19 @@ PYI062.pyi:5:31: PYI062 Duplicate literal member `False` 6 | 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 | + = help: Remove duplicates -PYI062.pyi:7:45: PYI062 Duplicate literal member `1` +ℹ Safe fix +2 2 | import typing as t +3 3 | import typing_extensions +4 4 | +5 |-x: Literal[True, False, True, False] # PY062 twice here + 5 |+x: Literal[True, False] # PY062 twice here +6 6 | +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +8 8 | + +PYI062.pyi:7:45: PYI062 [*] Duplicate literal member `1` | 5 | x: Literal[True, False, True, False] # PY062 twice here 6 | @@ -30,8 +52,19 @@ PYI062.pyi:7:45: PYI062 Duplicate literal member `1` 8 | 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal | + = help: Remove duplicates -PYI062.pyi:9:33: PYI062 Duplicate literal member `{1, 3, 5}` +ℹ Safe fix +4 4 | +5 5 | x: Literal[True, False, True, False] # PY062 twice here +6 6 | +7 |-y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 + 7 |+y: Literal[1, print("hello"), 3, 4] # PY062 on the last 1 +8 8 | +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +10 10 | + +PYI062.pyi:9:33: PYI062 [*] Duplicate literal member `{1, 3, 5}` | 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 8 | @@ -40,8 +73,19 @@ PYI062.pyi:9:33: PYI062 Duplicate literal member `{1, 3, 5}` 10 | 11 | Literal[1, Literal[1]] # once | + = help: Remove duplicates -PYI062.pyi:11:20: PYI062 Duplicate literal member `1` +ℹ Safe fix +6 6 | +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +8 8 | +9 |-z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal + 9 |+z: Literal[{1, 3, 5}, "foobar"] # PY062 on the set literal +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice + +PYI062.pyi:11:20: PYI062 [*] Duplicate literal member `1` | 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal 10 | @@ -50,8 +94,19 @@ PYI062.pyi:11:20: PYI062 Duplicate literal member `1` 12 | Literal[1, 2, Literal[1, 2]] # twice 13 | Literal[1, Literal[1], Literal[1]] # twice | + = help: Remove duplicates -PYI062.pyi:12:23: PYI062 Duplicate literal member `1` +ℹ Safe fix +8 8 | +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +10 10 | +11 |-Literal[1, Literal[1]] # once + 11 |+Literal[1] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once + +PYI062.pyi:12:23: PYI062 [*] Duplicate literal member `1` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -59,8 +114,19 @@ PYI062.pyi:12:23: PYI062 Duplicate literal member `1` 13 | Literal[1, Literal[1], Literal[1]] # twice 14 | Literal[1, Literal[2], Literal[2]] # once | + = help: Remove duplicates -PYI062.pyi:12:26: PYI062 Duplicate literal member `2` +ℹ Safe fix +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 |-Literal[1, 2, Literal[1, 2]] # twice + 12 |+Literal[1, 2] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once + +PYI062.pyi:12:26: PYI062 [*] Duplicate literal member `2` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -68,8 +134,19 @@ PYI062.pyi:12:26: PYI062 Duplicate literal member `2` 13 | Literal[1, Literal[1], Literal[1]] # twice 14 | Literal[1, Literal[2], Literal[2]] # once | + = help: Remove duplicates -PYI062.pyi:13:20: PYI062 Duplicate literal member `1` +ℹ Safe fix +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 |-Literal[1, 2, Literal[1, 2]] # twice + 12 |+Literal[1, 2] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once + +PYI062.pyi:13:20: PYI062 [*] Duplicate literal member `1` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -78,8 +155,19 @@ PYI062.pyi:13:20: PYI062 Duplicate literal member `1` 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once | + = help: Remove duplicates -PYI062.pyi:13:32: PYI062 Duplicate literal member `1` +ℹ Safe fix +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 |-Literal[1, Literal[1], Literal[1]] # twice + 13 |+Literal[1] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice + +PYI062.pyi:13:32: PYI062 [*] Duplicate literal member `1` | 11 | Literal[1, Literal[1]] # once 12 | Literal[1, 2, Literal[1, 2]] # twice @@ -88,8 +176,19 @@ PYI062.pyi:13:32: PYI062 Duplicate literal member `1` 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once | + = help: Remove duplicates -PYI062.pyi:14:32: PYI062 Duplicate literal member `2` +ℹ Safe fix +10 10 | +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 |-Literal[1, Literal[1], Literal[1]] # twice + 13 |+Literal[1] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice + +PYI062.pyi:14:32: PYI062 [*] Duplicate literal member `2` | 12 | Literal[1, 2, Literal[1, 2]] # twice 13 | Literal[1, Literal[1], Literal[1]] # twice @@ -98,8 +197,19 @@ PYI062.pyi:14:32: PYI062 Duplicate literal member `2` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 | typing_extensions.Literal[1, 1, 1] # twice | + = help: Remove duplicates -PYI062.pyi:15:37: PYI062 Duplicate literal member `1` +ℹ Safe fix +11 11 | Literal[1, Literal[1]] # once +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 |-Literal[1, Literal[2], Literal[2]] # once + 14 |+Literal[1, 2] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice +17 17 | + +PYI062.pyi:15:37: PYI062 [*] Duplicate literal member `1` | 13 | Literal[1, Literal[1], Literal[1]] # twice 14 | Literal[1, Literal[2], Literal[2]] # once @@ -107,8 +217,19 @@ PYI062.pyi:15:37: PYI062 Duplicate literal member `1` | ^ PYI062 16 | typing_extensions.Literal[1, 1, 1] # twice | + = help: Remove duplicates -PYI062.pyi:16:30: PYI062 Duplicate literal member `1` +ℹ Safe fix +12 12 | Literal[1, 2, Literal[1, 2]] # twice +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 |-t.Literal[1, t.Literal[2, t.Literal[1]]] # once + 15 |+t.Literal[1, 2] # once +16 16 | typing_extensions.Literal[1, 1, 1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals + +PYI062.pyi:16:30: PYI062 [*] Duplicate literal member `1` | 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once @@ -117,8 +238,19 @@ PYI062.pyi:16:30: PYI062 Duplicate literal member `1` 17 | 18 | # Ensure issue is only raised once, even on nested literals | + = help: Remove duplicates -PYI062.pyi:16:33: PYI062 Duplicate literal member `1` +ℹ Safe fix +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 |-typing_extensions.Literal[1, 1, 1] # twice + 16 |+typing_extensions.Literal[1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals +19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + +PYI062.pyi:16:33: PYI062 [*] Duplicate literal member `1` | 14 | Literal[1, Literal[2], Literal[2]] # once 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once @@ -127,8 +259,19 @@ PYI062.pyi:16:33: PYI062 Duplicate literal member `1` 17 | 18 | # Ensure issue is only raised once, even on nested literals | + = help: Remove duplicates -PYI062.pyi:19:46: PYI062 Duplicate literal member `True` +ℹ Safe fix +13 13 | Literal[1, Literal[1], Literal[1]] # twice +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once +16 |-typing_extensions.Literal[1, 1, 1] # twice + 16 |+typing_extensions.Literal[1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals +19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + +PYI062.pyi:19:46: PYI062 [*] Duplicate literal member `True` | 18 | # Ensure issue is only raised once, even on nested literals 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 @@ -136,3 +279,13 @@ PYI062.pyi:19:46: PYI062 Duplicate literal member `True` 20 | 21 | n: Literal["No", "duplicates", "here", 1, "1"] | + = help: Remove duplicates + +ℹ Safe fix +16 16 | typing_extensions.Literal[1, 1, 1] # twice +17 17 | +18 18 | # Ensure issue is only raised once, even on nested literals +19 |-MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + 19 |+MyType = Literal["foo", True, False, "bar"] # PYI062 +20 20 | +21 21 | n: Literal["No", "duplicates", "here", 1, "1"]