Supported starred exceptions in length-one tuple detection (#7080)

This commit is contained in:
Charlie Marsh 2023-09-03 14:31:13 +01:00 committed by GitHub
parent b70dde4a77
commit b0d171ac19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 17 deletions

View file

@ -1,3 +1,5 @@
retriable_exceptions = (FileExistsError, FileNotFoundError)
try:
pass
except (ValueError,):
@ -6,3 +8,5 @@ except AttributeError:
pass
except (ImportError, TypeError):
pass
except (*retriable_exceptions,):
pass

View file

@ -2,6 +2,7 @@ use ruff_python_ast::{self as ast, ExceptHandler, Expr};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::map_starred;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
@ -41,11 +42,7 @@ pub struct RedundantTupleInExceptionHandler {
impl AlwaysAutofixableViolation for RedundantTupleInExceptionHandler {
#[derive_message_formats]
fn message(&self) -> String {
let RedundantTupleInExceptionHandler { name } = self;
format!(
"A length-one tuple literal is redundant. Write `except {name}` instead of `except \
({name},)`."
)
format!("A length-one tuple literal is redundant in exception handlers")
}
fn autofix_title(&self) -> String {
@ -70,9 +67,10 @@ pub(crate) fn redundant_tuple_in_exception_handler(
let Expr::Tuple(ast::ExprTuple { elts, .. }) = type_.as_ref() else {
continue;
};
let [elt] = &elts[..] else {
let [elt] = elts.as_slice() else {
continue;
};
let elt = map_starred(elt);
let mut diagnostic = Diagnostic::new(
RedundantTupleInExceptionHandler {
name: checker.generator().expr(elt),

View file

@ -1,24 +1,43 @@
---
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
---
B013.py:3:8: B013 [*] A length-one tuple literal is redundant. Write `except ValueError` instead of `except (ValueError,)`.
B013.py:5:8: B013 [*] A length-one tuple literal is redundant in exception handlers
|
1 | try:
2 | pass
3 | except (ValueError,):
| ^^^^^^^^^^^^^ B013
3 | try:
4 | pass
5 | except AttributeError:
5 | except (ValueError,):
| ^^^^^^^^^^^^^ B013
6 | pass
7 | except AttributeError:
|
= help: Replace with `except ValueError`
Fix
1 1 | try:
2 2 | pass
3 |-except (ValueError,):
3 |+except ValueError:
2 2 |
3 3 | try:
4 4 | pass
5 5 | except AttributeError:
5 |-except (ValueError,):
5 |+except ValueError:
6 6 | pass
7 7 | except AttributeError:
8 8 | pass
B013.py:11:8: B013 [*] A length-one tuple literal is redundant in exception handlers
|
9 | except (ImportError, TypeError):
10 | pass
11 | except (*retriable_exceptions,):
| ^^^^^^^^^^^^^^^^^^^^^^^^ B013
12 | pass
|
= help: Replace with `except retriable_exceptions`
Fix
8 8 | pass
9 9 | except (ImportError, TypeError):
10 10 | pass
11 |-except (*retriable_exceptions,):
11 |+except retriable_exceptions:
12 12 | pass

View file

@ -653,6 +653,17 @@ pub fn map_subscript(expr: &Expr) -> &Expr {
}
}
/// Given an [`Expr`] that can be starred, return the underlying starred expression.
pub fn map_starred(expr: &Expr) -> &Expr {
if let Expr::Starred(ast::ExprStarred { value, .. }) = expr {
// Ex) `*args`
value
} else {
// Ex) `args`
expr
}
}
/// Return `true` if the body uses `locals()`, `globals()`, `vars()`, `eval()`.
///
/// Accepts a closure that determines whether a given name (e.g., `"list"`) is a Python builtin.