diff --git a/crates/ruff_python_formatter/README.md b/crates/ruff_python_formatter/README.md index 37e96c8a61..688a784042 100644 --- a/crates/ruff_python_formatter/README.md +++ b/crates/ruff_python_formatter/README.md @@ -305,3 +305,21 @@ import os import sys ``` + +### Parentheses around awaited collections are not preserved + +Black preserves parentheses around awaited collections: + +```python +await ([1, 2, 3]) +``` + +Ruff will instead remove them: + +```python +await [1, 2, 3] +``` + +This is more consistent to the formatting of other awaited expressions: Ruff and Black both +remove parentheses around, e.g., `await (1)`, only retaining them when syntactically required, +as in, e.g., `await (x := 1)`. diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/await.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/await.py index f5319a8195..03b7ce38de 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/await.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/await.py @@ -10,3 +10,41 @@ result = await (self.request( result = await (1 + f(1, 2, 3,)) result = (await (1 + f(1, 2, 3,))) + +# Optional parentheses. +await foo +await (foo) +await foo() +await (foo()) +await []() +await ([]()) +await (foo + bar)() +await ((foo + bar)()) +await foo.bar +await (foo.bar) +await foo['bar'] +await (foo['bar']) +await 1 +await (1) +await "" +await ("") +await f"" +await (f"") +await [foo] +await ([foo]) +await {foo} +await ({foo}) +await (lambda foo: foo) +await (foo or bar) +await (foo * bar) +await (yield foo) +await (not foo) +await 1, 2, 3 +await (1, 2, 3) +await ( # comment + [foo] +) +await ( + # comment + [foo] +) diff --git a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs index 8601f6b1df..5402b3e5f5 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs @@ -33,7 +33,7 @@ impl NeedsParentheses for ExprBinOp { parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - if parent.is_expr_await() && !self.op.is_pow() { + 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 diff --git a/crates/ruff_python_formatter/src/expression/expr_bool_op.rs b/crates/ruff_python_formatter/src/expression/expr_bool_op.rs index 27e511dd96..674cfa9334 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bool_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bool_op.rs @@ -19,10 +19,14 @@ impl FormatNodeRule for FormatExprBoolOp { impl NeedsParentheses for ExprBoolOp { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, _context: &PyFormatContext, ) -> OptionalParentheses { - OptionalParentheses::Multiline + if parent.is_expr_await() { + OptionalParentheses::Always + } else { + OptionalParentheses::Multiline + } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_compare.rs b/crates/ruff_python_formatter/src/expression/expr_compare.rs index 8ca05d864a..e3c75e8891 100644 --- a/crates/ruff_python_formatter/src/expression/expr_compare.rs +++ b/crates/ruff_python_formatter/src/expression/expr_compare.rs @@ -31,10 +31,12 @@ impl FormatNodeRule 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()) diff --git a/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs b/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs index 75d2ba2e84..db577e3d3c 100644 --- a/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs @@ -91,10 +91,14 @@ impl FormatNodeRule for FormatExprGeneratorExp { impl NeedsParentheses for ExprGeneratorExp { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, _context: &PyFormatContext, ) -> OptionalParentheses { - OptionalParentheses::Never + if parent.is_expr_await() { + OptionalParentheses::Always + } else { + OptionalParentheses::Never + } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_if_exp.rs b/crates/ruff_python_formatter/src/expression/expr_if_exp.rs index a1b57b3bf3..78853d40d3 100644 --- a/crates/ruff_python_formatter/src/expression/expr_if_exp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_if_exp.rs @@ -85,10 +85,14 @@ impl FormatNodeRule for FormatExprIfExp { impl NeedsParentheses for ExprIfExp { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, _context: &PyFormatContext, ) -> OptionalParentheses { - OptionalParentheses::Multiline + if parent.is_expr_await() { + OptionalParentheses::Always + } else { + OptionalParentheses::Multiline + } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_lambda.rs b/crates/ruff_python_formatter/src/expression/expr_lambda.rs index d2244596e0..3de50e7668 100644 --- a/crates/ruff_python_formatter/src/expression/expr_lambda.rs +++ b/crates/ruff_python_formatter/src/expression/expr_lambda.rs @@ -64,9 +64,13 @@ impl FormatNodeRule for FormatExprLambda { impl NeedsParentheses for ExprLambda { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, _context: &PyFormatContext, ) -> OptionalParentheses { - OptionalParentheses::Multiline + if parent.is_expr_await() { + OptionalParentheses::Always + } else { + OptionalParentheses::Multiline + } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs index 5057a68693..62646e2da8 100644 --- a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs @@ -72,11 +72,12 @@ impl FormatNodeRule for FormatExprUnaryOp { impl NeedsParentheses for ExprUnaryOp { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - // We preserve the parentheses of the operand. It should not be necessary to break this expression. - if is_expression_parenthesized( + if parent.is_expr_await() { + OptionalParentheses::Always + } else if is_expression_parenthesized( self.operand.as_ref().into(), context.comments().ranges(), context.source(), diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__await.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__await.py.snap index c623da8319..f01cb0d85f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__await.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__await.py.snap @@ -16,6 +16,44 @@ result = await (self.request( result = await (1 + f(1, 2, 3,)) result = (await (1 + f(1, 2, 3,))) + +# Optional parentheses. +await foo +await (foo) +await foo() +await (foo()) +await []() +await ([]()) +await (foo + bar)() +await ((foo + bar)()) +await foo.bar +await (foo.bar) +await foo['bar'] +await (foo['bar']) +await 1 +await (1) +await "" +await ("") +await f"" +await (f"") +await [foo] +await ([foo]) +await {foo} +await ({foo}) +await (lambda foo: foo) +await (foo or bar) +await (foo * bar) +await (yield foo) +await (not foo) +await 1, 2, 3 +await (1, 2, 3) +await ( # comment + [foo] +) +await ( + # comment + [foo] +) ``` ## Output @@ -46,6 +84,44 @@ result = await ( 3, ) ) + +# Optional parentheses. +await foo +await foo +await foo() +await foo() +await []() +await []() +await (foo + bar)() +await (foo + bar)() +await foo.bar +await foo.bar +await foo["bar"] +await foo["bar"] +await 1 +await 1 +await "" +await "" +await f"" +await f"" +await [foo] +await [foo] +await {foo} +await {foo} +await (lambda foo: foo) +await (foo or bar) +await (foo * bar) +await (yield foo) +await (not foo) +await 1, 2, 3 +await (1, 2, 3) +await ( # comment + [foo] +) +await ( + # comment + [foo] +) ```