diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B013.py b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B013.py index bb28f08220..4b505ed58f 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B013.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B013.py @@ -18,4 +18,12 @@ list_exceptions = [FileExistsError, FileNotFoundError] try: pass except (*list_exceptions,): - pass \ No newline at end of file + pass + +try: + ... +except ( + ValueError, + # text + ): + ... \ No newline at end of file diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/redundant_tuple_in_exception_handler.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/redundant_tuple_in_exception_handler.rs index 2ace373d4e..cd98dbc7a3 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/redundant_tuple_in_exception_handler.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/redundant_tuple_in_exception_handler.rs @@ -1,3 +1,4 @@ +use ruff_diagnostics::Applicability; use ruff_macros::{ViolationMetadata, derive_message_formats}; use ruff_python_ast::{self as ast, ExceptHandler, Expr}; use ruff_text_size::Ranged; @@ -33,6 +34,9 @@ use crate::{AlwaysFixableViolation, Edit, Fix}; /// ... /// ``` /// +/// ## Fix safety +/// This rule's fix is marked as safe, unless the exception handler contains comments. +/// /// ## References /// - [Python documentation: `except` clause](https://docs.python.org/3/reference/compound_stmts.html#except-clause) #[derive(ViolationMetadata)] @@ -86,6 +90,13 @@ pub(crate) fn redundant_tuple_in_exception_handler(checker: &Checker, handlers: }, type_.range(), ); + + let applicability = if checker.comment_ranges().intersects(type_.range()) { + Applicability::Unsafe + } else { + Applicability::Safe + }; + // If there's no space between the `except` and the tuple, we need to insert a space, // as in: // ```python @@ -93,13 +104,16 @@ pub(crate) fn redundant_tuple_in_exception_handler(checker: &Checker, handlers: // ``` // Otherwise, the output will be invalid syntax, since we're removing a set of // parentheses. - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - pad( - checker.generator().expr(elt), + diagnostic.set_fix(Fix::applicable_edit( + Edit::range_replacement( + pad( + checker.generator().expr(elt), + type_.range(), + checker.locator(), + ), type_.range(), - checker.locator(), ), - type_.range(), - ))); + applicability, + )); } } diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B013_B013.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B013_B013.py.snap index 558df83a88..f286c3f497 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B013_B013.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B013_B013.py.snap @@ -39,3 +39,28 @@ help: Replace with `except ValueError` 14 | pass 15 | 16 | list_exceptions = [FileExistsError, FileNotFoundError] + +B013 [*] A length-one tuple literal is redundant in exception handlers + --> B013.py:25:8 + | +23 | try: +24 | ... +25 | except ( + | ________^ +26 | | ValueError, +27 | | # text +28 | | ): + | |_________^ +29 | ... + | +help: Replace with `except ValueError` +22 | +23 | try: +24 | ... + - except ( + - ValueError, + - # text + - ): +25 + except ValueError: +26 | ... +note: This is an unsafe fix and may change runtime behavior