## Summary We were using `Parenthesize::IfBreaks` universally for `await`, but dropping parentheses can change the AST due to precedence. It turns out that Black's rules aren't _exactly_ the same as operator precedence (e.g., they leave parentheses around `await ([1, 2, 3])`, although they aren't strictly required). Closes https://github.com/astral-sh/ruff/issues/7467. ## Test Plan `cargo test` No change in similarity. Before: | project | similarity index | total files | changed files | |--------------|------------------:|------------------:|------------------:| | cpython | 0.76083 | 1789 | 1632 | | django | 0.99982 | 2760 | 37 | | transformers | 0.99957 | 2587 | 398 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99983 | 3496 | 18 | | warehouse | 0.99929 | 648 | 16 | | zulip | 0.99962 | 1437 | 22 | After: | project | similarity index | total files | changed files | |--------------|------------------:|------------------:|------------------:| | cpython | 0.76083 | 1789 | 1632 | | django | 0.99982 | 2760 | 37 | | transformers | 0.99957 | 2587 | 398 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99983 | 3496 | 18 | | warehouse | 0.99929 | 648 | 16 | | zulip | 0.99962 | 1437 | 22 |
77 lines
2.0 KiB
Rust
77 lines
2.0 KiB
Rust
use ruff_formatter::write;
|
|
use ruff_python_ast::node::AnyNodeRef;
|
|
use ruff_python_ast::ExprLambda;
|
|
|
|
use crate::comments::{dangling_comments, SourceComment};
|
|
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
|
|
use crate::other::parameters::ParametersParentheses;
|
|
use crate::prelude::*;
|
|
|
|
#[derive(Default)]
|
|
pub struct FormatExprLambda;
|
|
|
|
impl FormatNodeRule<ExprLambda> for FormatExprLambda {
|
|
fn fmt_fields(&self, item: &ExprLambda, f: &mut PyFormatter) -> FormatResult<()> {
|
|
let ExprLambda {
|
|
range: _,
|
|
parameters,
|
|
body,
|
|
} = item;
|
|
|
|
let comments = f.context().comments().clone();
|
|
let dangling = comments.dangling(item);
|
|
|
|
write!(f, [token("lambda")])?;
|
|
|
|
if let Some(parameters) = parameters {
|
|
write!(
|
|
f,
|
|
[
|
|
space(),
|
|
parameters
|
|
.format()
|
|
.with_options(ParametersParentheses::Never),
|
|
]
|
|
)?;
|
|
}
|
|
|
|
write!(f, [token(":")])?;
|
|
|
|
if dangling.is_empty() {
|
|
write!(f, [space()])?;
|
|
} else {
|
|
write!(f, [dangling_comments(dangling)])?;
|
|
}
|
|
|
|
// Insert hard line break if body has leading comment to ensure consistent formatting
|
|
if comments.has_leading(body.as_ref()) {
|
|
write!(f, [hard_line_break()])?;
|
|
}
|
|
|
|
write!(f, [body.format()])
|
|
}
|
|
|
|
fn fmt_dangling_comments(
|
|
&self,
|
|
_dangling_comments: &[SourceComment],
|
|
_f: &mut PyFormatter,
|
|
) -> FormatResult<()> {
|
|
// Override. Dangling comments are handled in `fmt_fields`.
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl NeedsParentheses for ExprLambda {
|
|
fn needs_parentheses(
|
|
&self,
|
|
parent: AnyNodeRef,
|
|
_context: &PyFormatContext,
|
|
) -> OptionalParentheses {
|
|
if parent.is_expr_await() {
|
|
OptionalParentheses::Always
|
|
} else {
|
|
OptionalParentheses::Multiline
|
|
}
|
|
}
|
|
}
|