From d22ffd5e259f0487aba57b391939f499a42029fe Mon Sep 17 00:00:00 2001 From: Steve C Date: Fri, 15 Nov 2024 18:46:09 -0500 Subject: [PATCH] [`pylint`] - use sets when possible for PLR1714 autofix --- .../pylint/repeated_equality_comparison.py | 8 + .../rules/repeated_equality_comparison.rs | 46 ++++-- ...R1714_repeated_equality_comparison.py.snap | 152 +++++++++++++----- 3 files changed, 156 insertions(+), 50 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/repeated_equality_comparison.py b/crates/ruff_linter/resources/test/fixtures/pylint/repeated_equality_comparison.py index 862065c5f183c..605d2092631b1 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/repeated_equality_comparison.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/repeated_equality_comparison.py @@ -65,3 +65,11 @@ foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets + +foo == 1 or foo == True # Different types, same hashed value, Tuple expected + +foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected + +foo == False or foo == 0 # Different types, same hashed value, Tuple expected + +foo == 0.0 or foo == 0j # Different types, same hashed value, Tuple expected diff --git a/crates/ruff_linter/src/rules/pylint/rules/repeated_equality_comparison.rs b/crates/ruff_linter/src/rules/pylint/rules/repeated_equality_comparison.rs index 735ca8f28b94b..57b15b59ef791 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/repeated_equality_comparison.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/repeated_equality_comparison.rs @@ -1,10 +1,10 @@ use itertools::Itertools; -use rustc_hash::{FxBuildHasher, FxHashMap}; +use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; use ast::ExprContext; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::comparable::ComparableExpr; +use ruff_python_ast::comparable::{ComparableExpr, HashableExpr}; use ruff_python_ast::helpers::{any_over_expr, contains_effect}; use ruff_python_ast::{self as ast, BoolOp, CmpOp, Expr}; use ruff_python_semantic::SemanticModel; @@ -51,12 +51,9 @@ impl AlwaysFixableViolation for RepeatedEqualityComparison { #[derive_message_formats] fn message(&self) -> String { if let Some(expression) = self.expression.full_display() { - format!( - "Consider merging multiple comparisons: `{expression}`. Use a `set` if the elements are hashable." - ) + format!("Consider merging multiple comparisons: `{expression}`.") } else { - "Consider merging multiple comparisons. Use a `set` if the elements are hashable." - .to_string() + "Consider merging multiple comparisons.".to_string() } } @@ -121,6 +118,12 @@ pub(crate) fn repeated_equality_comparison(checker: &mut Checker, bool_op: &ast: continue; } + let mut seen_values = + FxHashSet::with_capacity_and_hasher(comparators.len(), FxBuildHasher); + let use_set = comparators + .iter() + .all(|comparator| seen_values.insert(HashableExpr::from(*comparator))); + let mut diagnostic = Diagnostic::new( RepeatedEqualityComparison { expression: SourceCodeSnippet::new(merged_membership_test( @@ -128,6 +131,7 @@ pub(crate) fn repeated_equality_comparison(checker: &mut Checker, bool_op: &ast: bool_op.op, &comparators, checker.locator(), + use_set, )), }, bool_op.range(), @@ -140,6 +144,20 @@ pub(crate) fn repeated_equality_comparison(checker: &mut Checker, bool_op: &ast: let before = bool_op.values.iter().take(*first).cloned(); let after = bool_op.values.iter().skip(last + 1).cloned(); + let comparator = if use_set { + Expr::Set(ast::ExprSet { + elts: comparators.iter().copied().cloned().collect(), + range: TextRange::default(), + }) + } else { + Expr::Tuple(ast::ExprTuple { + elts: comparators.iter().copied().cloned().collect(), + range: TextRange::default(), + ctx: ExprContext::Load, + parenthesized: true, + }) + }; + diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( checker.generator().expr(&Expr::BoolOp(ast::ExprBoolOp { op: bool_op.op, @@ -150,12 +168,7 @@ pub(crate) fn repeated_equality_comparison(checker: &mut Checker, bool_op: &ast: BoolOp::Or => Box::from([CmpOp::In]), BoolOp::And => Box::from([CmpOp::NotIn]), }, - comparators: Box::from([Expr::Tuple(ast::ExprTuple { - elts: comparators.iter().copied().cloned().collect(), - range: TextRange::default(), - ctx: ExprContext::Load, - parenthesized: true, - })]), + comparators: Box::from([comparator]), range: bool_op.range(), }))) .chain(after) @@ -231,11 +244,13 @@ fn to_allowed_value<'a>( } /// Generate a string like `obj in (a, b, c)` or `obj not in (a, b, c)`. +/// If `use_set` is `true`, the string will use a set instead of a tuple. fn merged_membership_test( left: &Expr, op: BoolOp, comparators: &[&Expr], locator: &Locator, + use_set: bool, ) -> String { let op = match op { BoolOp::Or => "in", @@ -246,5 +261,10 @@ fn merged_membership_test( .iter() .map(|comparator| locator.slice(comparator)) .join(", "); + + if use_set { + return format!("{left} {op} {{{members}}}",); + } + format!("{left} {op} ({members})",) } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1714_repeated_equality_comparison.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1714_repeated_equality_comparison.py.snap index 06f948e4df7f4..daf7b2433fbce 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1714_repeated_equality_comparison.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1714_repeated_equality_comparison.py.snap @@ -1,8 +1,7 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs -snapshot_kind: text --- -repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`. | 1 | # Errors. 2 | foo == "a" or foo == "b" @@ -15,12 +14,12 @@ repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple compa ℹ Unsafe fix 1 1 | # Errors. 2 |-foo == "a" or foo == "b" - 2 |+foo in ("a", "b") + 2 |+foo in {"a", "b"} 3 3 | 4 4 | foo != "a" and foo != "b" 5 5 | -repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b"}`. | 2 | foo == "a" or foo == "b" 3 | @@ -36,12 +35,12 @@ repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple compa 2 2 | foo == "a" or foo == "b" 3 3 | 4 |-foo != "a" and foo != "b" - 4 |+foo not in ("a", "b") + 4 |+foo not in {"a", "b"} 5 5 | 6 6 | foo == "a" or foo == "b" or foo == "c" 7 7 | -repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`. | 4 | foo != "a" and foo != "b" 5 | @@ -57,12 +56,12 @@ repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple compa 4 4 | foo != "a" and foo != "b" 5 5 | 6 |-foo == "a" or foo == "b" or foo == "c" - 6 |+foo in ("a", "b", "c") + 6 |+foo in {"a", "b", "c"} 7 7 | 8 8 | foo != "a" and foo != "b" and foo != "c" 9 9 | -repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`. | 6 | foo == "a" or foo == "b" or foo == "c" 7 | @@ -78,12 +77,12 @@ repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple compa 6 6 | foo == "a" or foo == "b" or foo == "c" 7 7 | 8 |-foo != "a" and foo != "b" and foo != "c" - 8 |+foo not in ("a", "b", "c") + 8 |+foo not in {"a", "b", "c"} 9 9 | 10 10 | foo == a or foo == "b" or foo == 3 # Mixed types. 11 11 | -repeated_equality_comparison.py:10:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (a, "b", 3)`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:10:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {a, "b", 3}`. | 8 | foo != "a" and foo != "b" and foo != "c" 9 | @@ -99,12 +98,12 @@ repeated_equality_comparison.py:10:1: PLR1714 [*] Consider merging multiple comp 8 8 | foo != "a" and foo != "b" and foo != "c" 9 9 | 10 |-foo == a or foo == "b" or foo == 3 # Mixed types. - 10 |+foo in (a, "b", 3) # Mixed types. + 10 |+foo in {a, "b", 3} # Mixed types. 11 11 | 12 12 | "a" == foo or "b" == foo or "c" == foo 13 13 | -repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`. | 10 | foo == a or foo == "b" or foo == 3 # Mixed types. 11 | @@ -120,12 +119,12 @@ repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comp 10 10 | foo == a or foo == "b" or foo == 3 # Mixed types. 11 11 | 12 |-"a" == foo or "b" == foo or "c" == foo - 12 |+foo in ("a", "b", "c") + 12 |+foo in {"a", "b", "c"} 13 13 | 14 14 | "a" != foo and "b" != foo and "c" != foo 15 15 | -repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`. | 12 | "a" == foo or "b" == foo or "c" == foo 13 | @@ -141,12 +140,12 @@ repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comp 12 12 | "a" == foo or "b" == foo or "c" == foo 13 13 | 14 |-"a" != foo and "b" != foo and "c" != foo - 14 |+foo not in ("a", "b", "c") + 14 |+foo not in {"a", "b", "c"} 15 15 | 16 16 | "a" == foo or foo == "b" or "c" == foo 17 17 | -repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`. | 14 | "a" != foo and "b" != foo and "c" != foo 15 | @@ -162,12 +161,12 @@ repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comp 14 14 | "a" != foo and "b" != foo and "c" != foo 15 15 | 16 |-"a" == foo or foo == "b" or "c" == foo - 16 |+foo in ("a", "b", "c") + 16 |+foo in {"a", "b", "c"} 17 17 | 18 18 | foo == bar or baz == foo or qux == foo 19 19 | -repeated_equality_comparison.py:18:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (bar, baz, qux)`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:18:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {bar, baz, qux}`. | 16 | "a" == foo or foo == "b" or "c" == foo 17 | @@ -183,12 +182,12 @@ repeated_equality_comparison.py:18:1: PLR1714 [*] Consider merging multiple comp 16 16 | "a" == foo or foo == "b" or "c" == foo 17 17 | 18 |-foo == bar or baz == foo or qux == foo - 18 |+foo in (bar, baz, qux) + 18 |+foo in {bar, baz, qux} 19 19 | 20 20 | foo == "a" or "b" == foo or foo == "c" 21 21 | -repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`. | 18 | foo == bar or baz == foo or qux == foo 19 | @@ -204,12 +203,12 @@ repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comp 18 18 | foo == bar or baz == foo or qux == foo 19 19 | 20 |-foo == "a" or "b" == foo or foo == "c" - 20 |+foo in ("a", "b", "c") + 20 |+foo in {"a", "b", "c"} 21 21 | 22 22 | foo != "a" and "b" != foo and foo != "c" 23 23 | -repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b", "c")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`. | 20 | foo == "a" or "b" == foo or foo == "c" 21 | @@ -225,12 +224,12 @@ repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comp 20 20 | foo == "a" or "b" == foo or foo == "c" 21 21 | 22 |-foo != "a" and "b" != foo and foo != "c" - 22 |+foo not in ("a", "b", "c") + 22 |+foo not in {"a", "b", "c"} 23 23 | 24 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets 25 25 | -repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`. | 22 | foo != "a" and "b" != foo and foo != "c" 23 | @@ -246,12 +245,12 @@ repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comp 22 22 | foo != "a" and "b" != foo and foo != "c" 23 23 | 24 |-foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets - 24 |+foo in ("a", "b") or "c" == bar or "d" == bar # Multiple targets + 24 |+foo in {"a", "b"} or "c" == bar or "d" == bar # Multiple targets 25 25 | 26 26 | foo.bar == "a" or foo.bar == "b" # Attributes. 27 27 | -repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `bar in ("c", "d")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `bar in {"c", "d"}`. | 22 | foo != "a" and "b" != foo and foo != "c" 23 | @@ -267,12 +266,12 @@ repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comp 22 22 | foo != "a" and "b" != foo and foo != "c" 23 23 | 24 |-foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets - 24 |+foo == "a" or foo == "b" or bar in ("c", "d") # Multiple targets + 24 |+foo == "a" or foo == "b" or bar in {"c", "d"} # Multiple targets 25 25 | 26 26 | foo.bar == "a" or foo.bar == "b" # Attributes. 27 27 | -repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comparisons: `foo.bar in ("a", "b")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comparisons: `foo.bar in {"a", "b"}`. | 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets 25 | @@ -288,12 +287,12 @@ repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comp 24 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets 25 25 | 26 |-foo.bar == "a" or foo.bar == "b" # Attributes. - 26 |+foo.bar in ("a", "b") # Attributes. + 26 |+foo.bar in {"a", "b"} # Attributes. 27 27 | 28 28 | # OK 29 29 | foo == "a" and foo == "b" and foo == "c" # `and` mixed with `==`. -repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple comparisons: `bar in ("c", "d")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple comparisons: `bar in {"c", "d"}`. | 59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets 60 | @@ -309,12 +308,12 @@ repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple com 59 59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets 60 60 | 61 |-foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets - 61 |+foo == "a" or (bar in ("c", "d")) or foo == "b" # Multiple targets + 61 |+foo == "a" or (bar in {"c", "d"}) or foo == "b" # Multiple targets 62 62 | 63 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets 64 64 | -repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`. | 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets 62 | @@ -330,12 +329,12 @@ repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comp 61 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets 62 62 | 63 |-foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets - 63 |+foo in ("a", "b") or "c" != bar and "d" != bar # Multiple targets + 63 |+foo in {"a", "b"} or "c" != bar and "d" != bar # Multiple targets 64 64 | 65 65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets 66 66 | -repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple comparisons: `bar not in ("c", "d")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple comparisons: `bar not in {"c", "d"}`. | 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets 62 | @@ -351,12 +350,12 @@ repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple com 61 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets 62 62 | 63 |-foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets - 63 |+foo == "a" or foo == "b" or bar not in ("c", "d") # Multiple targets + 63 |+foo == "a" or foo == "b" or bar not in {"c", "d"} # Multiple targets 64 64 | 65 65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets 66 66 | -repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple comparisons: `bar not in ("c", "d")`. Use a `set` if the elements are hashable. +repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple comparisons: `bar not in {"c", "d"}`. | 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets 64 | @@ -372,6 +371,85 @@ repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple com 63 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets 64 64 | 65 |-foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets - 65 |+foo == "a" or (bar not in ("c", "d")) or foo == "b" # Multiple targets + 65 |+foo == "a" or (bar not in {"c", "d"}) or foo == "b" # Multiple targets 66 66 | 67 67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets +68 68 | + +repeated_equality_comparison.py:69:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (1, True)`. + | +67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets +68 | +69 | foo == 1 or foo == True # Different types, same hashed value, Tuple expected + | ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +70 | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +66 66 | +67 67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets +68 68 | +69 |-foo == 1 or foo == True # Different types, same hashed value, Tuple expected + 69 |+foo in (1, True) # Different types, same hashed value, Tuple expected +70 70 | +71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected +72 72 | + +repeated_equality_comparison.py:71:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (1, 1.0)`. + | +69 | foo == 1 or foo == True # Different types, same hashed value, Tuple expected +70 | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected + | ^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +72 | +73 | foo == False or foo == 0 # Different types, same hashed value, Tuple expected + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +68 68 | +69 69 | foo == 1 or foo == True # Different types, same hashed value, Tuple expected +70 70 | +71 |-foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected + 71 |+foo in (1, 1.0) # Different types, same hashed value, Tuple expected +72 72 | +73 73 | foo == False or foo == 0 # Different types, same hashed value, Tuple expected +74 74 | + +repeated_equality_comparison.py:73:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (False, 0)`. + | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected +72 | +73 | foo == False or foo == 0 # Different types, same hashed value, Tuple expected + | ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +74 | +75 | foo == 0.0 or foo == 0j # Different types, same hashed value, Tuple expected + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +70 70 | +71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value, Tuple expected +72 72 | +73 |-foo == False or foo == 0 # Different types, same hashed value, Tuple expected + 73 |+foo in (False, 0) # Different types, same hashed value, Tuple expected +74 74 | +75 75 | foo == 0.0 or foo == 0j # Different types, same hashed value, Tuple expected + +repeated_equality_comparison.py:75:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (0.0, 0j)`. + | +73 | foo == False or foo == 0 # Different types, same hashed value, Tuple expected +74 | +75 | foo == 0.0 or foo == 0j # Different types, same hashed value, Tuple expected + | ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +72 72 | +73 73 | foo == False or foo == 0 # Different types, same hashed value, Tuple expected +74 74 | +75 |-foo == 0.0 or foo == 0j # Different types, same hashed value, Tuple expected + 75 |+foo in (0.0, 0j) # Different types, same hashed value, Tuple expected