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

Formatter: Comprehension ifs should break if the comprehension breaks #6063

Closed
Tracked by #6069 ...
konstin opened this issue Jul 25, 2023 · 5 comments · Fixed by #6321
Closed
Tracked by #6069 ...

Formatter: Comprehension ifs should break if the comprehension breaks #6063

konstin opened this issue Jul 25, 2023 · 5 comments · Fixed by #6321
Labels
formatter Related to the formatter good first issue Good for newcomers

Comments

@konstin
Copy link
Member

konstin commented Jul 25, 2023

Black breaks the if into its own line if the comprehension breaks

a = (
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    for f in bbbbbbbbbbbbbbb
    if f not in ccccccccccc
)

while we don't

a = (
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    for f in bbbbbbbbbbbbbbb if f not in ccccccccccc
)

Conversely, parentheses should not require the target breaking

black:

aaaaaaaaaaaaaaaaaaaaa = (
    o for o in self.registry.values if o.__class__ is not ModelAdmin
)

ours:

aaaaaaaaaaaaaaaaaaaaa = (
    o
    for o in self.registry.values if o.__class__ is not ModelAdmin
)

Fixing this requires changing the grouping strategy for comprehensions and generator expressions.

@konstin konstin added good first issue Good for newcomers formatter Related to the formatter labels Jul 25, 2023
@AbhinavMir
Copy link

Happy to work on this. Where would the source for this be? I tried looking in comprehensions and a few other places, but couldn't find the grouping strat. Thx.

@MichaReiser
Copy link
Member

Happy to work on this. Where would the source for this be? I tried looking in comprehensions and a few other places, but couldn't find the grouping strat. Thx.

You're in the right file. The grouping of the ifs and adding the line break before it happens here. It may already be sufficient to just move the line break outside of the group.

joiner.entry(&group(&format_args!(
leading_comments(own_line_if_comments),
text("if"),
trailing_comments(end_of_line_if_comments),
Spacer(if_case),
if_case.format(),
)));

@konstin
Copy link
Member Author

konstin commented Jul 28, 2023

Additionally, you might need to look at expr_list_comp.rs/expr_dict_comp.rs/expr_set_comp.rs (they follow the same structure so i can fix one and then copy that to the others once one works). I think i tried and moving a single group wasn't enough, but it should still be doable by shuffling group()s in the right way.

@AbhinavMir
Copy link

Thanks @konstin will get to that too!
@MichaReiser quick question: how does soft_line_break_or_space() decide between line break or space? I assume by moving the line break outside you meant something like this?

write!(
            f,
            [
                text("for"),
                // ADD in line break here!
                trailing_comments(before_target_comments),
                group(&format_args!(
                    Spacer(target),
                    ExprTupleWithoutParentheses(target),
                    in_spacer,
                    leading_comments(before_in_comments),
                    text("in"),
                    trailing_comments(trailing_in_comments),
                    Spacer(iter),
                    iter.format(),
                )),
            ]
        )?;

@MichaReiser
Copy link
Member

soft_line_break_or_space renders a space if its enclosing group fits on a line and it renders a line break if it does not.

A group fits on a line if all its content (including nested groups) can be printed on a line without exceeding the configured line width. The way this is determined is by measuring if the groups content and any content coming after the group up to the first line break (soft or hard doesn't matter) doesn't exceed the line width.

You may also want to take a look at the documentation of the different builder methdos (like soft_line_break_or_space). Each of them comes with examples.

moving the line break outside you meant something like this?

Yeah, that's what I had in mind but it may not work (always hard to tell with formatting)

@MichaReiser MichaReiser added this to the Formatter: Alpha milestone Jul 31, 2023
charliermarsh added a commit that referenced this issue Aug 4, 2023
## Summary

Fixes some comprehension formatting by avoiding creating the group for
the comprehension itself (so that if it breaks, all parts break on their
own lines, e.g. the `for` and the `if` clauses).

Closes #6063.

## Test Plan

Bunch of new fixtures.
@AbhinavMir AbhinavMir removed their assignment Feb 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
formatter Related to the formatter good first issue Good for newcomers
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants