-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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 StmtFor #5163
Format StmtFor #5163
Conversation
PR Check ResultsEcosystem✅ ecosystem check detected no changes. BenchmarkLinux
Windows
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You picked a tough node but this looks good barring ExprTuple always keeping its parentheses (because i missed that case in ExprTuple)
# trailing else body comment | ||
|
||
|
||
for ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
black doesn't break this for statement, but i think this actually makes more sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm. interesting (how did you notice the difference?)
at this point, do we have a policy/guidelines for matching black (to help people migrate) vs improving formatting? maybe we raise an issue or otherwise to see if the black maintainers also prefer this formatting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our goal is to match black except in edge cases, but we haven't formalized what exactly this means. I'll discuss with @MichaReiser tomorrow what we want do about this
how did you notice the difference?
copied the code and ran black over it ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copied the code and ran black over it ;)
is it only the tests from black's test suite that automatically compare to black's output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at the moment, yes
text("for"), | ||
space(), | ||
// TODO: the `IfBreaks` is currently ignored by | ||
// https://github.com/astral-sh/ruff/blob/4b9b6829dccabdd4faf6efa6a118b4868347a701/crates/ruff_python_formatter/src/expression/expr_tuple.rs#L78 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might need a new setting that actually removes expression parentheses if not used, i'll experiment with this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want to keep this open pending that or merge as is for now?
Impl is mostly copied from |
## Motivation While black keeps parentheses nearly everywhere, with the notable exception of in the body of for loops: ```python for (a, b) in x: pass ``` becomes ```python for a, b in x: pass ``` This currently blocks #5163, which this PR should unblock. ## Solution This changes the `ExprTuple` formatting option to include one additional option that removes the parentheses when not using magic trailing comma and not breaking. It is supposed to be used through ``` #[derive(Debug)] struct ExprTupleWithoutParentheses<'a>(&'a Expr); impl Format<PyFormatContext<'_>> for ExprTupleWithoutParentheses<'_> { fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> { match self.0 { Expr::Tuple(expr_tuple) => expr_tuple .format() .with_options(TupleParentheses::StripInsideForLoop) .fmt(f), other => other.format().with_options(Parenthesize::IfBreaks).fmt(f), } } } ``` ## Testing The for loop formatting isn't merged due to missing this (and i didn't want to create more git weirdness across two people), but I've confirmed that when applying this to while loops instead of for loops, then ```rust write!( f, [ text("while"), space(), ExprTupleWithoutParentheses(test.as_ref()), text(":"), trailing_comments(trailing_condition_comments), block_indent(&body.format()) ] )?; ``` makes ```python while (a, b): pass while ( ajssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa, b, ): pass while (a,b,): pass ``` formatted as ```python while a, b: pass while ( ajssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa, b, ): pass while ( a, b, ): pass ```
Finally got around to it: #5175 This should hopefully unblock you, using #[derive(Debug)]
struct ExprTupleWithoutParentheses<'a>(&'a Expr);
impl Format<PyFormatContext<'_>> for ExprTupleWithoutParentheses<'_> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
match self.0 {
Expr::Tuple(expr_tuple) => expr_tuple
.format()
.with_options(TupleParentheses::StripInsideForLoop)
.fmt(f),
other => other.format().with_options(Parenthesize::IfBreaks).fmt(f),
}
}
} and |
block_indent(&orelse.format()) | ||
] | ||
)?; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a debug_assert!
here that in the orelse.is_empty()
case or_else_comments
is also empty?
## Motivation While black keeps parentheses nearly everywhere, with the notable exception of in the body of for loops: ```python for (a, b) in x: pass ``` becomes ```python for a, b in x: pass ``` This currently blocks #5163, which this PR should unblock. ## Solution This changes the `ExprTuple` formatting option to include one additional option that removes the parentheses when not using magic trailing comma and not breaking. It is supposed to be used through ``` #[derive(Debug)] struct ExprTupleWithoutParentheses<'a>(&'a Expr); impl Format<PyFormatContext<'_>> for ExprTupleWithoutParentheses<'_> { fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> { match self.0 { Expr::Tuple(expr_tuple) => expr_tuple .format() .with_options(TupleParentheses::StripInsideForLoop) .fmt(f), other => other.format().with_options(Parenthesize::IfBreaks).fmt(f), } } } ``` ## Testing The for loop formatting isn't merged due to missing this (and i didn't want to create more git weirdness across two people), but I've confirmed that when applying this to while loops instead of for loops, then ```rust write!( f, [ text("while"), space(), ExprTupleWithoutParentheses(test.as_ref()), text(":"), trailing_comments(trailing_condition_comments), block_indent(&body.format()) ] )?; ``` makes ```python while (a, b): pass while ( ajssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa, b, ): pass while (a,b,): pass ``` formatted as ```python while a, b: pass while ( ajssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa, b, ): pass while ( a, b, ): pass ```
## Motivation While black keeps parentheses nearly everywhere, the notable exception is in the body of for loops: ```python for (a, b) in x: pass ``` becomes ```python for a, b in x: pass ``` This currently blocks #5163, which this PR should unblock. ## Solution This changes the `ExprTuple` formatting option to include one additional option that removes the parentheses when not using magic trailing comma and not breaking. It is supposed to be used through ```rust #[derive(Debug)] struct ExprTupleWithoutParentheses<'a>(&'a Expr); impl Format<PyFormatContext<'_>> for ExprTupleWithoutParentheses<'_> { fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> { match self.0 { Expr::Tuple(expr_tuple) => expr_tuple .format() .with_options(TupleParentheses::StripInsideForLoop) .fmt(f), other => other.format().with_options(Parenthesize::IfBreaks).fmt(f), } } } ``` ## Testing The for loop formatting isn't merged due to missing this (and i didn't want to create more git weirdness across two people), but I've confirmed that when applying this to while loops instead of for loops, then ```rust write!( f, [ text("while"), space(), ExprTupleWithoutParentheses(test.as_ref()), text(":"), trailing_comments(trailing_condition_comments), block_indent(&body.format()) ] )?; ``` makes ```python while (a, b): pass while ( ajssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa, b, ): pass while (a,b,): pass ``` formatted as ```python while a, b: pass while ( ajssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa, b, ): pass while ( a, b, ): pass ```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks
Summary
format StmtFor
still trying to learn how to help out with the formatter. trying something slightly more advanced than break
mostly copied form StmtWhile
Test Plan
snapshots