mirror of
https://github.com/astral-sh/ruff
synced 2026-01-21 13:30:49 -05:00
Preserve required parentheses in lambda bodies (#22747)
Summary -- This PR fixes the issues revealed in #22744 by adding an additional branch to the lambda body formatting that checks if the body `needs_parentheses` before falling back on the `Parentheses::Never` case. I also updated the `ExprNamed::needs_parentheses` implementation to match the one from #8465. Test Plan -- New test based on the failing cases in #22744. I also checked out #22744 and checked that the tests pass after applying the changes from this PR.
This commit is contained in:
@@ -804,3 +804,12 @@ transform = lambda left, right: ibis.timestamp("2017-04-01").cast(dt.date).betwe
|
||||
x
|
||||
)
|
||||
)
|
||||
|
||||
lambda x: (
|
||||
x := 1
|
||||
)
|
||||
|
||||
(
|
||||
lambda # dangling header comment
|
||||
: (x := 1)
|
||||
)
|
||||
|
||||
@@ -145,6 +145,7 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
|
||||
let fmt_body = FormatBody {
|
||||
body,
|
||||
dangling_header_comments,
|
||||
needs_parentheses: body.needs_parentheses(item.into(), f.context()),
|
||||
};
|
||||
|
||||
match self.layout {
|
||||
@@ -262,6 +263,7 @@ struct FormatBody<'a> {
|
||||
/// )
|
||||
/// ```
|
||||
dangling_header_comments: &'a [SourceComment],
|
||||
needs_parentheses: OptionalParentheses,
|
||||
}
|
||||
|
||||
impl Format<PyFormatContext<'_>> for FormatBody<'_> {
|
||||
@@ -269,6 +271,7 @@ impl Format<PyFormatContext<'_>> for FormatBody<'_> {
|
||||
let FormatBody {
|
||||
dangling_header_comments,
|
||||
body,
|
||||
needs_parentheses,
|
||||
} = self;
|
||||
|
||||
let body = *body;
|
||||
@@ -438,6 +441,14 @@ impl Format<PyFormatContext<'_>> for FormatBody<'_> {
|
||||
else if has_own_parentheses(body, f.context()).is_some() {
|
||||
body.format().fmt(f)
|
||||
}
|
||||
// Include parentheses for cases that always require them, such as named expressions:
|
||||
//
|
||||
// ```py
|
||||
// lambda x: (y := x + 1)
|
||||
// ```
|
||||
else if matches!(needs_parentheses, OptionalParentheses::Always) {
|
||||
body.format().with_options(Parentheses::Always).fmt(f)
|
||||
}
|
||||
// Finally, for expressions without their own parentheses, use
|
||||
// `parenthesize_if_expands` to add parentheses around the body, only if it expands
|
||||
// across multiple lines. The `Parentheses::Never` here also removes unnecessary
|
||||
|
||||
@@ -66,6 +66,7 @@ impl NeedsParentheses for ExprNamed {
|
||||
|| parent.is_stmt_delete()
|
||||
|| parent.is_stmt_for()
|
||||
|| parent.is_stmt_function_def()
|
||||
|| parent.is_expr_lambda()
|
||||
{
|
||||
OptionalParentheses::Always
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py
|
||||
---
|
||||
## Input
|
||||
```python
|
||||
@@ -810,6 +809,15 @@ transform = lambda left, right: ibis.timestamp("2017-04-01").cast(dt.date).betwe
|
||||
x
|
||||
)
|
||||
)
|
||||
|
||||
lambda x: (
|
||||
x := 1
|
||||
)
|
||||
|
||||
(
|
||||
lambda # dangling header comment
|
||||
: (x := 1)
|
||||
)
|
||||
```
|
||||
|
||||
## Output
|
||||
@@ -1649,6 +1657,13 @@ transform = (
|
||||
x
|
||||
)
|
||||
)
|
||||
|
||||
lambda x: (x := 1)
|
||||
|
||||
(
|
||||
lambda: # dangling header comment
|
||||
(x := 1)
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
@@ -2567,4 +2582,14 @@ transform = (
|
||||
x
|
||||
)
|
||||
)
|
||||
@@ -837,6 +854,7 @@
|
||||
lambda x: (x := 1)
|
||||
|
||||
(
|
||||
- lambda: # dangling header comment
|
||||
- (x := 1)
|
||||
+ lambda: ( # dangling header comment
|
||||
+ x := 1
|
||||
+ )
|
||||
)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user