Skip to content

Fix # fmt: skip on the last line of a multi-line conditional expression in brackets - #5647

Merged
cobaltt7 merged 2 commits into
psf:mainfrom
b84330808:fix-fmt-skip-multiline-ternary
Nov 1, 2026
Merged

cobaltt7 merged 2 commits into
psf:mainfrom
b84330808:fix-fmt-skip-multiline-ternary

Conversation

@b84330808

Copy link
Copy Markdown
Contributor

Description

When a conditional expression inside brackets spans several lines and # fmt: skip is on its last line, Black produces invalid code:

x = (
    a
    if c else d,  # fmt: skip
    e,
)
error: cannot format repro.py: INTERNAL ERROR: ... produced invalid code: cannot parse: 5:6:         ) e,

With --fast it's written out silently; a variant like a # comment / + b if c else d, # fmt: skip / (e), turns the tuple into a call: (a ... else d, # fmt: skip\n)(e).

# fmt: skip hides only the code on its own line (if c else d,), so that hidden code ends the test node and also takes the comma after it. visit_test then wraps the node in invisible parentheses and the closing one lands after the comma. #5464 fixed the case where the whole ternary is on the skipped line; this is the multi-line one.

visit_test now skips the invisible parentheses when the node's last leaf is code hidden by # fmt: skip, like the existing check for hidden code at the start. Three multi-line cases added to fmtskip_conditional_in_brackets.py; they fail on main and pass with the change.

The same thing still happens under --preview for a dict value via wrap_long_dict_values_in_parens; I left that alone since #5627 is reworking that code.

Checklist - did you ...

  • Implement any code style changes under the --preview style, following the stability policy?
  • Add an entry in CHANGES.md if necessary?
  • Add / update tests if necessary?
  • Add new / update outdated documentation?

I used Claude Code to write this change.

When a conditional expression in a collection spans several lines and
`# fmt: skip` is on its last line, only the code on that line is hidden,
and the hidden code also takes the comma after the expression. The
STANDALONE_COMMENT holding it then ends the `test` node, so the invisible
parentheses that `visit_test` adds closed after the comma, and the output
turned the collection into a call or didn't parse:

    x = (
        a
        if c else d,  # fmt: skip
        e,
    )

Don't wrap the expression in invisible parentheses when its last leaf is
code hidden by `# fmt: skip`, like the existing check for when hidden code
starts it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@b84330808
b84330808 force-pushed the fix-fmt-skip-multiline-ternary branch from e1a4568 to b427ba8 Compare November 1, 2026 10:05
Comment thread src/black/linegen.py Resolved
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

diff-shades results comparing this PR (c56cb21) to main (e49fc44):

--preview style: no changes

--stable style: no changes


What is this? | Workflow run | diff-shades documentation

@cobaltt7

cobaltt7 commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks!

@cobaltt7
cobaltt7 merged commit a755b56 into psf:main Nov 1, 2026
54 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants