From 21ea290d6aa6b3173530e645f9cd849ff0c95ed1 Mon Sep 17 00:00:00 2001 From: Steve C Date: Tue, 17 Oct 2023 00:44:25 -0400 Subject: [PATCH] [pylint] Implement PLR0916 (`too-many-boolean-expressions`) (#7975) ## Summary Add [R0916](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/too-many-boolean-expressions.html), no autofix available. See: #970 ## Test Plan `cargo test` and manually. --- .../pylint/too_many_boolean_expressions.py | 54 +++++ .../src/checkers/ast/analyze/statement.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/pylint/mod.rs | 16 ++ .../ruff_linter/src/rules/pylint/rules/mod.rs | 2 + .../rules/too_many_boolean_expressions.rs | 89 ++++++++ .../ruff_linter/src/rules/pylint/settings.rs | 2 + ...ylint__tests__max_boolean_expressions.snap | 214 ++++++++++++++++++ crates/ruff_workspace/src/options.rs | 6 + ruff.schema.json | 10 + scripts/check_docs_formatted.py | 1 + 11 files changed, 398 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pylint/too_many_boolean_expressions.py create mode 100644 crates/ruff_linter/src/rules/pylint/rules/too_many_boolean_expressions.rs create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_boolean_expressions.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/too_many_boolean_expressions.py b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_boolean_expressions.py new file mode 100644 index 0000000000000..a83f387c6dda8 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_boolean_expressions.py @@ -0,0 +1,54 @@ +if a: + ... +elif (a and b): + ... +elif (a and b) and c: + ... +elif (a and b) and c and d: + ... +elif (a and b) and c and d and e: + ... +elif (a and b) and c and d and e and f: + ... +elif (a and b) and c and d and e and f and g: + ... +elif (a and b) and c and d and e and f and g and h: + ... +elif (a and b) and c and d and e and f and g and h and i: + ... +elif (a and b) and c and d and e and f and g and h and i and j: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y: + ... +elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y and z: + ... +else: + ... diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 393dc0237f50a..bf5313b981e00 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1070,6 +1070,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::CheckAndRemoveFromSet) { refurb::rules::check_and_remove_from_set(checker, if_); } + if checker.enabled(Rule::TooManyBooleanExpressions) { + pylint::rules::too_many_boolean_expressions(checker, if_); + } if checker.source_type.is_stub() { if checker.any_enabled(&[ Rule::UnrecognizedVersionInfoCheck, diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index c67d4e9a6b3e4..6835e7e725a98 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -247,6 +247,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pylint, "R0912") => (RuleGroup::Stable, rules::pylint::rules::TooManyBranches), (Pylint, "R0913") => (RuleGroup::Stable, rules::pylint::rules::TooManyArguments), (Pylint, "R0915") => (RuleGroup::Stable, rules::pylint::rules::TooManyStatements), + (Pylint, "R0916") => (RuleGroup::Preview, rules::pylint::rules::TooManyBooleanExpressions), (Pylint, "R1701") => (RuleGroup::Stable, rules::pylint::rules::RepeatedIsinstanceCalls), (Pylint, "R1711") => (RuleGroup::Stable, rules::pylint::rules::UselessReturn), (Pylint, "R1714") => (RuleGroup::Stable, rules::pylint::rules::RepeatedEqualityComparison), diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index cf7d903f7a86e..d17a662cbdb4f 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -231,6 +231,22 @@ mod tests { Ok(()) } + #[test] + fn max_boolean_expressions() -> Result<()> { + let diagnostics = test_path( + Path::new("pylint/too_many_boolean_expressions.py"), + &LinterSettings { + pylint: pylint::settings::Settings { + max_bool_expr: 5, + ..pylint::settings::Settings::default() + }, + ..LinterSettings::for_rule(Rule::TooManyBooleanExpressions) + }, + )?; + assert_messages!(diagnostics); + Ok(()) + } + #[test] fn max_statements() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pylint/rules/mod.rs b/crates/ruff_linter/src/rules/pylint/rules/mod.rs index 2d7495ac07909..c4d7bd831b8ed 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/mod.rs @@ -45,6 +45,7 @@ pub(crate) use subprocess_popen_preexec_fn::*; pub(crate) use subprocess_run_without_check::*; pub(crate) use sys_exit_alias::*; pub(crate) use too_many_arguments::*; +pub(crate) use too_many_boolean_expressions::*; pub(crate) use too_many_branches::*; pub(crate) use too_many_public_methods::*; pub(crate) use too_many_return_statements::*; @@ -108,6 +109,7 @@ mod subprocess_popen_preexec_fn; mod subprocess_run_without_check; mod sys_exit_alias; mod too_many_arguments; +mod too_many_boolean_expressions; mod too_many_branches; mod too_many_public_methods; mod too_many_return_statements; diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_boolean_expressions.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_boolean_expressions.rs new file mode 100644 index 0000000000000..33cead02fc3cf --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_boolean_expressions.rs @@ -0,0 +1,89 @@ +use ast::{Expr, StmtIf}; +use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast as ast; +use ruff_text_size::Ranged; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for too many Boolean expressions in an `if` statement. +/// +/// By default, this rule allows up to 5 expressions. This can be configured +/// using the [`pylint.max-bool-expr`] option. +/// +/// ## Why is this bad? +/// `if` statements with many Boolean expressions are harder to understand +/// and maintain. Consider assigning the result of the Boolean expression, +/// or any of its sub-expressions, to a variable. +/// +/// ## Example +/// ```python +/// if a and b and c and d and e and f and g and h: +/// ... +/// ``` +/// +/// ## Options +/// - `pylint.max-bool-expr` +#[violation] +pub struct TooManyBooleanExpressions { + expressions: usize, + max_expressions: usize, +} + +impl Violation for TooManyBooleanExpressions { + #[derive_message_formats] + fn message(&self) -> String { + let TooManyBooleanExpressions { + expressions, + max_expressions, + } = self; + format!("Too many Boolean expressions ({expressions} > {max_expressions})") + } +} + +/// PLR0916 +pub(crate) fn too_many_boolean_expressions(checker: &mut Checker, stmt: &StmtIf) { + if let Some(bool_op) = stmt.test.as_bool_op_expr() { + let expressions = count_bools(bool_op); + if expressions > checker.settings.pylint.max_bool_expr { + checker.diagnostics.push(Diagnostic::new( + TooManyBooleanExpressions { + expressions, + max_expressions: checker.settings.pylint.max_bool_expr, + }, + bool_op.range(), + )); + } + } + + for elif in &stmt.elif_else_clauses { + if let Some(bool_op) = elif.test.as_ref().and_then(Expr::as_bool_op_expr) { + let expressions = count_bools(bool_op); + if expressions > checker.settings.pylint.max_bool_expr { + checker.diagnostics.push(Diagnostic::new( + TooManyBooleanExpressions { + expressions, + max_expressions: checker.settings.pylint.max_bool_expr, + }, + bool_op.range(), + )); + } + } + } +} + +/// Count the number of Boolean expressions in a `bool_op` expression. +fn count_bools(bool_op: &ast::ExprBoolOp) -> usize { + bool_op + .values + .iter() + .map(|expr| { + if let Expr::BoolOp(bool_op) = expr { + count_bools(bool_op) + } else { + 1 + } + }) + .sum::() +} diff --git a/crates/ruff_linter/src/rules/pylint/settings.rs b/crates/ruff_linter/src/rules/pylint/settings.rs index e09e4835f8279..3ad2892c0e54c 100644 --- a/crates/ruff_linter/src/rules/pylint/settings.rs +++ b/crates/ruff_linter/src/rules/pylint/settings.rs @@ -40,6 +40,7 @@ pub struct Settings { pub allow_magic_value_types: Vec, pub max_args: usize, pub max_returns: usize, + pub max_bool_expr: usize, pub max_branches: usize, pub max_statements: usize, pub max_public_methods: usize, @@ -51,6 +52,7 @@ impl Default for Settings { allow_magic_value_types: vec![ConstantType::Str, ConstantType::Bytes], max_args: 5, max_returns: 6, + max_bool_expr: 5, max_branches: 12, max_statements: 50, max_public_methods: 20, diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_boolean_expressions.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_boolean_expressions.snap new file mode 100644 index 0000000000000..141ee9e4c5c2b --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_boolean_expressions.snap @@ -0,0 +1,214 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +too_many_boolean_expressions.py:11:6: PLR0916 Too many Boolean expressions (6 > 5) + | + 9 | elif (a and b) and c and d and e: +10 | ... +11 | elif (a and b) and c and d and e and f: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +12 | ... +13 | elif (a and b) and c and d and e and f and g: + | + +too_many_boolean_expressions.py:13:6: PLR0916 Too many Boolean expressions (7 > 5) + | +11 | elif (a and b) and c and d and e and f: +12 | ... +13 | elif (a and b) and c and d and e and f and g: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +14 | ... +15 | elif (a and b) and c and d and e and f and g and h: + | + +too_many_boolean_expressions.py:15:6: PLR0916 Too many Boolean expressions (8 > 5) + | +13 | elif (a and b) and c and d and e and f and g: +14 | ... +15 | elif (a and b) and c and d and e and f and g and h: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +16 | ... +17 | elif (a and b) and c and d and e and f and g and h and i: + | + +too_many_boolean_expressions.py:17:6: PLR0916 Too many Boolean expressions (9 > 5) + | +15 | elif (a and b) and c and d and e and f and g and h: +16 | ... +17 | elif (a and b) and c and d and e and f and g and h and i: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +18 | ... +19 | elif (a and b) and c and d and e and f and g and h and i and j: + | + +too_many_boolean_expressions.py:19:6: PLR0916 Too many Boolean expressions (10 > 5) + | +17 | elif (a and b) and c and d and e and f and g and h and i: +18 | ... +19 | elif (a and b) and c and d and e and f and g and h and i and j: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +20 | ... +21 | elif (a and b) and c and d and e and f and g and h and i and j and k: + | + +too_many_boolean_expressions.py:21:6: PLR0916 Too many Boolean expressions (11 > 5) + | +19 | elif (a and b) and c and d and e and f and g and h and i and j: +20 | ... +21 | elif (a and b) and c and d and e and f and g and h and i and j and k: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +22 | ... +23 | elif (a and b) and c and d and e and f and g and h and i and j and k and l: + | + +too_many_boolean_expressions.py:23:6: PLR0916 Too many Boolean expressions (12 > 5) + | +21 | elif (a and b) and c and d and e and f and g and h and i and j and k: +22 | ... +23 | elif (a and b) and c and d and e and f and g and h and i and j and k and l: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +24 | ... +25 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m: + | + +too_many_boolean_expressions.py:25:6: PLR0916 Too many Boolean expressions (13 > 5) + | +23 | elif (a and b) and c and d and e and f and g and h and i and j and k and l: +24 | ... +25 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +26 | ... +27 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n: + | + +too_many_boolean_expressions.py:27:6: PLR0916 Too many Boolean expressions (14 > 5) + | +25 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m: +26 | ... +27 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +28 | ... +29 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o: + | + +too_many_boolean_expressions.py:29:6: PLR0916 Too many Boolean expressions (15 > 5) + | +27 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n: +28 | ... +29 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +30 | ... +31 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p: + | + +too_many_boolean_expressions.py:31:6: PLR0916 Too many Boolean expressions (16 > 5) + | +29 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o: +30 | ... +31 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +32 | ... +33 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q: + | + +too_many_boolean_expressions.py:33:6: PLR0916 Too many Boolean expressions (17 > 5) + | +31 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p: +32 | ... +33 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +34 | ... +35 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r: + | + +too_many_boolean_expressions.py:35:6: PLR0916 Too many Boolean expressions (18 > 5) + | +33 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q: +34 | ... +35 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +36 | ... +37 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s: + | + +too_many_boolean_expressions.py:37:6: PLR0916 Too many Boolean expressions (19 > 5) + | +35 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r: +36 | ... +37 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +38 | ... +39 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t: + | + +too_many_boolean_expressions.py:39:6: PLR0916 Too many Boolean expressions (20 > 5) + | +37 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s: +38 | ... +39 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +40 | ... +41 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u: + | + +too_many_boolean_expressions.py:41:6: PLR0916 Too many Boolean expressions (21 > 5) + | +39 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t: +40 | ... +41 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +42 | ... +43 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v: + | + +too_many_boolean_expressions.py:43:6: PLR0916 Too many Boolean expressions (22 > 5) + | +41 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u: +42 | ... +43 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +44 | ... +45 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w: + | + +too_many_boolean_expressions.py:45:6: PLR0916 Too many Boolean expressions (23 > 5) + | +43 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v: +44 | ... +45 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +46 | ... +47 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x: + | + +too_many_boolean_expressions.py:47:6: PLR0916 Too many Boolean expressions (24 > 5) + | +45 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w: +46 | ... +47 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +48 | ... +49 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y: + | + +too_many_boolean_expressions.py:49:6: PLR0916 Too many Boolean expressions (25 > 5) + | +47 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x: +48 | ... +49 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +50 | ... +51 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y and z: + | + +too_many_boolean_expressions.py:51:6: PLR0916 Too many Boolean expressions (26 > 5) + | +49 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y: +50 | ... +51 | elif (a and b) and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w and x and y and z: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR0916 +52 | ... +53 | else: + | + + diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 409e50f9fb75d..eaf1cd22fe058 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2379,6 +2379,11 @@ pub struct PylintOptions { example = r"max-public-methods = 20" )] pub max_public_methods: Option, + + /// Maximum number of Boolean expressions allowed within a single `if` statement + /// (see: `PLR0916`). + #[option(default = r"5", value_type = "int", example = r"max-bool-expr = 5")] + pub max_bool_expr: Option, } impl PylintOptions { @@ -2389,6 +2394,7 @@ impl PylintOptions { .allow_magic_value_types .unwrap_or(defaults.allow_magic_value_types), max_args: self.max_args.unwrap_or(defaults.max_args), + max_bool_expr: self.max_bool_expr.unwrap_or(defaults.max_bool_expr), max_returns: self.max_returns.unwrap_or(defaults.max_returns), max_branches: self.max_branches.unwrap_or(defaults.max_branches), max_statements: self.max_statements.unwrap_or(defaults.max_statements), diff --git a/ruff.schema.json b/ruff.schema.json index 9c5e70507bc4d..1c49b5838559d 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2214,6 +2214,15 @@ "format": "uint", "minimum": 0.0 }, + "max-bool-expr": { + "description": "Maximum number of Boolean expressions allowed within a single `if` statement (see: `PLR0916`).", + "type": [ + "integer", + "null" + ], + "format": "uint", + "minimum": 0.0 + }, "max-branches": { "description": "Maximum number of branches allowed for a function or method body (see: `PLR0912`).", "type": [ @@ -2949,6 +2958,7 @@ "PLR0912", "PLR0913", "PLR0915", + "PLR0916", "PLR1", "PLR17", "PLR170", diff --git a/scripts/check_docs_formatted.py b/scripts/check_docs_formatted.py index b1d09ab068676..78334cc3b5f9a 100755 --- a/scripts/check_docs_formatted.py +++ b/scripts/check_docs_formatted.py @@ -68,6 +68,7 @@ "surrounding-whitespace", "tab-indentation", "too-few-spaces-before-inline-comment", + "too-many-boolean-expressions", "trailing-comma-on-bare-tuple", "triple-single-quotes", "under-indentation",