diff --git a/crates/ruff_python_formatter/src/expression/expr_lambda.rs b/crates/ruff_python_formatter/src/expression/expr_lambda.rs index c5890fba24..4c02467cfd 100644 --- a/crates/ruff_python_formatter/src/expression/expr_lambda.rs +++ b/crates/ruff_python_formatter/src/expression/expr_lambda.rs @@ -4,6 +4,7 @@ use ruff_python_ast::ExprLambda; use ruff_text_size::Ranged; use crate::comments::dangling_comments; +use crate::comments::leading_comments; use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; use crate::other::parameters::ParametersParentheses; use crate::prelude::*; @@ -33,24 +34,45 @@ impl FormatNodeRule for FormatExprLambda { if dangling_before_parameters.is_empty() { write!(f, [space()])?; - } else { - write!(f, [dangling_comments(dangling_before_parameters)])?; } - write!( - f, - [parameters - .format() - .with_options(ParametersParentheses::Never)] - )?; + group(&format_with(|f: &mut PyFormatter| { + if f.context().node_level().is_parenthesized() + && (parameters.len() > 1 || !dangling_before_parameters.is_empty()) + { + let end_of_line_start = dangling_before_parameters + .partition_point(|comment| comment.line_position().is_end_of_line()); + let (same_line_comments, own_line_comments) = + dangling_before_parameters.split_at(end_of_line_start); - write!(f, [token(":")])?; + dangling_comments(same_line_comments).fmt(f)?; - if dangling_after_parameters.is_empty() { - write!(f, [space()])?; - } else { - write!(f, [dangling_comments(dangling_after_parameters)])?; - } + write![ + f, + [ + soft_line_break(), + leading_comments(own_line_comments), + parameters + .format() + .with_options(ParametersParentheses::Never), + ] + ] + } else { + parameters + .format() + .with_options(ParametersParentheses::Never) + .fmt(f) + }?; + + write!(f, [token(":")])?; + + if dangling_after_parameters.is_empty() { + write!(f, [space()]) + } else { + write!(f, [dangling_comments(dangling_after_parameters)]) + } + })) + .fmt(f)?; } else { write!(f, [token(":")])?; diff --git a/crates/ruff_python_formatter/src/other/parameters.rs b/crates/ruff_python_formatter/src/other/parameters.rs index 1c6682bab1..736d0d6fa0 100644 --- a/crates/ruff_python_formatter/src/other/parameters.rs +++ b/crates/ruff_python_formatter/src/other/parameters.rs @@ -241,7 +241,7 @@ impl FormatNodeRule for FormatParameters { let num_parameters = item.len(); if self.parentheses == ParametersParentheses::Never { - write!(f, [group(&format_inner), dangling_comments(dangling)]) + write!(f, [format_inner, dangling_comments(dangling)]) } else if num_parameters == 0 { let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f); // No parameters, format any dangling comments between `()` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap index 03332c6f92..610cd5255a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py -snapshot_kind: text --- ## Input ```python @@ -132,6 +131,13 @@ lambda a, /, c: a *x: x ) +( + lambda + # comment + *x, + **y: x +) + ( lambda # comment 1 @@ -142,6 +148,17 @@ lambda a, /, c: a x ) +( + lambda + # comment 1 + * + # comment 2 + x, + **y: + # comment 3 + x +) + ( lambda # comment 1 * # comment 2 @@ -149,6 +166,14 @@ lambda a, /, c: a x ) +( + lambda # comment 1 + * # comment 2 + x, + y: # comment 3 + x +) + lambda *x\ :x @@ -203,6 +228,17 @@ lambda: ( # comment x ) +( + lambda # 1 + # 2 + x, # 3 + # 4 + y + : # 5 + # 6 + x +) + ( lambda x, @@ -211,6 +247,71 @@ lambda: ( # comment 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 @@ -237,7 +338,22 @@ def a(): ``` -## Output +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = "dynamic" +preview = Disabled +target_version = 3.10 +source_type = Python +``` + ```python # Leading lambda x: x # Trailing @@ -301,7 +417,8 @@ a = ( ) a = ( - lambda x, # Dangling + lambda + x, # Dangling y: 1 ) @@ -367,6 +484,13 @@ lambda a, /, c: a *x: x ) +( + lambda + # comment + *x, + **y: x +) + ( lambda # comment 1 @@ -376,6 +500,16 @@ lambda a, /, c: a x ) +( + lambda + # comment 1 + # comment 2 + *x, + **y: + # comment 3 + x +) + ( lambda # comment 1 # comment 2 @@ -383,6 +517,14 @@ lambda a, /, c: a x ) +( + lambda # comment 1 + # comment 2 + *x, + y: # comment 3 + x +) + lambda *x: x ( @@ -435,11 +577,87 @@ lambda: ( # comment ) ( - lambda x, + lambda # 1 + # 2 + x, # 3 + # 4 + y: # 5 + # 6 + x +) + +( + lambda + x, # comment y: 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 @@ -451,7 +669,8 @@ def a(): c, d, e, - f=lambda self, + f=lambda + self, *args, **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), ) @@ -462,7 +681,365 @@ def a(): c, d, e, - f=lambda self, + f=lambda + self, + araa, + kkkwargs, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + args, + kwargs, + e=1, + f=2, + g=2: d, + g=10, + ) +``` + + +### Output 2 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = "dynamic" +preview = Enabled +target_version = 3.10 +source_type = Python +``` + +```python +# Leading +lambda x: x # Trailing +# Trailing + +# Leading +lambda x, y: x # Trailing +# Trailing + +# Leading +lambda x, y: x, y # Trailing +# Trailing + +# Leading +lambda x, /, y: x # Trailing +# Trailing + +# Leading +lambda x: lambda y: lambda z: x # Trailing +# Trailing + +# Leading +lambda x: lambda y: lambda z: (x, y, z) # Trailing +# Trailing + +# Leading +lambda x: lambda y: lambda z: (x, 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, + z, +) # Trailing +# Trailing + +a = ( + lambda: # Dangling + 1 +) + +a = ( + lambda + x, # Dangling + y: 1 +) + +# Regression test: lambda empty arguments ranges were too long, leading to unstable +# formatting +( + lambda: ( # + ), +) + + +# lambda arguments don't have parentheses, so we never add a magic trailing comma ... +def f( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = lambda x: y, +): + pass + + +# ...but we do preserve a trailing comma after the arguments +a = lambda b,: 0 + +lambda a,: 0 +lambda *args,: 0 +lambda **kwds,: 0 +lambda a, *args,: 0 +lambda a, **kwds,: 0 +lambda *args, b,: 0 +lambda *, b,: 0 +lambda *args, **kwds,: 0 +lambda a, *args, b,: 0 +lambda a, *, b,: 0 +lambda a, *args, **kwds,: 0 +lambda *args, b, **kwds,: 0 +lambda *, b, **kwds,: 0 +lambda a, *args, b, **kwds,: 0 +lambda a, *, b, **kwds,: 0 +lambda a, /: a +lambda a, /, c: a + +# Dangling comments without parameters. +( + lambda: # 3 + None +) + +( + lambda: + # 3 + None +) + +( + lambda: # 1 + # 2 + # 3 + # 4 + None # 5 +) + +( + lambda + # comment + *x: x +) + +( + lambda + # comment + *x, + **y: x +) + +( + lambda + # comment 1 + # comment 2 + *x: + # comment 3 + x +) + +( + lambda + # comment 1 + # comment 2 + *x, + **y: + # comment 3 + x +) + +( + lambda # comment 1 + # comment 2 + *x: # comment 3 + x +) + +( + lambda # comment 1 + # comment 2 + *x, + y: # comment 3 + x +) + +lambda *x: x + +( + lambda + # comment + *x: x +) + +lambda: ( # comment + x +) + +( + lambda: # comment + x +) + +( + lambda: + # comment + x +) + +( + lambda: # comment + x +) + +( + lambda: + # comment + x +) + +( + lambda: # comment + ( # comment + x + ) +) + +( + lambda # 1 + # 2 + x: # 3 + # 4 + # 5 + # 6 + x +) + +( + lambda # 1 + # 2 + x, # 3 + # 4 + y: # 5 + # 6 + x +) + +( + lambda + x, + # comment + y: 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 +def a(): + return b( + c, + d, + e, + f=lambda + self, + *args, + **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), + ) + + +def a(): + return b( + c, + d, + e, + f=lambda + self, araa, kkkwargs, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,