Skip to content

Commit 01c6438

Browse files
committed
Indent lambda parameters if parameters wrap
1 parent 9f30ccc commit 01c6438

7 files changed

Lines changed: 99 additions & 87 deletions

File tree

crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,5 @@ def f(
203203
y:
204204
z
205205
)
206+
207+
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d

crates/ruff_python_formatter/src/comments/placement.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,18 +1805,6 @@ fn handle_lambda_comment<'a>(
18051805
locator: &Locator,
18061806
) -> CommentPlacement<'a> {
18071807
if let Some(parameters) = lambda.parameters.as_deref() {
1808-
// Comments between the `lambda` and the parameters are dangling on the lambda:
1809-
// ```python
1810-
// (
1811-
// lambda # comment
1812-
// x:
1813-
// y
1814-
// )
1815-
// ```
1816-
if comment.start() < parameters.start() {
1817-
return CommentPlacement::dangling(comment.enclosing_node(), comment);
1818-
}
1819-
18201808
// Comments between the parameters and the body are dangling on the lambda:
18211809
// ```python
18221810
// (

crates/ruff_python_formatter/src/expression/expr_lambda.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use ruff_python_ast::AnyNodeRef;
33
use ruff_python_ast::ExprLambda;
44
use ruff_text_size::Ranged;
55

6+
use crate::builders::parenthesize_if_expands;
67
use crate::comments::{dangling_comments, SourceComment};
7-
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
8+
use crate::expression::has_own_parentheses;
9+
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parentheses};
810
use crate::other::parameters::ParametersParentheses;
911
use crate::prelude::*;
1012

@@ -25,7 +27,7 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
2527
write!(f, [token("lambda")])?;
2628

2729
if let Some(parameters) = parameters {
28-
// In this context, a dangling comment can either be a comment between the `lambda` the
30+
// In this context, a dangling comment can either be a comment between the `lambda` and the
2931
// parameters, or a comment between the parameters and the body.
3032
let (dangling_before_parameters, dangling_after_parameters) = dangling
3133
.split_at(dangling.partition_point(|comment| comment.end() < parameters.start()));
@@ -36,20 +38,30 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
3638
write!(f, [dangling_comments(dangling_before_parameters)])?;
3739
}
3840

39-
write!(
40-
f,
41-
[parameters
42-
.format()
43-
.with_options(ParametersParentheses::Never)]
44-
)?;
41+
group(&format_with(|f: &mut PyFormatter| {
42+
if f.context().node_level().is_parenthesized() {
43+
soft_block_indent(
44+
&parameters
45+
.format()
46+
.with_options(ParametersParentheses::Never),
47+
)
48+
.fmt(f)
49+
} else {
50+
parameters
51+
.format()
52+
.with_options(ParametersParentheses::Never)
53+
.fmt(f)
54+
}?;
4555

46-
write!(f, [token(":")])?;
56+
token(":").fmt(f)?;
4757

48-
if dangling_after_parameters.is_empty() {
49-
write!(f, [space()])?;
50-
} else {
51-
write!(f, [dangling_comments(dangling_after_parameters)])?;
52-
}
58+
if dangling_after_parameters.is_empty() {
59+
space().fmt(f)
60+
} else {
61+
dangling_comments(dangling_after_parameters).fmt(f)
62+
}
63+
}))
64+
.fmt(f)?;
5365
} else {
5466
write!(f, [token(":")])?;
5567

@@ -61,7 +73,13 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
6173
}
6274
}
6375

64-
write!(f, [body.format()])
76+
if has_own_parentheses(body, f.context()).is_some()
77+
|| body.needs_parentheses(item.into(), f.context()) == OptionalParentheses::Always
78+
{
79+
body.format().fmt(f)
80+
} else {
81+
parenthesize_if_expands(&body.format().with_options(Parentheses::Never)).fmt(f)
82+
}
6583
}
6684

6785
fn fmt_dangling_comments(

crates/ruff_python_formatter/src/expression/expr_named_expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl NeedsParentheses for ExprNamedExpr {
6969
|| parent.is_stmt_delete()
7070
|| parent.is_stmt_for()
7171
|| parent.is_stmt_function_def()
72+
|| parent.is_expr_lambda()
7273
{
7374
OptionalParentheses::Always
7475
} else {

crates/ruff_python_formatter/src/lib.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,7 @@ if True:
206206
#[test]
207207
fn quick_test() {
208208
let source = r#"
209-
def main() -> None:
210-
if True:
211-
some_very_long_variable_name_abcdefghijk = Foo()
212-
some_very_long_variable_name_abcdefghijk = some_very_long_variable_name_abcdefghijk[
213-
some_very_long_variable_name_abcdefghijk.some_very_long_attribute_name
214-
== "This is a very long string abcdefghijk"
215-
]
216-
209+
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d
217210
"#;
218211
let source_type = PySourceType::Python;
219212
let (tokens, comment_ranges) = tokens_and_ranges(source, source_type).unwrap();

crates/ruff_python_formatter/src/other/parameters.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,15 @@ impl FormatNodeRule<Parameters> for FormatParameters {
102102
dangling.split_at(parenthesis_comments_end);
103103

104104
let format_inner = format_with(|f: &mut PyFormatter| {
105-
let separator = format_with(|f| write!(f, [token(","), soft_line_break_or_space()]));
105+
let separator = format_with(|f: &mut PyFormatter| {
106+
token(",").fmt(f)?;
107+
108+
if f.context().node_level().is_parenthesized() {
109+
soft_line_break_or_space().fmt(f)
110+
} else {
111+
space().fmt(f)
112+
}
113+
});
106114
let mut joiner = f.join_with(separator);
107115
let mut last_node: Option<AnyNodeRef> = None;
108116

@@ -232,20 +240,21 @@ impl FormatNodeRule<Parameters> for FormatParameters {
232240
Ok(())
233241
});
234242

235-
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
236-
237243
let num_parameters = posonlyargs.len()
238244
+ args.len()
239245
+ usize::from(vararg.is_some())
240246
+ kwonlyargs.len()
241247
+ usize::from(kwarg.is_some());
242248

243249
if self.parentheses == ParametersParentheses::Never {
244-
write!(f, [group(&format_inner), dangling_comments(dangling)])
250+
write!(f, [format_inner, dangling_comments(dangling)])
245251
} else if num_parameters == 0 {
252+
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
246253
// No parameters, format any dangling comments between `()`
247254
write!(f, [empty_parenthesized("(", dangling, ")")])
248255
} else {
256+
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
257+
249258
// Intentionally avoid `parenthesized`, which groups the entire formatted contents.
250259
// We want parameters to be grouped alongside return types, one level up, so we
251260
// format them "inline" here.

crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ lambda: ( # comment
209209
y:
210210
z
211211
)
212+
213+
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d
212214
```
213215

214216
## Output
@@ -242,30 +244,10 @@ lambda x: lambda y: lambda z: (x, y, z) # Trailing
242244
# Trailing
243245
244246
# Leading
245-
lambda x: lambda y: lambda z: (
246-
x,
247-
y,
248-
y,
249-
y,
250-
y,
251-
y,
252-
y,
253-
y,
254-
y,
255-
y,
256-
y,
257-
y,
258-
y,
259-
y,
260-
y,
261-
y,
262-
y,
263-
y,
264-
y,
265-
y,
266-
y,
267-
y,
268-
z,
247+
lambda x: (
248+
lambda y: (
249+
lambda z: (x, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, z)
250+
)
269251
) # Trailing
270252
# Trailing
271253
@@ -275,8 +257,10 @@ a = (
275257
)
276258
277259
a = (
278-
lambda x, # Dangling
279-
y: 1
260+
lambda
261+
x, # Dangling
262+
y
263+
: 1
280264
)
281265
282266
# Regression test: lambda empty arguments ranges were too long, leading to unstable
@@ -289,7 +273,9 @@ a = (
289273
290274
# lambda arguments don't have parentheses, so we never add a magic trailing comma ...
291275
def f(
292-
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = lambda x: y,
276+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = lambda
277+
x
278+
: y,
293279
):
294280
pass
295281
@@ -336,36 +322,42 @@ lambda a, /, c: a
336322
)
337323
338324
(
339-
lambda
340-
# comment
341-
*x: x
325+
lambda
326+
# comment
327+
*x
328+
: x
342329
)
343330
344331
(
345-
lambda
346-
# comment 1
347-
# comment 2
348-
*x:
332+
lambda
333+
# comment 1
334+
# comment 2
335+
*x
336+
:
349337
# comment 3
350338
x
351339
)
352340
353341
(
354-
lambda # comment 1
355-
# comment 2
356-
*x: # comment 3
342+
lambda
343+
# comment 1
344+
# comment 2
345+
*x
346+
: # comment 3
357347
x
358348
)
359349
360350
lambda *x: x
361351
362352
(
363-
lambda
364-
# comment
365-
*x: x
353+
lambda
354+
# comment
355+
*x
356+
: x
366357
)
367358
368-
lambda: ( # comment
359+
lambda: (
360+
# comment
369361
x
370362
)
371363
@@ -393,26 +385,35 @@ lambda: ( # comment
393385
394386
(
395387
lambda: # comment
396-
( # comment
388+
(
389+
# comment
397390
x
398391
)
399392
)
400393
401394
(
402-
lambda # 1
403-
# 2
404-
x: # 3
395+
lambda
396+
# 1
397+
# 2
398+
x
399+
: # 3
405400
# 4
406401
# 5
407402
# 6
408403
x
409404
)
410405
411406
(
412-
lambda x,
413-
# comment
414-
y: z
407+
lambda
408+
x,
409+
# comment
410+
y
411+
: z
415412
)
413+
414+
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
415+
*args, **kwargs
416+
), e=1, f=2, g=2: d
416417
```
417418

418419

0 commit comments

Comments
 (0)