-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ruff
] improve handling of intermixed comments inside from-imports
#20561
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
Conversation
|
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 for looking into this. We'll need to add tests (see resources/fixtures
). I also suggest playing with different comment combinations. E.g. the following now flips the order of comments which is always undesired:
from x import (a # more
as # whatever
b)
Gets formatted to
from x import (
a as b, # more
# whatever
)
This one doesn't flip the comment order but it places the other
comment that used to be before b
after b
from x import (a
as # whatever
# other
b)
Not suggesting that you should or that it makes your life easier in any way. But an alternative fix is to update place_comment
so that it makes comments between as
and the first alias leading comments of the first alias (as was done in #20589)
token("as"), | ||
space(), | ||
asname.format(), | ||
line_suffix(&dangling_comments(dangling), 0), |
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.
Passing 0 for the width is incorrect here. The width is used to determine how much space the Printer
needs to reserve for the comments. Zero means that they take zero width (or the width is ignored) and they always fit if the content before fits on the line.
The reason line_suffix
has a width is that Ruff excludes pragma comments from the width calculation, but all other comments need to fit into the 88-character limit, or the line is split over multiple lines.
You can use trailing_comments
if you want to format the comments as end-of-line comments
Working on adding some test fixtures to validate results, and considering alternative approaches. |
Resolves the crash when attempting to format code like: ``` from x import (a as # whatever b) ``` And chooses to format it as: ``` from x import ( a as b, # whatever ) ``` Fixes issue #19138
In this given example putting comments in every possible position, Black will maintain placement of all the comments, rather than re-flowing any elements together and merging comments:
Do we want to ensure that we follow Black's style and preserve all of these comments in their original positions? Or do we want to have an opinion and re-flow/merge various comments to ensure that |
We've used Black's comment formatting as inspiration and we try to match it for "common" comment placements but it's not a strict requirement that we have to match black precisely (I also found Black inconsistent about when it tries to be smart/opinionated and when it's strict about preserving comment placements). We do try to preserve own-line comments as own-line comments and end-of line comments should remain end-of-line comments. It's also important to preserve the ordering of comments. Trying your example with a few "similar" syntax elements (this is the formatted output): # alpha
(
# bravo
a # charlie
# delta
+ # echo
# foxtrot
b, # golf
# hotel
# india
# juliet
) # kilo
# scrambles own line and end of line comments
# alpha
with (
# bravo
a as ( # charlie
# delta # echo
# foxtrot
b
), # golf
# hotel
# india
# juliet
): # kilo
...
match x:
# alpha
case (
# bravo
a # charlie
# delta
as # echo
# foxtrot
b, # golf
# hotel
# india
# juliet
): # kilo
... |
63b3f7a
to
db386d3
Compare
Updated to use |
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.
Does this change reflow comments of already formatted code?
Could we do something similar to the MatchAs
formatting
ruff/crates/ruff_python_formatter/src/pattern/pattern_match_as.rs
Lines 27 to 44 in 63b3f7a
if comments.has_trailing(pattern.as_ref()) { | |
write!(f, [hard_line_break()])?; | |
} else { | |
write!(f, [space()])?; | |
} | |
write!(f, [token("as")])?; | |
let trailing_as_comments = comments.dangling(item); | |
if trailing_as_comments.is_empty() { | |
write!(f, [space()])?; | |
} else if trailing_as_comments | |
.iter() | |
.all(|comment| comment.line_position().is_own_line()) | |
{ | |
write!(f, [hard_line_break()])?; | |
} | |
write!(f, [dangling_comments(trailing_as_comments)])?; |
I'm asking because the formatting of
from x import (a # more
as # whatever
b)
from x import (a
as # whatever
# other
b)
to
from x import (
a as b, # more
# whatever
)
from x import (
a as b, # whatever
# other
)
or
# alpha
from x import (
# bravo
a
as # echo
# foxtrot
b # golf
# hotel
)
where the foxdrot
comment now comes after b
(it was a leading comment but it now becomes a trailing comment and the indent for golf
is off)
# alpha
from x import (
# bravo
a as b, # echo
# foxtrot
# golf
# hotel
)
The indent of # golf
is problematic because this is now a case where the formatter needs two passes to reach convergence. We need to fix this at least and add them as test cases.
Hmm, I'm seeing different results from you when I test this locally:
|
Ah, sorry. I think pulling the changes this morning failed and I then tested against the previous revision. Adding those tests might still make sense because they demonstrate other issues that your PR fixes. |
I'm revisiting the comment placement mechanisms, and attempting to better associate comments within an alias node to the identifiers they belong with. |
db386d3
to
77a4803
Compare
Reworked the ways comments are associated, specifically for the
Passing ruff's output black confirms no changes:
|
77a4803
to
2636902
Compare
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.
Nice!
Given that we now preserve the original placement in more cases, it should also mean that we don't reformat any existing code (and, thus, doesn't require any preview gating)
if let Some(SimpleToken { | ||
kind: SimpleTokenKind::Comma, | ||
.. | ||
}) = SimpleTokenizer::starts_at(comment.start(), source) | ||
.skip_trivia() | ||
.next() | ||
{ |
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.
Nit: The place_comments
logic tends to be complicated and its often non obvious what cases each branch is handling. That's why we tend to add inline comments that show examples of the patterns they match on (see the comments above).
Could you add such comments for this branch and to handle_alias_comment
too?
// this should be a dangling comment but only if it comes before the `,`
// ```python
// from foo import (
// baz # comment
// ,
// bar
// )
// ```
Documented placement functions and changes, as well as in the alias formatter. Also added more test cases and updated the logic to better match black style and merge lines/comments when no own-line comments are between the alias and the trailing comma: Eg, from foo import (
bar # one
, # two Becomes: from foo import (
bar, # one # two
) Edit: to be clear, this change is also closer to the existing behavior of Ruff, so even though it changes formatting, it's no different than what Ruff already does today:
|
c18f1f5
to
1936389
Compare
ruff
] improve handling of intermixed comments inside from-imports
Resolves the crash when attempting to format code like:
And chooses to format it as:
Fixes issue #19138