From 0c2b88f2241d359f4c53fba9b614d3a995915c70 Mon Sep 17 00:00:00 2001 From: Dylan <53534755+dylwil3@users.noreply.github.com> Date: Sat, 10 Aug 2024 11:49:25 -0500 Subject: [PATCH] [`flake8-simplify`] Further simplify to binary in preview for `if-else-block-instead-of-if-exp (SIM108)` (#12796) In most cases we should suggest a ternary operator, but there are three edge cases where a binary operator is more appropriate. Given an if-else block of the form ```python if test: target_var = body_value else: target_var = else_value ``` This PR updates the check for SIM108 to the following: - If `test == body_value` and preview enabled, suggest to replace with `target_var = test or else_value` - If `test == not body_value` and preview enabled, suggest to replace with `target_var = body_value and else_value` - If `not test == body_value` and preview enabled, suggest to replace with `target_var = body_value and else_value` - Otherwise, suggest to replace with `target_var = body_value if test else else_value` Closes #12189. --- .../test/fixtures/flake8_simplify/SIM108.py | 59 ++++ .../src/rules/flake8_simplify/mod.rs | 20 ++ .../rules/if_else_block_instead_of_if_exp.rs | 142 +++++++- ...ke8_simplify__tests__SIM108_SIM108.py.snap | 182 +++++++++++ ...ify__tests__preview__SIM108_SIM108.py.snap | 304 ++++++++++++++++++ 5 files changed, 698 insertions(+), 9 deletions(-) create mode 100644 crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM108_SIM108.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM108.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM108.py index e31cc0af02e34..25991d478233d 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM108.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM108.py @@ -135,3 +135,62 @@ def f(): x = 3 else: x = 5 + +# SIM108 - should suggest +# z = cond or other_cond +if cond: + z = cond +else: + z = other_cond + +# SIM108 - should suggest +# z = cond and other_cond +if not cond: + z = cond +else: + z = other_cond + +# SIM108 - should suggest +# z = not cond and other_cond +if cond: + z = not cond +else: + z = other_cond + +# SIM108 does not suggest +# a binary option in these cases, +# despite the fact that `bool` +# is a subclass of both `int` and `float` +# so, e.g. `True == 1`. +# (Of course, these specific expressions +# should be simplified for other reasons...) +if True: + z = 1 +else: + z = other + +if False: + z = 1 +else: + z = other + +if 1: + z = True +else: + z = other + +# SIM108 does not suggest a binary option in this +# case, since we'd be reducing the number of calls +# from Two to one. +if foo(): + z = foo() +else: + z = other + +# SIM108 does not suggest a binary option in this +# case, since we'd be reducing the number of calls +# from Two to one. +if foo(): + z = not foo() +else: + z = other diff --git a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs index 5652d8e40b2c3..e2cf5dee0f9df 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs @@ -9,6 +9,8 @@ mod tests { use test_case::test_case; use crate::registry::Rule; + use crate::settings::types::PreviewMode; + use crate::settings::LinterSettings; use crate::test::test_path; use crate::{assert_messages, settings}; @@ -54,4 +56,22 @@ mod tests { assert_messages!(snapshot, diagnostics); Ok(()) } + + #[test_case(Rule::IfElseBlockInsteadOfIfExp, Path::new("SIM108.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("flake8_simplify").join(path).as_path(), + &LinterSettings { + preview: PreviewMode::Enabled, + ..LinterSettings::for_rule(rule_code) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } } diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/if_else_block_instead_of_if_exp.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/if_else_block_instead_of_if_exp.rs index e2f97ac3c7ac4..03e0dacec0fa2 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/if_else_block_instead_of_if_exp.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/if_else_block_instead_of_if_exp.rs @@ -1,6 +1,8 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, ElifElseClause, Expr, Stmt}; +use ruff_python_ast::comparable::ComparableExpr; +use ruff_python_ast::helpers::contains_effect; +use ruff_python_ast::{self as ast, BoolOp, ElifElseClause, Expr, Stmt}; use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block}; use ruff_text_size::{Ranged, TextRange}; @@ -9,12 +11,15 @@ use crate::fix::edits::fits; /// ## What it does /// Check for `if`-`else`-blocks that can be replaced with a ternary operator. +/// Moreover, in [preview], check if these ternary expressions can be +/// further simplified to binary expressions. /// /// ## Why is this bad? /// `if`-`else`-blocks that assign a value to a variable in both branches can -/// be expressed more concisely by using a ternary operator. +/// be expressed more concisely by using a ternary or binary operator. /// /// ## Example +/// /// ```python /// if foo: /// bar = x @@ -27,11 +32,31 @@ use crate::fix::edits::fits; /// bar = x if foo else y /// ``` /// +/// Or, in [preview]: +/// +/// ```python +/// if cond: +/// z = cond +/// else: +/// z = other_cond +/// ``` +/// +/// Use instead: +/// +/// ```python +/// z = cond or other_cond +/// ``` +/// /// ## References /// - [Python documentation: Conditional expressions](https://docs.python.org/3/reference/expressions.html#conditional-expressions) +/// +/// [preview]: https://docs.astral.sh/ruff/preview/ #[violation] pub struct IfElseBlockInsteadOfIfExp { + /// The ternary or binary expression to replace the `if`-`else`-block. contents: String, + /// Whether to use a binary or ternary assignment. + kind: AssignmentKind, } impl Violation for IfElseBlockInsteadOfIfExp { @@ -39,12 +64,19 @@ impl Violation for IfElseBlockInsteadOfIfExp { #[derive_message_formats] fn message(&self) -> String { - let IfElseBlockInsteadOfIfExp { contents } = self; - format!("Use ternary operator `{contents}` instead of `if`-`else`-block") + let IfElseBlockInsteadOfIfExp { contents, kind } = self; + match kind { + AssignmentKind::Ternary => { + format!("Use ternary operator `{contents}` instead of `if`-`else`-block") + } + AssignmentKind::Binary => { + format!("Use binary operator `{contents}` instead of `if`-`else`-block") + } + } } fn fix_title(&self) -> Option { - let IfElseBlockInsteadOfIfExp { contents } = self; + let IfElseBlockInsteadOfIfExp { contents, .. } = self; Some(format!("Replace `if`-`else`-block with `{contents}`")) } } @@ -121,9 +153,59 @@ pub(crate) fn if_else_block_instead_of_if_exp(checker: &mut Checker, stmt_if: &a return; } - let target_var = &body_target; - let ternary = ternary(target_var, body_value, test, else_value); - let contents = checker.generator().stmt(&ternary); + // In most cases we should now suggest a ternary operator, + // but there are three edge cases where a binary operator + // is more appropriate. + // + // For the reader's convenience, here is how + // the notation translates to the if-else block: + // + // ```python + // if test: + // target_var = body_value + // else: + // target_var = else_value + // ``` + // + // The match statement below implements the following + // logic: + // - If `test == body_value` and preview enabled, replace with `target_var = test or else_value` + // - If `test == not body_value` and preview enabled, replace with `target_var = body_value and else_value` + // - If `not test == body_value` and preview enabled, replace with `target_var = body_value and else_value` + // - Otherwise, replace with `target_var = body_value if test else else_value` + let (contents, assignment_kind) = + match (checker.settings.preview.is_enabled(), test, body_value) { + (true, test_node, body_node) + if ComparableExpr::from(test_node) == ComparableExpr::from(body_node) + && !contains_effect(test_node, |id| { + checker.semantic().has_builtin_binding(id) + }) => + { + let target_var = &body_target; + let binary = assignment_binary_or(target_var, body_value, else_value); + (checker.generator().stmt(&binary), AssignmentKind::Binary) + } + (true, test_node, body_node) + if (test_node.as_unary_op_expr().is_some_and(|op_expr| { + op_expr.op.is_not() + && ComparableExpr::from(&op_expr.operand) == ComparableExpr::from(body_node) + }) || body_node.as_unary_op_expr().is_some_and(|op_expr| { + op_expr.op.is_not() + && ComparableExpr::from(&op_expr.operand) == ComparableExpr::from(test_node) + })) && !contains_effect(test_node, |id| { + checker.semantic().has_builtin_binding(id) + }) => + { + let target_var = &body_target; + let binary = assignment_binary_and(target_var, body_value, else_value); + (checker.generator().stmt(&binary), AssignmentKind::Binary) + } + _ => { + let target_var = &body_target; + let ternary = assignment_ternary(target_var, body_value, test, else_value); + (checker.generator().stmt(&ternary), AssignmentKind::Ternary) + } + }; // Don't flag if the resulting expression would exceed the maximum line length. if !fits( @@ -139,6 +221,7 @@ pub(crate) fn if_else_block_instead_of_if_exp(checker: &mut Checker, stmt_if: &a let mut diagnostic = Diagnostic::new( IfElseBlockInsteadOfIfExp { contents: contents.clone(), + kind: assignment_kind, }, stmt_if.range(), ); @@ -154,7 +237,18 @@ pub(crate) fn if_else_block_instead_of_if_exp(checker: &mut Checker, stmt_if: &a checker.diagnostics.push(diagnostic); } -fn ternary(target_var: &Expr, body_value: &Expr, test: &Expr, orelse_value: &Expr) -> Stmt { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum AssignmentKind { + Binary, + Ternary, +} + +fn assignment_ternary( + target_var: &Expr, + body_value: &Expr, + test: &Expr, + orelse_value: &Expr, +) -> Stmt { let node = ast::ExprIf { test: Box::new(test.clone()), body: Box::new(body_value.clone()), @@ -168,3 +262,33 @@ fn ternary(target_var: &Expr, body_value: &Expr, test: &Expr, orelse_value: &Exp }; node1.into() } + +fn assignment_binary_and(target_var: &Expr, left_value: &Expr, right_value: &Expr) -> Stmt { + let node = ast::ExprBoolOp { + op: BoolOp::And, + values: vec![left_value.clone(), right_value.clone()], + range: TextRange::default(), + }; + let node1 = ast::StmtAssign { + targets: vec![target_var.clone()], + value: Box::new(node.into()), + range: TextRange::default(), + }; + node1.into() +} + +fn assignment_binary_or(target_var: &Expr, left_value: &Expr, right_value: &Expr) -> Stmt { + (ast::StmtAssign { + range: TextRange::default(), + targets: vec![target_var.clone()], + value: Box::new( + (ast::ExprBoolOp { + range: TextRange::default(), + op: BoolOp::Or, + values: vec![left_value.clone(), right_value.clone()], + }) + .into(), + ), + }) + .into() +} diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap index 71cede1631308..12e9c96372b61 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap @@ -119,4 +119,186 @@ SIM108.py:117:1: SIM108 Use ternary operator `x = 3 if True else 5` instead of ` | = help: Replace `if`-`else`-block with `x = 3 if True else 5` +SIM108.py:141:1: SIM108 [*] Use ternary operator `z = cond if cond else other_cond` instead of `if`-`else`-block + | +139 | # SIM108 - should suggest +140 | # z = cond or other_cond +141 | / if cond: +142 | | z = cond +143 | | else: +144 | | z = other_cond + | |__________________^ SIM108 +145 | +146 | # SIM108 - should suggest + | + = help: Replace `if`-`else`-block with `z = cond if cond else other_cond` + +ℹ Unsafe fix +138 138 | +139 139 | # SIM108 - should suggest +140 140 | # z = cond or other_cond +141 |-if cond: +142 |- z = cond +143 |-else: +144 |- z = other_cond + 141 |+z = cond if cond else other_cond +145 142 | +146 143 | # SIM108 - should suggest +147 144 | # z = cond and other_cond + +SIM108.py:148:1: SIM108 [*] Use ternary operator `z = cond if not cond else other_cond` instead of `if`-`else`-block + | +146 | # SIM108 - should suggest +147 | # z = cond and other_cond +148 | / if not cond: +149 | | z = cond +150 | | else: +151 | | z = other_cond + | |__________________^ SIM108 +152 | +153 | # SIM108 - should suggest + | + = help: Replace `if`-`else`-block with `z = cond if not cond else other_cond` + +ℹ Unsafe fix +145 145 | +146 146 | # SIM108 - should suggest +147 147 | # z = cond and other_cond +148 |-if not cond: +149 |- z = cond +150 |-else: +151 |- z = other_cond + 148 |+z = cond if not cond else other_cond +152 149 | +153 150 | # SIM108 - should suggest +154 151 | # z = not cond and other_cond + +SIM108.py:155:1: SIM108 [*] Use ternary operator `z = not cond if cond else other_cond` instead of `if`-`else`-block + | +153 | # SIM108 - should suggest +154 | # z = not cond and other_cond +155 | / if cond: +156 | | z = not cond +157 | | else: +158 | | z = other_cond + | |__________________^ SIM108 +159 | +160 | # SIM108 does not suggest + | + = help: Replace `if`-`else`-block with `z = not cond if cond else other_cond` + +ℹ Unsafe fix +152 152 | +153 153 | # SIM108 - should suggest +154 154 | # z = not cond and other_cond +155 |-if cond: +156 |- z = not cond +157 |-else: +158 |- z = other_cond + 155 |+z = not cond if cond else other_cond +159 156 | +160 157 | # SIM108 does not suggest +161 158 | # a binary option in these cases, + +SIM108.py:167:1: SIM108 [*] Use ternary operator `z = 1 if True else other` instead of `if`-`else`-block + | +165 | # (Of course, these specific expressions +166 | # should be simplified for other reasons...) +167 | / if True: +168 | | z = 1 +169 | | else: +170 | | z = other + | |_____________^ SIM108 +171 | +172 | if False: + | + = help: Replace `if`-`else`-block with `z = 1 if True else other` +ℹ Unsafe fix +164 164 | # so, e.g. `True == 1`. +165 165 | # (Of course, these specific expressions +166 166 | # should be simplified for other reasons...) +167 |-if True: +168 |- z = 1 +169 |-else: +170 |- z = other + 167 |+z = 1 if True else other +171 168 | +172 169 | if False: +173 170 | z = 1 + +SIM108.py:177:1: SIM108 [*] Use ternary operator `z = True if 1 else other` instead of `if`-`else`-block + | +175 | z = other +176 | +177 | / if 1: +178 | | z = True +179 | | else: +180 | | z = other + | |_____________^ SIM108 +181 | +182 | # SIM108 does not suggest a binary option in this + | + = help: Replace `if`-`else`-block with `z = True if 1 else other` + +ℹ Unsafe fix +174 174 | else: +175 175 | z = other +176 176 | +177 |-if 1: +178 |- z = True +179 |-else: +180 |- z = other + 177 |+z = True if 1 else other +181 178 | +182 179 | # SIM108 does not suggest a binary option in this +183 180 | # case, since we'd be reducing the number of calls + +SIM108.py:185:1: SIM108 [*] Use ternary operator `z = foo() if foo() else other` instead of `if`-`else`-block + | +183 | # case, since we'd be reducing the number of calls +184 | # from Two to one. +185 | / if foo(): +186 | | z = foo() +187 | | else: +188 | | z = other + | |_____________^ SIM108 +189 | +190 | # SIM108 does not suggest a binary option in this + | + = help: Replace `if`-`else`-block with `z = foo() if foo() else other` + +ℹ Unsafe fix +182 182 | # SIM108 does not suggest a binary option in this +183 183 | # case, since we'd be reducing the number of calls +184 184 | # from Two to one. +185 |-if foo(): +186 |- z = foo() +187 |-else: +188 |- z = other + 185 |+z = foo() if foo() else other +189 186 | +190 187 | # SIM108 does not suggest a binary option in this +191 188 | # case, since we'd be reducing the number of calls + +SIM108.py:193:1: SIM108 [*] Use ternary operator `z = not foo() if foo() else other` instead of `if`-`else`-block + | +191 | # case, since we'd be reducing the number of calls +192 | # from Two to one. +193 | / if foo(): +194 | | z = not foo() +195 | | else: +196 | | z = other + | |_____________^ SIM108 + | + = help: Replace `if`-`else`-block with `z = not foo() if foo() else other` + +ℹ Unsafe fix +190 190 | # SIM108 does not suggest a binary option in this +191 191 | # case, since we'd be reducing the number of calls +192 192 | # from Two to one. +193 |-if foo(): +194 |- z = not foo() +195 |-else: +196 |- z = other + 193 |+z = not foo() if foo() else other diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM108_SIM108.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM108_SIM108.py.snap new file mode 100644 index 0000000000000..0be8a6b7ca0a5 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM108_SIM108.py.snap @@ -0,0 +1,304 @@ +--- +source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs +--- +SIM108.py:2:1: SIM108 [*] Use ternary operator `b = c if a else d` instead of `if`-`else`-block + | +1 | # SIM108 +2 | / if a: +3 | | b = c +4 | | else: +5 | | b = d + | |_________^ SIM108 +6 | +7 | # OK + | + = help: Replace `if`-`else`-block with `b = c if a else d` + +ℹ Unsafe fix +1 1 | # SIM108 +2 |-if a: +3 |- b = c +4 |-else: +5 |- b = d + 2 |+b = c if a else d +6 3 | +7 4 | # OK +8 5 | b = c if a else d + +SIM108.py:30:5: SIM108 [*] Use ternary operator `b = 1 if a else 2` instead of `if`-`else`-block + | +28 | pass +29 | else: +30 | if a: + | _____^ +31 | | b = 1 +32 | | else: +33 | | b = 2 + | |_____________^ SIM108 + | + = help: Replace `if`-`else`-block with `b = 1 if a else 2` + +ℹ Unsafe fix +27 27 | if True: +28 28 | pass +29 29 | else: +30 |- if a: +31 |- b = 1 +32 |- else: +33 |- b = 2 + 30 |+ b = 1 if a else 2 +34 31 | +35 32 | +36 33 | import sys + +SIM108.py:58:1: SIM108 Use ternary operator `abc = x if x > 0 else -x` instead of `if`-`else`-block + | +57 | # SIM108 (without fix due to comments) +58 | / if x > 0: +59 | | # test test +60 | | abc = x +61 | | else: +62 | | # test test test +63 | | abc = -x + | |____________^ SIM108 + | + = help: Replace `if`-`else`-block with `abc = x if x > 0 else -x` + +SIM108.py:82:1: SIM108 [*] Use ternary operator `b = "cccccccccccccccccccccccccccccccccß" if a else "ddddddddddddddddddddddddddddddddd💣"` instead of `if`-`else`-block + | +81 | # SIM108 +82 | / if a: +83 | | b = "cccccccccccccccccccccccccccccccccß" +84 | | else: +85 | | b = "ddddddddddddddddddddddddddddddddd💣" + | |_____________________________________________^ SIM108 + | + = help: Replace `if`-`else`-block with `b = "cccccccccccccccccccccccccccccccccß" if a else "ddddddddddddddddddddddddddddddddd💣"` + +ℹ Unsafe fix +79 79 | +80 80 | +81 81 | # SIM108 +82 |-if a: +83 |- b = "cccccccccccccccccccccccccccccccccß" +84 |-else: +85 |- b = "ddddddddddddddddddddddddddddddddd💣" + 82 |+b = "cccccccccccccccccccccccccccccccccß" if a else "ddddddddddddddddddddddddddddddddd💣" +86 83 | +87 84 | +88 85 | # OK (too long) + +SIM108.py:105:1: SIM108 Use ternary operator `exitcode = 0 if True else 1` instead of `if`-`else`-block + | +104 | # SIM108 (without fix due to trailing comment) +105 | / if True: +106 | | exitcode = 0 +107 | | else: +108 | | exitcode = 1 # Trailing comment + | |________________^ SIM108 + | + = help: Replace `if`-`else`-block with `exitcode = 0 if True else 1` + +SIM108.py:112:1: SIM108 Use ternary operator `x = 3 if True else 5` instead of `if`-`else`-block + | +111 | # SIM108 +112 | / if True: x = 3 # Foo +113 | | else: x = 5 + | |___________^ SIM108 + | + = help: Replace `if`-`else`-block with `x = 3 if True else 5` + +SIM108.py:117:1: SIM108 Use ternary operator `x = 3 if True else 5` instead of `if`-`else`-block + | +116 | # SIM108 +117 | / if True: # Foo +118 | | x = 3 +119 | | else: +120 | | x = 5 + | |_________^ SIM108 + | + = help: Replace `if`-`else`-block with `x = 3 if True else 5` + +SIM108.py:141:1: SIM108 [*] Use binary operator `z = cond or other_cond` instead of `if`-`else`-block + | +139 | # SIM108 - should suggest +140 | # z = cond or other_cond +141 | / if cond: +142 | | z = cond +143 | | else: +144 | | z = other_cond + | |__________________^ SIM108 +145 | +146 | # SIM108 - should suggest + | + = help: Replace `if`-`else`-block with `z = cond or other_cond` + +ℹ Unsafe fix +138 138 | +139 139 | # SIM108 - should suggest +140 140 | # z = cond or other_cond +141 |-if cond: +142 |- z = cond +143 |-else: +144 |- z = other_cond + 141 |+z = cond or other_cond +145 142 | +146 143 | # SIM108 - should suggest +147 144 | # z = cond and other_cond + +SIM108.py:148:1: SIM108 [*] Use binary operator `z = cond and other_cond` instead of `if`-`else`-block + | +146 | # SIM108 - should suggest +147 | # z = cond and other_cond +148 | / if not cond: +149 | | z = cond +150 | | else: +151 | | z = other_cond + | |__________________^ SIM108 +152 | +153 | # SIM108 - should suggest + | + = help: Replace `if`-`else`-block with `z = cond and other_cond` + +ℹ Unsafe fix +145 145 | +146 146 | # SIM108 - should suggest +147 147 | # z = cond and other_cond +148 |-if not cond: +149 |- z = cond +150 |-else: +151 |- z = other_cond + 148 |+z = cond and other_cond +152 149 | +153 150 | # SIM108 - should suggest +154 151 | # z = not cond and other_cond + +SIM108.py:155:1: SIM108 [*] Use binary operator `z = not cond and other_cond` instead of `if`-`else`-block + | +153 | # SIM108 - should suggest +154 | # z = not cond and other_cond +155 | / if cond: +156 | | z = not cond +157 | | else: +158 | | z = other_cond + | |__________________^ SIM108 +159 | +160 | # SIM108 does not suggest + | + = help: Replace `if`-`else`-block with `z = not cond and other_cond` + +ℹ Unsafe fix +152 152 | +153 153 | # SIM108 - should suggest +154 154 | # z = not cond and other_cond +155 |-if cond: +156 |- z = not cond +157 |-else: +158 |- z = other_cond + 155 |+z = not cond and other_cond +159 156 | +160 157 | # SIM108 does not suggest +161 158 | # a binary option in these cases, + +SIM108.py:167:1: SIM108 [*] Use ternary operator `z = 1 if True else other` instead of `if`-`else`-block + | +165 | # (Of course, these specific expressions +166 | # should be simplified for other reasons...) +167 | / if True: +168 | | z = 1 +169 | | else: +170 | | z = other + | |_____________^ SIM108 +171 | +172 | if False: + | + = help: Replace `if`-`else`-block with `z = 1 if True else other` + +ℹ Unsafe fix +164 164 | # so, e.g. `True == 1`. +165 165 | # (Of course, these specific expressions +166 166 | # should be simplified for other reasons...) +167 |-if True: +168 |- z = 1 +169 |-else: +170 |- z = other + 167 |+z = 1 if True else other +171 168 | +172 169 | if False: +173 170 | z = 1 + +SIM108.py:177:1: SIM108 [*] Use ternary operator `z = True if 1 else other` instead of `if`-`else`-block + | +175 | z = other +176 | +177 | / if 1: +178 | | z = True +179 | | else: +180 | | z = other + | |_____________^ SIM108 +181 | +182 | # SIM108 does not suggest a binary option in this + | + = help: Replace `if`-`else`-block with `z = True if 1 else other` + +ℹ Unsafe fix +174 174 | else: +175 175 | z = other +176 176 | +177 |-if 1: +178 |- z = True +179 |-else: +180 |- z = other + 177 |+z = True if 1 else other +181 178 | +182 179 | # SIM108 does not suggest a binary option in this +183 180 | # case, since we'd be reducing the number of calls + +SIM108.py:185:1: SIM108 [*] Use ternary operator `z = foo() if foo() else other` instead of `if`-`else`-block + | +183 | # case, since we'd be reducing the number of calls +184 | # from Two to one. +185 | / if foo(): +186 | | z = foo() +187 | | else: +188 | | z = other + | |_____________^ SIM108 +189 | +190 | # SIM108 does not suggest a binary option in this + | + = help: Replace `if`-`else`-block with `z = foo() if foo() else other` + +ℹ Unsafe fix +182 182 | # SIM108 does not suggest a binary option in this +183 183 | # case, since we'd be reducing the number of calls +184 184 | # from Two to one. +185 |-if foo(): +186 |- z = foo() +187 |-else: +188 |- z = other + 185 |+z = foo() if foo() else other +189 186 | +190 187 | # SIM108 does not suggest a binary option in this +191 188 | # case, since we'd be reducing the number of calls + +SIM108.py:193:1: SIM108 [*] Use ternary operator `z = not foo() if foo() else other` instead of `if`-`else`-block + | +191 | # case, since we'd be reducing the number of calls +192 | # from Two to one. +193 | / if foo(): +194 | | z = not foo() +195 | | else: +196 | | z = other + | |_____________^ SIM108 + | + = help: Replace `if`-`else`-block with `z = not foo() if foo() else other` + +ℹ Unsafe fix +190 190 | # SIM108 does not suggest a binary option in this +191 191 | # case, since we'd be reducing the number of calls +192 192 | # from Two to one. +193 |-if foo(): +194 |- z = not foo() +195 |-else: +196 |- z = other + 193 |+z = not foo() if foo() else other