Visitar URL original
Fix crash on `# fmt: skip` on several one-line clauses of a statement by vidigoat · Pull Request #5675 · psf/black · GitHub
Skip to content

Fix crash on # fmt: skip on several one-line clauses of a statement - #5675

Merged
cobaltt7 merged 3 commits into
psf:mainfrom
vidigoat:fix/fmt-skip-one-liner-later-clause
Nov 12, 2026
Merged

cobaltt7 merged 3 commits into
psf:mainfrom
vidigoat:fix/fmt-skip-one-liner-later-clause

Conversation

@vidigoat

@vidigoat vidigoat commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Description

# fmt: skip on two one-line clauses of the same statement crashes when their bodies are separated by semicolons:

if x: f(); g()  # fmt: skip
else: f(); g()  # fmt: skip
$ black example.py
error: cannot format example.py: INTERNAL ERROR: Black 26.10.2.dev98+gb4f1fcae4 on Python (CPython) 3.13.12 produced different code on the second pass of the formatter.

The same happens with elif, try/except/finally and for/while/async for with else, whenever a skipped one-line clause follows another skipped one-line clause. 26.10.1 formats this example; bisecting points to #5633. With bare names as the bodies (if x: a; b # fmt: skip / else: a; b # fmt: skip) it also crashes on 26.10.1.

For a one-line clause, _get_compound_statement_header prepends the clause's header to the skipped nodes (#4800). It collects every child of the compound statement before the body, so for the else line it starts at if. By then the if line has been hidden by its own # fmt: skip: the statement holds a STANDALONE_COMMENT and the simple_stmt with the newline left of its body. Both were hidden a second time with the else line, and since #5633 a newline is added after hidden code whose last line holds a comment, so the newline came out twice and blank lines were added before else on every pass. This starts the header after an already hidden clause and what is left of its body (a suite or simple_stmt with no code), so else only takes else:.

The new case is fmtskip_one_liner_later_clause.py; it fails on main. The full test suite and the pre-commit hooks pass. Running Black over the CPython 3.13 standard library, pandas, sqlglot, ibis, haystack and Ruff's formatter fixtures (11,573 files) gives the same output and the same errors as main, in stable and preview.

This changes nothing for code that doesn't crash. An earlier clause that isn't skipped itself, like if x: pass before else: f(); g() # fmt: skip, is still kept as written, as on main and 26.10.1, because changing that would reformat code that Black has already formatted.

This touches the same function's neighbourhood as #5674 but merges cleanly with it apart from the changelog line; the full suite passes with both.

Checklist - did you ...

  • Implement any code style changes under the --preview style, following the stability policy? (A crash fix, so stable; code that formatted before formats the same.)
  • Add an entry in CHANGES.md if necessary?
  • Add / update tests if necessary?
  • Add new / update outdated documentation? (Not needed.)

AI disclosure: this PR (code, tests and description) was written with Claude Code (Claude Opus 5.5); the verification above is what was run.

🤖 Generated with Claude Code

vidigoat and others added 2 commits November 8, 2026 21:10
For `if x: a; b  # fmt: skip` followed by `else: a; b  # fmt: skip`, the
header collected for the `else` line started at the beginning of the `if`
statement, so it took in the `if` line that its own `# fmt: skip` had
already hidden and the newline left of its body. That newline was written
twice, adding blank lines before `else` on every pass. The header of a
clause now starts after an already hidden clause and what is left of its
body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

diff-shades results comparing this PR (8d290e5) to main (b4f1fca):

--preview style: no changes

--stable style: no changes


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

@cobaltt7

Copy link
Copy Markdown
Collaborator

Thanks!

@cobaltt7
cobaltt7 merged commit 45f05c9 into psf:main Nov 12, 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