From 38678142edd3f37e53003f39b68c512bf132260d Mon Sep 17 00:00:00 2001 From: Chris Pryer <14341145+cnpryer@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:47:56 -0400 Subject: [PATCH] Format `lambda` expression (#5806) --- .../test/fixtures/ruff/expression/lambda.py | 63 ++++++++ .../src/expression/expr_lambda.rs | 52 ++++++- .../src/other/arguments.rs | 28 +++- ...black_compatibility@py_38__pep_570.py.snap | 20 +-- ...black_compatibility@py_38__pep_572.py.snap | 23 +-- ...ibility@simple_cases__bracketmatch.py.snap | 48 ------- ...atibility@simple_cases__expression.py.snap | 73 +++++----- ...mpatibility@simple_cases__fmtonoff.py.snap | 5 +- ...mpatibility@simple_cases__function.py.snap | 5 +- ...ity@simple_cases__power_op_spacing.py.snap | 8 +- ...@simple_cases__remove_for_brackets.py.snap | 11 +- ...compatibility@simple_cases__slices.py.snap | 10 +- .../format@expression__lambda.py.snap | 136 ++++++++++++++++++ 13 files changed, 327 insertions(+), 155 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py delete mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__bracketmatch.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py new file mode 100644 index 0000000000..7000569456 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py @@ -0,0 +1,63 @@ +# 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 +) \ No newline at end of file diff --git a/crates/ruff_python_formatter/src/expression/expr_lambda.rs b/crates/ruff_python_formatter/src/expression/expr_lambda.rs index e631e80061..1b2dc485cd 100644 --- a/crates/ruff_python_formatter/src/expression/expr_lambda.rs +++ b/crates/ruff_python_formatter/src/expression/expr_lambda.rs @@ -1,22 +1,62 @@ +use crate::comments::dangling_comments; use crate::context::PyFormatContext; use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; -use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; +use crate::other::arguments::ArgumentsParentheses; +use crate::AsFormat; +use crate::{FormatNodeRule, PyFormatter}; +use ruff_formatter::prelude::{space, text}; use ruff_formatter::{write, Buffer, FormatResult}; -use ruff_python_ast::node::AnyNodeRef; +use ruff_python_ast::node::{AnyNodeRef, AstNode}; use rustpython_parser::ast::ExprLambda; #[derive(Default)] pub struct FormatExprLambda; impl FormatNodeRule for FormatExprLambda { - fn fmt_fields(&self, _item: &ExprLambda, f: &mut PyFormatter) -> FormatResult<()> { + fn fmt_fields(&self, item: &ExprLambda, f: &mut PyFormatter) -> FormatResult<()> { + let ExprLambda { + range: _, + args, + body, + } = item; + + // It's possible for some `Arguments` of `lambda`s to be assigned dangling comments. + // + // a = ( + // lambda # Dangling + // : 1 + // ) + let comments = f.context().comments().clone(); + let dangling = comments.dangling_comments(args.as_any_node_ref()); + + write!(f, [text("lambda")])?; + + if !args.args.is_empty() { + write!( + f, + [ + space(), + args.format() + .with_options(ArgumentsParentheses::SkipInsideLambda), + ] + )?; + } + write!( f, - [not_yet_implemented_custom_text( - "lambda NOT_YET_IMPLEMENTED_lambda: True" - )] + [ + text(":"), + space(), + body.format(), + dangling_comments(dangling) + ] ) } + + fn fmt_dangling_comments(&self, _node: &ExprLambda, _f: &mut PyFormatter) -> FormatResult<()> { + // Override. Dangling comments are handled in `fmt_fields`. + Ok(()) + } } impl NeedsParentheses for ExprLambda { diff --git a/crates/ruff_python_formatter/src/other/arguments.rs b/crates/ruff_python_formatter/src/other/arguments.rs index 5e4d7fe6f3..07e1c051b0 100644 --- a/crates/ruff_python_formatter/src/other/arguments.rs +++ b/crates/ruff_python_formatter/src/other/arguments.rs @@ -3,7 +3,7 @@ use std::usize; use ruff_text_size::{TextRange, TextSize}; use rustpython_parser::ast::{Arguments, Ranged}; -use ruff_formatter::{format_args, write}; +use ruff_formatter::{format_args, write, FormatRuleWithOptions}; use ruff_python_ast::node::{AnyNodeRef, AstNode}; use ruff_python_whitespace::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind}; @@ -16,8 +16,28 @@ use crate::expression::parentheses::parenthesized; use crate::prelude::*; use crate::FormatNodeRule; +#[derive(Eq, PartialEq, Debug, Default)] +pub enum ArgumentsParentheses { + #[default] + Default, + + /// Arguments should never be inside parentheses for lambda expressions. + SkipInsideLambda, +} + #[derive(Default)] -pub struct FormatArguments; +pub struct FormatArguments { + parentheses: ArgumentsParentheses, +} + +impl FormatRuleWithOptions> for FormatArguments { + type Options = ArgumentsParentheses; + + fn with_options(mut self, options: Self::Options) -> Self { + self.parentheses = options; + self + } +} impl FormatNodeRule for FormatArguments { fn fmt_fields(&self, item: &Arguments, f: &mut PyFormatter) -> FormatResult<()> { @@ -170,7 +190,9 @@ impl FormatNodeRule for FormatArguments { + kwonlyargs.len() + usize::from(kwarg.is_some()); - if num_arguments == 0 { + if self.parentheses == ArgumentsParentheses::SkipInsideLambda { + group(&format_inner).fmt(f)?; + } else if num_arguments == 0 { // No arguments, format any dangling comments between `()` write!( f, diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_570.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_570.py.snap index 984c4bb1f9..b1326fc877 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_570.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_570.py.snap @@ -56,21 +56,15 @@ lambda a, b=1, /, c=2, d=3, *, e=4, f=5: 1 ```diff --- Black +++ Ruff -@@ -35,10 +35,10 @@ +@@ -35,7 +35,7 @@ pass -lambda a, /: a -+lambda NOT_YET_IMPLEMENTED_lambda: True ++lambda: a --lambda a, b, /, c, d, *, e, f: a -+lambda NOT_YET_IMPLEMENTED_lambda: True + lambda a, b, /, c, d, *, e, f: a --lambda a, b, /, c, d, *args, e, f, **kwargs: args -+lambda NOT_YET_IMPLEMENTED_lambda: True - --lambda a, b=1, /, c=2, d=3, *, e=4, f=5: 1 -+lambda NOT_YET_IMPLEMENTED_lambda: True ``` ## Ruff Output @@ -113,13 +107,13 @@ def long_one_with_long_parameter_names( pass -lambda NOT_YET_IMPLEMENTED_lambda: True +lambda: a -lambda NOT_YET_IMPLEMENTED_lambda: True +lambda a, b, /, c, d, *, e, f: a -lambda NOT_YET_IMPLEMENTED_lambda: True +lambda a, b, /, c, d, *args, e, f, **kwargs: args -lambda NOT_YET_IMPLEMENTED_lambda: True +lambda a, b=1, /, c=2, d=3, *, e=4, f=5: 1 ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572.py.snap index d9a42dae9b..061701bf16 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572.py.snap @@ -68,21 +68,6 @@ while x := f(x): pass [y := f(x), y**2, y**3] filtered_data = [y for x in data if (y := f(x)) is None] -@@ -19,10 +19,10 @@ - pass - - --lambda: (x := 1) --(x := lambda: 1) --(x := lambda: (y := 1)) --lambda line: (m := re.match(pattern, line)) and m.group(1) -+lambda NOT_YET_IMPLEMENTED_lambda: True -+(x := lambda NOT_YET_IMPLEMENTED_lambda: True) -+(x := lambda NOT_YET_IMPLEMENTED_lambda: True) -+lambda NOT_YET_IMPLEMENTED_lambda: True - x = (y := 0) - (z := (y := (x := 0))) - (info := (name, phone, *rest)) @@ -33,7 +33,7 @@ foo(cat=(category := "vector")) if any(len(longline := l) >= 100 for l in lines): @@ -128,10 +113,10 @@ def foo(answer: (p := 42) = 5): pass -lambda NOT_YET_IMPLEMENTED_lambda: True -(x := lambda NOT_YET_IMPLEMENTED_lambda: True) -(x := lambda NOT_YET_IMPLEMENTED_lambda: True) -lambda NOT_YET_IMPLEMENTED_lambda: True +lambda: (x := 1) +(x := lambda: 1) +(x := lambda: (y := 1)) +lambda line: (m := re.match(pattern, line)) and m.group(1) x = (y := 0) (z := (y := (x := 0))) (info := (name, phone, *rest)) diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__bracketmatch.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__bracketmatch.py.snap deleted file mode 100644 index 8201dc55c6..0000000000 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__bracketmatch.py.snap +++ /dev/null @@ -1,48 +0,0 @@ ---- -source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py ---- -## Input - -```py -for ((x in {}) or {})['a'] in x: - pass -pem_spam = lambda l, spam = { - "x": 3 -}: not spam.get(l.strip()) -lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -1,4 +1,4 @@ - for ((x in {}) or {})["a"] in x: - pass --pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip()) --lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x -+pem_spam = lambda NOT_YET_IMPLEMENTED_lambda: True -+lambda NOT_YET_IMPLEMENTED_lambda: True -``` - -## Ruff Output - -```py -for ((x in {}) or {})["a"] in x: - pass -pem_spam = lambda NOT_YET_IMPLEMENTED_lambda: True -lambda NOT_YET_IMPLEMENTED_lambda: True -``` - -## Black Output - -```py -for ((x in {}) or {})["a"] in x: - pass -pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip()) -lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x -``` - - diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap index 12608cc9b6..541a0aff4f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap @@ -274,34 +274,32 @@ last_call() Name None True -@@ -31,18 +31,15 @@ +@@ -31,7 +31,7 @@ -1 ~int and not v1 ^ 123 + v2 | True (~int) and (not ((v1 ^ (123 + v2)) | True)) -+(really ** -(confusing ** ~(operator**-precedence))) ++really ** -confusing ** ~operator**-precedence flags & ~select.EPOLLIN and waiters.write_task is not None --lambda arg: None --lambda a=True: a --lambda a, b, c=True: a --lambda a, b, c=True, *, d=(1 << v2), e="str": a --lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b --manylambdas = lambda x=lambda y=lambda z=1: z: y(): x() + lambda arg: None + lambda a=True: a +@@ -39,10 +39,11 @@ + lambda a, b, c=True, *, d=(1 << v2), e="str": a + lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b + manylambdas = lambda x=lambda y=lambda z=1: z: y(): x() -foo = lambda port_id, ignore_missing: { - "port1": port1_resource, - "port2": port2_resource, -}[port_id] -+lambda NOT_YET_IMPLEMENTED_lambda: True -+lambda NOT_YET_IMPLEMENTED_lambda: True -+lambda NOT_YET_IMPLEMENTED_lambda: True -+lambda NOT_YET_IMPLEMENTED_lambda: True -+lambda NOT_YET_IMPLEMENTED_lambda: True -+manylambdas = lambda NOT_YET_IMPLEMENTED_lambda: True -+foo = lambda NOT_YET_IMPLEMENTED_lambda: True ++foo = ( ++ lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[ ++ port_id ++ ] ++) 1 if True else 2 str or None if True else str or bytes or None (str or None) if True else (str or bytes or None) -@@ -57,7 +54,13 @@ +@@ -57,7 +58,13 @@ {"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}} {**a, **b, **c} {"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")} @@ -316,7 +314,7 @@ last_call() () (1,) (1, 2) -@@ -101,7 +104,10 @@ +@@ -101,7 +108,10 @@ {a: b * -2 for a, b in dictionary.items()} { k: v @@ -328,7 +326,7 @@ last_call() } Python3 > Python2 > COBOL Life is Life -@@ -115,7 +121,7 @@ +@@ -115,7 +125,7 @@ arg, another, kwarg="hey", @@ -337,7 +335,7 @@ last_call() ) # note: no trailing comma pre-3.6 call(*gidgets[:2]) call(a, *gidgets[:2]) -@@ -152,13 +158,13 @@ +@@ -152,13 +162,13 @@ slice[0:1] slice[0:1:2] slice[:] @@ -354,7 +352,7 @@ last_call() numpy[0, :] numpy[:, i] numpy[0, :2] -@@ -172,7 +178,7 @@ +@@ -172,7 +182,7 @@ numpy[1 : c + 1, c] numpy[-(c + 1) :, d] numpy[:, l[-2]] @@ -363,7 +361,7 @@ last_call() numpy[np.newaxis, :] (str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None) {"2.7": dead, "3.7": long_live or die_hard} -@@ -208,24 +214,14 @@ +@@ -208,24 +218,14 @@ what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set( vars_to_remove ) @@ -396,7 +394,7 @@ last_call() Ø = set() authors.łukasz.say_thanks() mapping = { -@@ -237,10 +233,10 @@ +@@ -237,10 +237,10 @@ def gen(): @@ -411,16 +409,7 @@ last_call() async def f(): -@@ -249,7 +245,7 @@ - - print(*[] or [1]) - print(**{1: 3} if False else {x: x for x in range(3)}) --print(*lambda x: x) -+print(*lambda NOT_YET_IMPLEMENTED_lambda: True) - assert not Test, "Short message" - assert this is ComplexTest and not requirements.fit_in_a_single_line( - force=False -@@ -328,13 +324,18 @@ +@@ -328,13 +328,18 @@ ): return True if ( @@ -442,7 +431,7 @@ last_call() ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n ): return True -@@ -342,7 +343,8 @@ +@@ -342,7 +347,8 @@ ~aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e @@ -492,13 +481,17 @@ not great (~int) and (not ((v1 ^ (123 + v2)) | True)) +really ** -confusing ** ~operator**-precedence flags & ~select.EPOLLIN and waiters.write_task is not None -lambda NOT_YET_IMPLEMENTED_lambda: True -lambda NOT_YET_IMPLEMENTED_lambda: True -lambda NOT_YET_IMPLEMENTED_lambda: True -lambda NOT_YET_IMPLEMENTED_lambda: True -lambda NOT_YET_IMPLEMENTED_lambda: True -manylambdas = lambda NOT_YET_IMPLEMENTED_lambda: True -foo = lambda NOT_YET_IMPLEMENTED_lambda: True +lambda arg: None +lambda a=True: a +lambda a, b, c=True: a +lambda a, b, c=True, *, d=(1 << v2), e="str": a +lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b +manylambdas = lambda x=lambda y=lambda z=1: z: y(): x() +foo = ( + lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[ + port_id + ] +) 1 if True else 2 str or None if True else str or bytes or None (str or None) if True else (str or bytes or None) @@ -704,7 +697,7 @@ async def f(): print(*[] or [1]) print(**{1: 3} if False else {x: x for x in range(3)}) -print(*lambda NOT_YET_IMPLEMENTED_lambda: True) +print(*lambda x: x) assert not Test, "Short message" assert this is ComplexTest and not requirements.fit_in_a_single_line( force=False diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap index 0afead70b9..2bf9b9c919 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap @@ -269,9 +269,8 @@ d={'a':1, + # fmt: on def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): -- offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) + offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) - assert task._cancel_stack[: len(old_stack)] == old_stack -+ offset = attr.ib(default=attr.Factory(lambda NOT_YET_IMPLEMENTED_lambda: True)) + assert task._cancel_stack[ : len(old_stack)] == old_stack @@ -451,7 +450,7 @@ def function_signature_stress_test( # fmt: on def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): - offset = attr.ib(default=attr.Factory(lambda NOT_YET_IMPLEMENTED_lambda: True)) + offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) assert task._cancel_stack[ : len(old_stack)] == old_stack diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap index a362d715fd..4c89da9f9b 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap @@ -126,9 +126,8 @@ def __await__(): return (yield) def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): -- offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000))) + offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000))) - assert task._cancel_stack[: len(old_stack)] == old_stack -+ offset = attr.ib(default=attr.Factory(lambda NOT_YET_IMPLEMENTED_lambda: True)) + assert task._cancel_stack[ : len(old_stack)] == old_stack @@ -225,7 +224,7 @@ def function_signature_stress_test( def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): - offset = attr.ib(default=attr.Factory(lambda NOT_YET_IMPLEMENTED_lambda: True)) + offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000))) assert task._cancel_stack[ : len(old_stack)] == old_stack diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__power_op_spacing.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__power_op_spacing.py.snap index 2793e97310..1a9ad84245 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__power_op_spacing.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__power_op_spacing.py.snap @@ -80,7 +80,7 @@ return np.divide( c = -(5**2) d = 5 ** f["hi"] -e = lazy(lambda **kwargs: 5) -+e = lazy(lambda NOT_YET_IMPLEMENTED_lambda: True) ++e = lazy(lambda: 5) f = f() ** 5 g = a.b**c.d h = 5 ** funcs.f() @@ -89,7 +89,7 @@ return np.divide( c = -(5.0**2.0) d = 5.0 ** f["hi"] -e = lazy(lambda **kwargs: 5) -+e = lazy(lambda NOT_YET_IMPLEMENTED_lambda: True) ++e = lazy(lambda: 5) f = f() ** 5.0 g = a.b**c.d h = 5.0 ** funcs.f() @@ -115,7 +115,7 @@ a = 5**~4 b = 5 ** f() c = -(5**2) d = 5 ** f["hi"] -e = lazy(lambda NOT_YET_IMPLEMENTED_lambda: True) +e = lazy(lambda: 5) f = f() ** 5 g = a.b**c.d h = 5 ** funcs.f() @@ -134,7 +134,7 @@ a = 5.0**~4.0 b = 5.0 ** f() c = -(5.0**2.0) d = 5.0 ** f["hi"] -e = lazy(lambda NOT_YET_IMPLEMENTED_lambda: True) +e = lazy(lambda: 5) f = f() ** 5.0 g = a.b**c.d h = 5.0 ** funcs.f() diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap index 7b10496c12..9a32084e95 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap @@ -31,15 +31,6 @@ for (((((k, v))))) in d.items(): ```diff --- Black +++ Ruff -@@ -5,7 +5,7 @@ - # Don't touch tuple brackets after `in` - for module in (core, _unicodefun): - if hasattr(module, "_verify_python3_env"): -- module._verify_python3_env = lambda: None -+ module._verify_python3_env = lambda NOT_YET_IMPLEMENTED_lambda: True - - # Brackets remain for long for loop lines - for ( @@ -17,9 +17,7 @@ for ( k, @@ -63,7 +54,7 @@ for k, v in d.items(): # Don't touch tuple brackets after `in` for module in (core, _unicodefun): if hasattr(module, "_verify_python3_env"): - module._verify_python3_env = lambda NOT_YET_IMPLEMENTED_lambda: True + module._verify_python3_env = lambda: None # Brackets remain for long for loop lines for ( diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__slices.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__slices.py.snap index ab61f02fb6..2aac3024f5 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__slices.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__slices.py.snap @@ -56,11 +56,9 @@ ham[lower + offset : upper + offset] slice[ham[c::d] :: 1] slice[ham[cheese**2 : -1] : 1 : 1, ham[1:2]] -slice[:-1:] --slice[lambda: None : lambda: None] --slice[lambda x, y, *args, really=2, **kwargs: None :, None::] +slice[ : -1 :] -+slice[lambda NOT_YET_IMPLEMENTED_lambda: True : lambda NOT_YET_IMPLEMENTED_lambda: True] -+slice[lambda NOT_YET_IMPLEMENTED_lambda: True :, None::] + slice[lambda: None : lambda: None] + slice[lambda x, y, *args, really=2, **kwargs: None :, None::] slice[1 or 2 : True and False] slice[not so_simple : 1 < val <= 10] slice[(1 for i in range(42)) : x] @@ -94,8 +92,8 @@ slice[c, c + 1, d::] slice[ham[c::d] :: 1] slice[ham[cheese**2 : -1] : 1 : 1, ham[1:2]] slice[ : -1 :] -slice[lambda NOT_YET_IMPLEMENTED_lambda: True : lambda NOT_YET_IMPLEMENTED_lambda: True] -slice[lambda NOT_YET_IMPLEMENTED_lambda: True :, None::] +slice[lambda: None : lambda: None] +slice[lambda x, y, *args, really=2, **kwargs: None :, None::] slice[1 or 2 : True and False] slice[not so_simple : 1 < val <= 10] slice[(1 for i in range(42)) : x] 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 new file mode 100644 index 0000000000..9e9c2d59f6 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__lambda.py.snap @@ -0,0 +1,136 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.py +--- +## Input +```py +# 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 +)``` + +## Output +```py +# 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: 1 # Dangling +) +``` + + +