black icon indicating copy to clipboard operation
black copied to clipboard

Always respect original comment/code-order

Open randolf-scholz opened this issue 2 years ago • 3 comments

Is your feature request related to a problem? Please describe.

It would be nice to be able to force black to never change the order of code and comments.

for example:

x = (
    codeA   # commentA
    .codeB  # commentB
    .codeC  # commentC
    .codeD  # commentD
    .codeE  # commentE
    .codeF  # commentF
)

gets formatted to

x = (
    codeA.codeB.codeC.codeD.codeE.codeF  # commentA  # commentB  # commentC  # commentD  # commentE  # commentF
)

which even results in breaking the 88 character limit.

Describe the solution you'd like

It feels weird that black would even ever mess with the original ordering of code and comments. Imo, the order should always be respected, since comments go together with code. If the AST contains <codeA><commentA><codeB>, then the output should be <formatted-codeA><formatted-commentA><formatted-codeB>.

randolf-scholz avatar Jul 18 '23 17:07 randolf-scholz

I'm not sure we'll never want to reorder comments, but I agree in your example it's better to keep the comments as is. I would welcome a PR exploring a concrete change to make Black move comments less.

JelleZijlstra avatar Jul 22 '23 17:07 JelleZijlstra

@randolf-scholz I think your case is compounded by https://github.com/psf/black/issues/510, where a chain of attribute accesses is put on the same line even if it exceeds the length limit. This does not happen if you had method calls instead:

x = (
    codeA()  # commentA
    .codeB()  # commentB
    .codeC()  # commentC
    .codeD()  # commentD
    .codeE()  # commentE
    .codeF()  # commentF
)

If the comments are short enough, they are reordered in respect to the code though:

x = codeA().codeB().codeC().codeD().codeE().codeF()  # A  # B  # C  # D  # E  # F

To me it seems the most reasonable way of handling comments inside of lines is to associate it with a node and then unconditionally break all parents of that node so the node with the commend is placed on a separate line. To illustrate; in the following example, the comment would be associated with 99:

x = foo([
    1, 2, 3,
    99,  # Special case.
    4, 5
])

And this would be formatted like this:

x = foo(
    [
        1,
        2,
        3,
        99,  # Special case.
        4,
        5,
    ]
)

AFAICT this is what currently already happens with # type: comments. So as a first draft, we could handle all comments like this instead of just # type: comments. @JelleZijlstra What do you think?

Feuermurmel avatar Sep 07 '23 10:09 Feuermurmel

Seems worth trying!

JelleZijlstra avatar Sep 07 '23 14:09 JelleZijlstra