Respect parentheses for precedence in await (#7468)

## Summary

We were using `Parenthesize::IfBreaks` universally for `await`, but
dropping parentheses can change the AST due to precedence. It turns out
that Black's rules aren't _exactly_ the same as operator precedence
(e.g., they leave parentheses around `await ([1, 2, 3])`, although they
aren't strictly required).

Closes https://github.com/astral-sh/ruff/issues/7467.

## Test Plan

`cargo test`

No change in similarity.

Before:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99982 | 2760 | 37 |
| transformers | 0.99957 | 2587 | 398 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99983 | 3496 | 18 |
| warehouse | 0.99929 | 648 | 16 |
| zulip | 0.99962 | 1437 | 22 |

After:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99982 | 2760 | 37 |
| transformers | 0.99957 | 2587 | 398 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99983 | 3496 | 18 |
| warehouse | 0.99929 | 648 | 16 |
| zulip | 0.99962 | 1437 | 22 |
This commit is contained in:
Charlie Marsh 2023-09-18 09:56:41 -04:00 committed by GitHub
parent c4d85d6fb6
commit 8ab2519717
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 165 additions and 14 deletions

View file

@ -31,10 +31,12 @@ impl FormatNodeRule<ExprCompare> for FormatExprCompare {
impl NeedsParentheses for ExprCompare {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
if let Expr::Constant(constant) = self.left.as_ref() {
if parent.is_expr_await() {
OptionalParentheses::Always
} else if let Expr::Constant(constant) = self.left.as_ref() {
// Multiline strings are guaranteed to never fit, avoid adding unnecessary parentheses
if !constant.value.is_implicit_concatenated()
&& is_multiline_string(constant, context.source())