diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM105_0.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM105_0.py index 7d63806c61..a893af9add 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM105_0.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM105_0.py @@ -128,3 +128,16 @@ def write_models(directory, Models): pass; \ \ # + +# Regression tests for: https://github.com/astral-sh/ruff/issues/18209 +try: + 1 / 0 +except (): + pass + + +BaseException = ValueError +try: + int("a") +except BaseException: + pass \ No newline at end of file diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/suppressible_exception.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/suppressible_exception.rs index 1d01784e80..34c4915f3b 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/suppressible_exception.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/suppressible_exception.rs @@ -102,8 +102,11 @@ pub(crate) fn suppressible_exception( return; } - let [ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { body, range, .. })] = - handlers + let [ + ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { + body, range, type_, .. + }), + ] = handlers else { return; }; @@ -121,7 +124,13 @@ pub(crate) fn suppressible_exception( }; let exception = if handler_names.is_empty() { - "Exception".to_string() + if type_.is_none() { + // case where there are no handler names provided at all + "BaseException".to_string() + } else { + // case where handler names is an empty tuple + String::new() + } } else { handler_names.join(", ") }; @@ -142,15 +151,29 @@ pub(crate) fn suppressible_exception( stmt.start(), checker.semantic(), )?; - let replace_try = Edit::range_replacement( - format!("with {binding}({exception})"), + let mut rest: Vec = Vec::new(); + let content: String; + if exception == "BaseException" && handler_names.is_empty() { + let (import_exception, binding_exception) = + checker.importer().get_or_import_symbol( + &ImportRequest::import("builtins", &exception), + stmt.start(), + checker.semantic(), + )?; + content = format!("with {binding}({binding_exception})"); + rest.push(import_exception); + } else { + content = format!("with {binding}({exception})"); + } + rest.push(Edit::range_deletion( + checker.locator().full_lines_range(*range), + )); + rest.push(Edit::range_replacement( + content, TextRange::at(stmt.start(), "try".text_len()), - ); - let remove_handler = Edit::range_deletion(checker.locator().full_lines_range(*range)); - Ok(Fix::unsafe_edits( - import_edit, - [replace_try, remove_handler], - )) + )); + + Ok(Fix::unsafe_edits(import_edit, rest)) }); } } diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM105_SIM105_0.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM105_SIM105_0.py.snap index da95917f8a..c4fe31837c 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM105_SIM105_0.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM105_SIM105_0.py.snap @@ -90,7 +90,7 @@ SIM105_0.py:19:1: SIM105 [*] Use `contextlib.suppress(ValueError, OSError)` inst 24 23 | # SIM105 25 24 | try: -SIM105_0.py:25:1: SIM105 [*] Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass` +SIM105_0.py:25:1: SIM105 [*] Use `contextlib.suppress(BaseException)` instead of `try`-`except`-`pass` | 24 | # SIM105 25 | / try: @@ -101,25 +101,26 @@ SIM105_0.py:25:1: SIM105 [*] Use `contextlib.suppress(Exception)` instead of `tr 29 | 30 | # SIM105 | - = help: Replace with `contextlib.suppress(Exception)` + = help: Replace with `contextlib.suppress(BaseException)` ℹ Unsafe fix 1 |+import contextlib -1 2 | def foo(): -2 3 | pass -3 4 | + 2 |+import builtins +1 3 | def foo(): +2 4 | pass +3 5 | -------------------------------------------------------------------------------- -22 23 | pass -23 24 | -24 25 | # SIM105 +22 24 | pass +23 25 | +24 26 | # SIM105 25 |-try: - 26 |+with contextlib.suppress(Exception): -26 27 | foo() + 27 |+with contextlib.suppress(builtins.BaseException): +26 28 | foo() 27 |-except: 28 |- pass -29 28 | -30 29 | # SIM105 -31 30 | try: +29 29 | +30 30 | # SIM105 +31 31 | try: SIM105_0.py:31:1: SIM105 [*] Use `contextlib.suppress(a.Error, b.Error)` instead of `try`-`except`-`pass` | @@ -285,3 +286,59 @@ SIM105_0.py:126:5: SIM105 [*] Use `contextlib.suppress(OSError)` instead of `try 127 |+ with contextlib.suppress(OSError): os.makedirs(model_dir); 129 128 | \ 130 129 | # +131 130 | + +SIM105_0.py:133:1: SIM105 [*] Use `contextlib.suppress()` instead of `try`-`except`-`pass` + | +132 | # Regression tests for: https://github.com/astral-sh/ruff/issues/18209 +133 | / try: +134 | | 1 / 0 +135 | | except (): +136 | | pass + | |________^ SIM105 + | + = help: Replace with `contextlib.suppress()` + +ℹ Unsafe fix + 1 |+import contextlib +1 2 | def foo(): +2 3 | pass +3 4 | +-------------------------------------------------------------------------------- +130 131 | # +131 132 | +132 133 | # Regression tests for: https://github.com/astral-sh/ruff/issues/18209 +133 |-try: + 134 |+with contextlib.suppress(): +134 135 | 1 / 0 +135 |-except (): +136 |- pass +137 136 | +138 137 | +139 138 | BaseException = ValueError + +SIM105_0.py:140:1: SIM105 [*] Use `contextlib.suppress(BaseException)` instead of `try`-`except`-`pass` + | +139 | BaseException = ValueError +140 | / try: +141 | | int("a") +142 | | except BaseException: +143 | | pass + | |________^ SIM105 + | + = help: Replace with `contextlib.suppress(BaseException)` + +ℹ Unsafe fix + 1 |+import contextlib +1 2 | def foo(): +2 3 | pass +3 4 | +-------------------------------------------------------------------------------- +137 138 | +138 139 | +139 140 | BaseException = ValueError +140 |-try: + 141 |+with contextlib.suppress(BaseException): +141 142 | int("a") +142 |-except BaseException: +143 |- pass