Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format lambda expression #5806

Merged
merged 14 commits into from
Jul 19, 2023
Original file line number Diff line number Diff line change
@@ -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

konstin marked this conversation as resolved.
Show resolved Hide resolved
# 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
)
52 changes: 46 additions & 6 deletions crates/ruff_python_formatter/src/expression/expr_lambda.rs
Original file line number Diff line number Diff line change
@@ -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<ExprLambda> 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)
cnpryer marked this conversation as resolved.
Show resolved Hide resolved
]
)
}

fn fmt_dangling_comments(&self, _node: &ExprLambda, _f: &mut PyFormatter) -> FormatResult<()> {
// Override. Dangling comments are handled in `fmt_fields`.
Ok(())
}
}

impl NeedsParentheses for ExprLambda {
Expand Down
28 changes: 25 additions & 3 deletions crates/ruff_python_formatter/src/other/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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<Arguments, PyFormatContext<'_>> for FormatArguments {
type Options = ArgumentsParentheses;

fn with_options(mut self, options: Self::Options) -> Self {
self.parentheses = options;
self
}
}

impl FormatNodeRule<Arguments> for FormatArguments {
fn fmt_fields(&self, item: &Arguments, f: &mut PyFormatter) -> FormatResult<()> {
Expand Down Expand Up @@ -170,7 +190,9 @@ impl FormatNodeRule<Arguments> for FormatArguments {
+ kwonlyargs.len()
+ usize::from(kwarg.is_some());

if num_arguments == 0 {
if self.parentheses == ArgumentsParentheses::SkipInsideLambda {
group(&format_inner).fmt(f)?;
MichaReiser marked this conversation as resolved.
Show resolved Hide resolved
} else if num_arguments == 0 {
// No arguments, format any dangling comments between `()`
write!(
f,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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))
Expand Down

This file was deleted.

Loading