wip: parenthesize long lambda bodies

This commit is contained in:
Brent Westbrook 2025-11-20 15:12:22 -05:00
parent 8cc884428d
commit 1b58643040
No known key found for this signature in database
5 changed files with 123 additions and 24 deletions

View File

@ -1,4 +1,4 @@
use ruff_formatter::{Argument, Arguments, write}; use ruff_formatter::{Argument, Arguments, format_args, write};
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::context::{NodeLevel, WithNodeLevel}; use crate::context::{NodeLevel, WithNodeLevel};
@ -31,20 +31,32 @@ impl ParenthesizeIfExpands<'_, '_> {
impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> { impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> { fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
{ {
let parens_id = f.group_id("optional_parentheses");
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f); let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
write!( write!(
f, f,
[group(&format_with(|f| { [group(&format_with(|f| {
if_group_breaks(&token("(")).fmt(f)?;
if self.indent { if self.indent {
soft_block_indent(&Arguments::from(&self.inner)).fmt(f)?; write!(
f,
[group(&format_args![
if_group_breaks(&token("(")),
indent_if_group_breaks(
&format_args![soft_line_break(), &Arguments::from(&self.inner)],
parens_id
),
soft_line_break(),
if_group_breaks(&token(")"))
])
.with_id(Some(parens_id))]
)
} else { } else {
if_group_breaks(&token("(")).fmt(f)?;
Arguments::from(&self.inner).fmt(f)?; Arguments::from(&self.inner).fmt(f)?;
if_group_breaks(&token(")")).fmt(f)
} }
if_group_breaks(&token(")")).fmt(f)
}))] }))]
) )
} }

View File

@ -4,10 +4,14 @@ use ruff_python_ast::ExprLambda;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::comments::dangling_comments; use crate::comments::dangling_comments;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; use crate::expression::has_own_parentheses;
use crate::expression::parentheses::{
NeedsParentheses, OptionalParentheses, is_expression_parenthesized, optional_parentheses,
};
use crate::other::parameters::ParametersParentheses; use crate::other::parameters::ParametersParentheses;
use crate::prelude::*; use crate::prelude::*;
use crate::preview::is_force_single_line_lambda_parameters_enabled; use crate::preview::is_force_single_line_lambda_parameters_enabled;
use crate::preview::is_parenthesize_lambda_bodies_enabled;
#[derive(Default)] #[derive(Default)]
pub struct FormatExprLambda; pub struct FormatExprLambda;
@ -27,7 +31,7 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
write!(f, [token("lambda")])?; write!(f, [token("lambda")])?;
if let Some(parameters) = parameters { 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. // parameters, or a comment between the parameters and the body.
let (dangling_before_parameters, dangling_after_parameters) = dangling let (dangling_before_parameters, dangling_after_parameters) = dangling
.split_at(dangling.partition_point(|comment| comment.end() < parameters.start())); .split_at(dangling.partition_point(|comment| comment.end() < parameters.start()));
@ -76,7 +80,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()
&& !is_expression_parenthesized(body.into(), comments.ranges(), f.context().source())
{
fits_expanded(&optional_parentheses(&body.format())).fmt(f)
} else {
body.format().fmt(f)
}
} }
} }

View File

@ -53,6 +53,13 @@ pub(crate) const fn is_avoid_parens_for_long_as_captures_enabled(
context.is_preview() 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 /// Returns `true` if the
/// [`force_single_line_lambda_parameters`](https://github.com/astral-sh/ruff/pull/21385) preview /// [`force_single_line_lambda_parameters`](https://github.com/astral-sh/ruff/pull/21385) preview
/// style is enabled. /// style is enabled.

View File

@ -906,11 +906,10 @@ x = {
-) -)
+string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}" +string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}"
-msg = lambda x: ( msg = lambda x: (
- f"this is a very very very very long lambda value {x} that doesn't fit on a" - f"this is a very very very very long lambda value {x} that doesn't fit on a"
- " single line" - " single line"
+msg = ( + 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 = { dict_with_lambda_values = {
@ -1403,8 +1402,8 @@ string_with_escaped_nameescape = "..............................................
string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}" string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}"
msg = ( msg = lambda x: (
lambda x: f"this is a very very very very long lambda value {x} that doesn't fit on a single line" f"this is a very very very very long lambda value {x} that doesn't fit on a single line"
) )
dict_with_lambda_values = { dict_with_lambda_values = {

View File

@ -682,18 +682,86 @@ class C:
```diff ```diff
--- Stable --- Stable
+++ Preview +++ Preview
@@ -280,9 +280,7 @@ @@ -74,7 +74,9 @@
# lambda arguments don't have parentheses, so we never add a magic trailing comma ...
def f(
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = lambda x: y,
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = lambda x: (
+ y
+ ),
):
pass
@@ -218,29 +220,31 @@
# 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
+ 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
@@ -280,9 +284,9 @@
] # Trailing ] # Trailing
# Trailing # Trailing
-lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( -lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
- *args, **kwargs - *args, **kwargs
-), e=1, f=2, g=2: d -), e=1, f=2, g=2: d
+lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d +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 # Regression tests for https://github.com/astral-sh/ruff/issues/8179
@@ -291,9 +289,9 @@ @@ -291,9 +295,9 @@
c, c,
d, d,
e, e,
@ -706,7 +774,7 @@ class C:
) )
@@ -302,15 +300,7 @@ @@ -302,15 +306,9 @@
c, c,
d, d,
e, e,
@ -719,21 +787,22 @@ class C:
- e=1, - e=1,
- f=2, - f=2,
- g=2: d, - g=2: d,
+ f=lambda self, araa, kkkwargs, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, args, kwargs, e=1, f=2, g=2: d, + f=lambda self, araa, kkkwargs, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, args, kwargs, e=1, f=2, g=2: (
+ d
+ ),
g=10, g=10,
) )
@@ -320,9 +310,10 @@ @@ -320,9 +318,9 @@
c, c,
d, d,
e, e,
- f=lambda self, - f=lambda self,
- *args, - *args,
- **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs) + 1, - **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs) + 1,
+ f=lambda self, *args, **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( + f=lambda self, *args, **kwargs: (
+ *args, **kwargs + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs) + 1
+ ) + ),
+ + 1,
) )