Avoid false-positives for parens-on-raise with futures.exception() (#10206)

## Summary

As a heuristic, we now ignore function calls that "look like" method
calls (e.g., `future.exception()`).

Closes https://github.com/astral-sh/ruff/issues/10205.
This commit is contained in:
Charlie Marsh 2024-03-02 16:28:51 -08:00 committed by GitHub
parent 7515196245
commit ba7f6783e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 6 deletions

View file

@ -93,3 +93,15 @@ def func():
# OK
raise func()
# OK
future = executor.submit(float, "a")
if future.exception():
raise future.exception()
# RSE102
future = executor.submit(float, "a")
if future.exception():
raise future.Exception()

View file

@ -76,16 +76,35 @@ pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr:
None
};
if exception_type.is_none() {
// If the method name doesn't _look_ like a class (i.e., it's lowercase), it's
// probably a function call, not a class.
let identifier = match func.as_ref() {
Expr::Name(ast::ExprName { id, .. }) => Some(id.as_str()),
Expr::Attribute(ast::ExprAttribute { attr, .. }) => Some(attr.as_str()),
_ => None,
};
if identifier.is_some_and(|identifier| {
identifier
.strip_prefix('_')
.unwrap_or(identifier)
.chars()
.next()
.is_some_and(char::is_lowercase)
}) {
return;
}
// `ctypes.WinError()` is a function, not a class. It's part of the standard library, so
// we might as well get it right.
if exception_type.is_none()
&& checker
if checker
.semantic()
.resolve_call_path(func)
.is_some_and(|call_path| matches!(call_path.as_slice(), ["ctypes", "WinError"]))
{
return;
}
}
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, arguments.range());

View file

@ -281,4 +281,18 @@ RSE102.py:84:10: RSE102 [*] Unnecessary parentheses on raised exception
86 86 | # OK
87 87 | raise ctypes.WinError()
RSE102.py:107:27: RSE102 [*] Unnecessary parentheses on raised exception
|
105 | future = executor.submit(float, "a")
106 | if future.exception():
107 | raise future.Exception()
| ^^ RSE102
|
= help: Remove unnecessary parentheses
Unsafe fix
104 104 | # RSE102
105 105 | future = executor.submit(float, "a")
106 106 | if future.exception():
107 |- raise future.Exception()
107 |+ raise future.Exception