diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B014.py b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B014.py index 8a03e75121c013..99cbd2a2499c55 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B014.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B014.py @@ -76,8 +76,15 @@ class MyError(Exception): pass -# https://github.com/astral-sh/ruff/issues/6412 +# Regression test for: https://github.com/astral-sh/ruff/issues/6412 try: pass except (ValueError, ValueError, TypeError): pass + + +# Regression test for: https://github.com/astral-sh/ruff/issues/7455#issuecomment-1739801758 +try: + pas +except(re.error, re.error): + p diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_exceptions.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_exceptions.rs index ca2702757c636b..3cea4241d6b941 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_exceptions.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_exceptions.rs @@ -10,6 +10,7 @@ use ruff_python_ast::call_path; use ruff_python_ast::call_path::CallPath; use crate::checkers::ast::Checker; +use crate::fix::edits::pad; use crate::registry::{AsRule, Rule}; /// ## What it does @@ -112,6 +113,7 @@ fn type_pattern(elts: Vec<&Expr>) -> Expr { .into() } +/// B014 fn duplicate_handler_exceptions<'a>( checker: &mut Checker, expr: &'a Expr, @@ -146,12 +148,17 @@ fn duplicate_handler_exceptions<'a>( ); if checker.patch(diagnostic.kind.rule()) { diagnostic.set_fix(Fix::automatic(Edit::range_replacement( - if unique_elts.len() == 1 { - checker.generator().expr(unique_elts[0]) - } else { + match unique_elts.as_slice() { + // Single exceptions don't require parentheses, but since we're _removing_ + // parentheses, insert whitespace as needed. + [elt] => pad( + checker.generator().expr(elt), + expr.range(), + checker.locator(), + ), // Multiple exceptions must always be parenthesized. This is done // manually as the generator never parenthesizes lone tuples. - format!("({})", checker.generator().expr(&type_pattern(unique_elts))) + _ => format!("({})", checker.generator().expr(&type_pattern(unique_elts))), }, expr.range(), ))); @@ -163,6 +170,7 @@ fn duplicate_handler_exceptions<'a>( seen } +/// B025 pub(crate) fn duplicate_exceptions(checker: &mut Checker, handlers: &[ExceptHandler]) { let mut seen: FxHashSet = FxHashSet::default(); let mut duplicates: FxHashMap> = FxHashMap::default(); diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B014_B014.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B014_B014.py.snap index 87ececd961267b..75b8d36fc7703d 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B014_B014.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B014_B014.py.snap @@ -75,11 +75,31 @@ B014.py:82:8: B014 [*] Exception handler with duplicate exception: `ValueError` = help: De-duplicate exceptions ℹ Fix -79 79 | # https://github.com/astral-sh/ruff/issues/6412 +79 79 | # Regression test for: https://github.com/astral-sh/ruff/issues/6412 80 80 | try: 81 81 | pass 82 |-except (ValueError, ValueError, TypeError): 82 |+except (ValueError, TypeError): 83 83 | pass +84 84 | +85 85 | + +B014.py:89:7: B014 [*] Exception handler with duplicate exception: `re.error` + | +87 | try: +88 | pas +89 | except(re.error, re.error): + | ^^^^^^^^^^^^^^^^^^^^ B014 +90 | p + | + = help: De-duplicate exceptions + +ℹ Fix +86 86 | # Regression test for: https://github.com/astral-sh/ruff/issues/7455#issuecomment-1739801758 +87 87 | try: +88 88 | pas +89 |-except(re.error, re.error): + 89 |+except re.error: +90 90 | p