Repository navigation
Fix crash on # fmt: skip on a nested bracket after with or yield - #5620
Merged
Merged
Conversation
Collaborator
|
Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
# fmt: skipon an opening bracket crashes Black when the bracket starts an operand that's nested inside a longer expression afterwithoryield:fails with "INTERNAL ERROR: Black produced invalid code: cannot parse: 1:4". The same happens with
) + 1 == 2:,with not ( # fmt: skip...) or b:,async with, andwith ... as c. Afteryieldthe output still parses but means something else (yieldends up on its own line), so Black reports "produced code that is not equivalent to the source". 26.10.1 crashes on these too.To find the code before the bracket on the same line, the walk in
_generate_ignored_nodes_from_fmt_skipclimbs to the parent when a node has no previous sibling, but only by one level. Here the bracket is the first leaf of acomparisoninside anand_test, so the walk stops at thecomparisonandwithis never added to the skipped line. The skipped code then becomes a standalone comment afterwith, which gets split onto its own line.Both climbs (the one before the walk and the one inside it) now keep going up while the node is the first child of its parent. The inner loop that collapsed fully ignored parents is folded into the outer one, since it did the same climb with an extra condition.
With the whole line skipped, a unary operator before the bracket can be hidden while its operand goes on after the closing bracket (
with -( # fmt: skip...).y and b:). That leaves afactornode with only the operand, sovisit_factornow checks the number of children instead of unpacking two.In other statements this didn't crash, but the line wasn't kept as is either. For example
x = ( # fmt: skip...) == 1 and bwas turned intox = (followed by the bracket on its own line. Those lines are now left unchanged. Code that was already formatted by Black stays the same: I ran ~19k generated variants (x =,return,yield,with,if,assert, lambdas, unary operators, trailers, and/or/comparison/arithmetic operands) and the output ofmainfor each one is unchanged with this branch, in stable, preview and unstable. None of them crash now.Checklist - did you ...
--previewstyle, following the stability policy?CHANGES.mdif necessary?