From 577653551ce38e12caae75da5cbe1c72a5e5e4f0 Mon Sep 17 00:00:00 2001 From: Steve C Date: Mon, 18 Nov 2024 02:57:43 -0500 Subject: [PATCH] [`pylint`] - use sets when possible for `PLR1714` autofix (`repeated-equality-comparison`) (#14372) --- .../pylint/repeated_equality_comparison.py | 8 + crates/ruff_linter/src/rules/pylint/mod.rs | 25 +- .../rules/repeated_equality_comparison.rs | 63 ++- ...R1714_repeated_equality_comparison.py.snap | 80 ++- ...R1714_repeated_equality_comparison.py.snap | 455 ++++++++++++++++++ 5 files changed, 615 insertions(+), 16 deletions(-) create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__preview__PLR1714_repeated_equality_comparison.py.snap 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..328f38666c87d 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 + +foo == 1 or foo == 1.0 # Different types, same hashed value + +foo == False or foo == 0 # Different types, same hashed value + +foo == 0.0 or foo == 0j # Different types, same hashed value diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index 1ef1e7003f3e9..b17e530757a5d 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -15,10 +15,10 @@ mod tests { use crate::registry::Rule; use crate::rules::pylint; - use crate::assert_messages; - use crate::settings::types::PythonVersion; + use crate::settings::types::{PreviewMode, PythonVersion}; use crate::settings::LinterSettings; use crate::test::test_path; + use crate::{assert_messages, settings}; #[test_case(Rule::SingledispatchMethod, Path::new("singledispatch_method.py"))] #[test_case( @@ -405,4 +405,25 @@ mod tests { assert_messages!(diagnostics); Ok(()) } + + #[test_case( + Rule::RepeatedEqualityComparison, + Path::new("repeated_equality_comparison.py") + )] + fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!( + "preview__{}_{}", + rule_code.noqa_code(), + path.to_string_lossy() + ); + let diagnostics = test_path( + Path::new("pylint").join(path).as_path(), + &settings::LinterSettings { + preview: PreviewMode::Enabled, + ..settings::LinterSettings::for_rule(rule_code) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } } 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..b56aaaeaeb345 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 @@ -28,6 +28,10 @@ use crate::Locator; /// If the items are hashable, use a `set` for efficiency; otherwise, use a /// `tuple`. /// +/// In [preview], this rule will try to determine if the values are hashable +/// and the fix will use a `set` if they are. If unable to determine, the fix +/// will use a `tuple` and continue to suggest the use of a `set`. +/// /// ## Example /// ```python /// foo == "bar" or foo == "baz" or foo == "qux" @@ -42,21 +46,29 @@ use crate::Locator; /// - [Python documentation: Comparisons](https://docs.python.org/3/reference/expressions.html#comparisons) /// - [Python documentation: Membership test operations](https://docs.python.org/3/reference/expressions.html#membership-test-operations) /// - [Python documentation: `set`](https://docs.python.org/3/library/stdtypes.html#set) +/// +/// [preview]: https://docs.astral.sh/ruff/preview/ #[violation] pub struct RepeatedEqualityComparison { expression: SourceCodeSnippet, + all_hashable: bool, } 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." - ) - } else { - "Consider merging multiple comparisons. Use a `set` if the elements are hashable." - .to_string() + match (self.expression.full_display(), self.all_hashable) { + (Some(expression), false) => { + format!("Consider merging multiple comparisons: `{expression}`. Use a `set` if the elements are hashable.") + } + (Some(expression), true) => { + format!("Consider merging multiple comparisons: `{expression}`.") + } + (None, false) => { + "Consider merging multiple comparisons. Use a `set` if the elements are hashable." + .to_string() + } + (None, true) => "Consider merging multiple comparisons.".to_string(), } } @@ -121,6 +133,13 @@ pub(crate) fn repeated_equality_comparison(checker: &mut Checker, bool_op: &ast: continue; } + // if we can determine that all the values are hashable, we can use a set + // TODO: improve with type inference + let all_hashable = checker.settings.preview.is_enabled() + && comparators + .iter() + .all(|comparator| comparator.is_literal_expr()); + let mut diagnostic = Diagnostic::new( RepeatedEqualityComparison { expression: SourceCodeSnippet::new(merged_membership_test( @@ -128,7 +147,9 @@ pub(crate) fn repeated_equality_comparison(checker: &mut Checker, bool_op: &ast: bool_op.op, &comparators, checker.locator(), + all_hashable, )), + all_hashable, }, bool_op.range(), ); @@ -140,6 +161,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 all_hashable { + 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 +185,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 +261,13 @@ fn to_allowed_value<'a>( } /// Generate a string like `obj in (a, b, c)` or `obj not in (a, b, c)`. +/// If `all_hashable` is `true`, the string will use a set instead of a tuple. fn merged_membership_test( left: &Expr, op: BoolOp, comparators: &[&Expr], locator: &Locator, + all_hashable: bool, ) -> String { let op = match op { BoolOp::Or => "in", @@ -246,5 +278,10 @@ fn merged_membership_test( .iter() .map(|comparator| locator.slice(comparator)) .join(", "); + + if all_hashable { + 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..142e76e87f016 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,6 +1,5 @@ --- 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. | @@ -375,3 +374,82 @@ repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple com 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)`. Use a `set` if the elements are hashable. + | +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 + | ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +70 | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value + | + = 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 + 69 |+foo in (1, True) # Different types, same hashed value +70 70 | +71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value +72 72 | + +repeated_equality_comparison.py:71:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (1, 1.0)`. Use a `set` if the elements are hashable. + | +69 | foo == 1 or foo == True # Different types, same hashed value +70 | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value + | ^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +72 | +73 | foo == False or foo == 0 # Different types, same hashed value + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +68 68 | +69 69 | foo == 1 or foo == True # Different types, same hashed value +70 70 | +71 |-foo == 1 or foo == 1.0 # Different types, same hashed value + 71 |+foo in (1, 1.0) # Different types, same hashed value +72 72 | +73 73 | foo == False or foo == 0 # Different types, same hashed value +74 74 | + +repeated_equality_comparison.py:73:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (False, 0)`. Use a `set` if the elements are hashable. + | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value +72 | +73 | foo == False or foo == 0 # Different types, same hashed value + | ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +74 | +75 | foo == 0.0 or foo == 0j # Different types, same hashed value + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +70 70 | +71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value +72 72 | +73 |-foo == False or foo == 0 # Different types, same hashed value + 73 |+foo in (False, 0) # Different types, same hashed value +74 74 | +75 75 | foo == 0.0 or foo == 0j # Different types, same hashed value + +repeated_equality_comparison.py:75:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (0.0, 0j)`. Use a `set` if the elements are hashable. + | +73 | foo == False or foo == 0 # Different types, same hashed value +74 | +75 | foo == 0.0 or foo == 0j # Different types, same hashed value + | ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +72 72 | +73 73 | foo == False or foo == 0 # Different types, same hashed value +74 74 | +75 |-foo == 0.0 or foo == 0j # Different types, same hashed value + 75 |+foo in (0.0, 0j) # Different types, same hashed value diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__preview__PLR1714_repeated_equality_comparison.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__preview__PLR1714_repeated_equality_comparison.py.snap new file mode 100644 index 0000000000000..02c5e92cb799d --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__preview__PLR1714_repeated_equality_comparison.py.snap @@ -0,0 +1,455 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`. + | +1 | # Errors. +2 | foo == "a" or foo == "b" + | ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +3 | +4 | foo != "a" and foo != "b" + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +1 1 | # Errors. +2 |-foo == "a" or foo == "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"}`. + | +2 | foo == "a" or foo == "b" +3 | +4 | foo != "a" and foo != "b" + | ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +5 | +6 | foo == "a" or foo == "b" or foo == "c" + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +1 1 | # Errors. +2 2 | foo == "a" or foo == "b" +3 3 | +4 |-foo != "a" and foo != "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"}`. + | +4 | foo != "a" and foo != "b" +5 | +6 | foo == "a" or foo == "b" or foo == "c" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +7 | +8 | foo != "a" and foo != "b" and foo != "c" + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +3 3 | +4 4 | foo != "a" and foo != "b" +5 5 | +6 |-foo == "a" or foo == "b" or foo == "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"}`. + | + 6 | foo == "a" or foo == "b" or foo == "c" + 7 | + 8 | foo != "a" and foo != "b" and foo != "c" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 + 9 | +10 | foo == a or foo == "b" or foo == 3 # Mixed types. + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +5 5 | +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"} +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. + | + 8 | foo != "a" and foo != "b" and foo != "c" + 9 | +10 | foo == a or foo == "b" or foo == 3 # Mixed types. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +11 | +12 | "a" == foo or "b" == foo or "c" == foo + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +7 7 | +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. +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"}`. + | +10 | foo == a or foo == "b" or foo == 3 # Mixed types. +11 | +12 | "a" == foo or "b" == foo or "c" == foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +13 | +14 | "a" != foo and "b" != foo and "c" != foo + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +9 9 | +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"} +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"}`. + | +12 | "a" == foo or "b" == foo or "c" == foo +13 | +14 | "a" != foo and "b" != foo and "c" != foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +15 | +16 | "a" == foo or foo == "b" or "c" == foo + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +11 11 | +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"} +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"}`. + | +14 | "a" != foo and "b" != foo and "c" != foo +15 | +16 | "a" == foo or foo == "b" or "c" == foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +17 | +18 | foo == bar or baz == foo or qux == foo + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +13 13 | +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"} +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. + | +16 | "a" == foo or foo == "b" or "c" == foo +17 | +18 | foo == bar or baz == foo or qux == foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +19 | +20 | foo == "a" or "b" == foo or foo == "c" + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +15 15 | +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) +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"}`. + | +18 | foo == bar or baz == foo or qux == foo +19 | +20 | foo == "a" or "b" == foo or foo == "c" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +21 | +22 | foo != "a" and "b" != foo and foo != "c" + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +17 17 | +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"} +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"}`. + | +20 | foo == "a" or "b" == foo or foo == "c" +21 | +22 | foo != "a" and "b" != foo and foo != "c" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +23 | +24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +19 19 | +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"} +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"}`. + | +22 | foo != "a" and "b" != foo and foo != "c" +23 | +24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +25 | +26 | foo.bar == "a" or foo.bar == "b" # Attributes. + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +21 21 | +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 +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"}`. + | +22 | foo != "a" and "b" != foo and foo != "c" +23 | +24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +25 | +26 | foo.bar == "a" or foo.bar == "b" # Attributes. + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +21 21 | +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 +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"}`. + | +24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets +25 | +26 | foo.bar == "a" or foo.bar == "b" # Attributes. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +27 | +28 | # OK + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +23 23 | +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. +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"}`. + | +59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets +60 | +61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets + | ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +62 | +63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +58 58 | +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 +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"}`. + | +61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets +62 | +63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +64 | +65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +60 60 | +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 +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"}`. + | +61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets +62 | +63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets + | ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +64 | +65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +60 60 | +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 +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"}`. + | +63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets +64 | +65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets + | ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +66 | +67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +62 62 | +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 +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 + | ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +70 | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value + | + = 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 + 69 |+foo in {1, True} # Different types, same hashed value +70 70 | +71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value +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 +70 | +71 | foo == 1 or foo == 1.0 # Different types, same hashed value + | ^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +72 | +73 | foo == False or foo == 0 # Different types, same hashed value + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +68 68 | +69 69 | foo == 1 or foo == True # Different types, same hashed value +70 70 | +71 |-foo == 1 or foo == 1.0 # Different types, same hashed value + 71 |+foo in {1, 1.0} # Different types, same hashed value +72 72 | +73 73 | foo == False or foo == 0 # Different types, same hashed value +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 +72 | +73 | foo == False or foo == 0 # Different types, same hashed value + | ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 +74 | +75 | foo == 0.0 or foo == 0j # Different types, same hashed value + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +70 70 | +71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value +72 72 | +73 |-foo == False or foo == 0 # Different types, same hashed value + 73 |+foo in {False, 0} # Different types, same hashed value +74 74 | +75 75 | foo == 0.0 or foo == 0j # Different types, same hashed value + +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 +74 | +75 | foo == 0.0 or foo == 0j # Different types, same hashed value + | ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714 + | + = help: Merge multiple comparisons + +ℹ Unsafe fix +72 72 | +73 73 | foo == False or foo == 0 # Different types, same hashed value +74 74 | +75 |-foo == 0.0 or foo == 0j # Different types, same hashed value + 75 |+foo in {0.0, 0j} # Different types, same hashed value