Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ def f(
*x: x
)

(
lambda
# comment
*x,
**y: x
)

(
lambda
# comment 1
Expand Down Expand Up @@ -196,6 +203,17 @@ def f(
x
)

(
lambda # 1
# 2
x, # 3
# 4
y
: # 5
# 6
x
)

(
lambda
x,
Expand All @@ -204,6 +222,71 @@ def f(
z
)


# Leading
lambda x: (
lambda y: 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 # Trailing
) # Trailing


# Leading
lambda x: lambda y: lambda z: [
x,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
y,
z
] # Trailing
# Trailing

lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d

# Regression tests for https://github.com/astral-sh/ruff/issues/8179
Expand Down
43 changes: 34 additions & 9 deletions crates/ruff_python_formatter/src/expression/expr_lambda.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use ruff_formatter::RemoveSoftLinesBuffer;
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::ExprLambda;
use ruff_text_size::Ranged;

use crate::comments::dangling_comments;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parenthesize};
use crate::expression::{has_own_parentheses, maybe_parenthesize_expression};
use crate::other::parameters::ParametersParentheses;
use crate::prelude::*;
use crate::preview::is_force_single_line_lambda_parameters_enabled;
use crate::preview::is_parenthesize_lambda_bodies_enabled;

#[derive(Default)]
pub struct FormatExprLambda;
Expand All @@ -26,7 +30,7 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
write!(f, [token("lambda")])?;

if let Some(parameters) = parameters {
// In this context, a dangling comment can either be a comment between the `lambda` the
// In this context, a dangling comment can either be a comment between the `lambda` and the
// parameters, or a comment between the parameters and the body.
let (dangling_before_parameters, dangling_after_parameters) = dangling
.split_at(dangling.partition_point(|comment| comment.end() < parameters.start()));
Expand All @@ -37,12 +41,25 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
write!(f, [dangling_comments(dangling_before_parameters)])?;
}

write!(
f,
[parameters
.format()
.with_options(ParametersParentheses::Never)]
)?;
// Try to keep the parameters on a single line, unless there are intervening comments.
if is_force_single_line_lambda_parameters_enabled(f.context())
&& !comments.contains_comments(parameters.as_ref().into())
{
let mut buffer = RemoveSoftLinesBuffer::new(f);
write!(
buffer,
[parameters
.format()
.with_options(ParametersParentheses::Never)]
)?;
} else {
write!(
f,
[parameters
.format()
.with_options(ParametersParentheses::Never)]
)?;
}

write!(f, [token(":")])?;

Expand All @@ -62,7 +79,15 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
}
}

write!(f, [body.format()])
// Avoid parenthesizing lists, dictionaries, etc.
if is_parenthesize_lambda_bodies_enabled(f.context())
&& has_own_parentheses(body, f.context()).is_none()
{
maybe_parenthesize_expression(body, item, Parenthesize::IfBreaksParenthesizedNested)
.fmt(f)
} else {
body.format().fmt(f)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
16 changes: 16 additions & 0 deletions crates/ruff_python_formatter/src/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,19 @@ pub(crate) const fn is_avoid_parens_for_long_as_captures_enabled(
) -> bool {
context.is_preview()
}

/// Returns `true` if the
/// [`parenthesize_lambda_bodies`](https://github.com/astral-sh/ruff/pull/21385) preview style is
/// enabled.
pub(crate) const fn is_parenthesize_lambda_bodies_enabled(context: &PyFormatContext) -> bool {
context.is_preview()
}

/// Returns `true` if the
/// [`force_single_line_lambda_parameters`](https://github.com/astral-sh/ruff/pull/21385) preview
/// style is enabled.
pub(crate) const fn is_force_single_line_lambda_parameters_enabled(
context: &PyFormatContext,
) -> bool {
context.is_preview()
}
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ x = {

long_unmergable_string_with_pragma = (
"This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore
@@ -468,49 +358,24 @@
@@ -468,49 +358,26 @@
" of it."
)

Expand Down Expand Up @@ -910,11 +910,13 @@ x = {
- f"this is a very very very very long lambda value {x} that doesn't fit on a"
- " single line"
+msg = (
+ lambda x: f"this is a very very very very long lambda value {x} that doesn't fit on a single line"
+ lambda x: (
+ f"this is a very very very very long lambda value {x} that doesn't fit on a single line"
+ )
)

dict_with_lambda_values = {
@@ -522,65 +387,58 @@
@@ -522,65 +389,58 @@

# Complex string concatenations with a method call in the middle.
code = (
Expand Down Expand Up @@ -998,7 +1000,7 @@ x = {
)

log.info(
@@ -588,7 +446,7 @@
@@ -588,7 +448,7 @@
)

log.info(
Expand All @@ -1007,7 +1009,7 @@ x = {
)

x = {
@@ -597,10 +455,10 @@
@@ -597,10 +457,10 @@
)
}
x = {
Expand Down Expand Up @@ -1404,7 +1406,9 @@ string_with_escaped_nameescape = "..............................................
string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}"

msg = (
lambda x: f"this is a very very very very long lambda value {x} that doesn't fit on a single line"
lambda x: (
f"this is a very very very very long lambda value {x} that doesn't fit on a single line"
)
)

dict_with_lambda_values = {
Expand Down
Loading