Skip to content

keep async keyword with fmt: skip one-line compound statements - #5311

Open
sahvx655-wq wants to merge 3 commits into
psf:mainfrom
sahvx655-wq:fmtskip-async-compound
Open

keep async keyword with fmt: skip one-line compound statements#5311
sahvx655-wq wants to merge 3 commits into
psf:mainfrom
sahvx655-wq:fmtskip-async-compound

Conversation

@sahvx655-wq

@sahvx655-wq sahvx655-wq commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Description

Reported in #5307. Black crashes on a one-line async with/async for/async def that has a semicolon-separated body and a trailing # fmt: skip, e.g. async with ctx(): a; b # fmt: skip. The non-async form is fine, and the async form is fine without the semicolon, so it took a while to pin down the combination. The parse error it dies on is misleading (cannot parse: ... async) because it comes from Black's second pass reparsing its own output rather than from the input.

Dumping the first-pass output showed the cause: async had been split onto its own line, leaving async\n with g(): ..., which is not valid Python. When a one-line compound statement carries a semicolon body under # fmt: skip, _get_compound_statement_header gathers the header leaves to keep them inline, but it only walks the children of the with_stmt/for_stmt/funcdef. For an async statement the tree wraps that node in an async_stmt and the leading ASYNC token is a sibling of the compound node, not a child, so it never made it into the skipped nodes and got reformatted on its own. The colon-line form of # fmt: skip already handles this via the async_stmt grandparent, but the inline-semicolon path did not. The risk if left as-is is that any file with such a line cannot be formatted at all under --safe, and under --fast Black would silently emit broken code. Fixed by picking up the async_stmt's leading ASYNC token first; the three async variants are added to fmtskip10.py.

Close #5307, closes #5308, closes #5314

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?

the async token sits on the wrapping async_stmt, not on the with/for/def compound node, so it was dropped from the ignored nodes and split onto its own line
@sahvx655-wq
sahvx655-wq force-pushed the fmtskip-async-compound branch from cfe9f36 to e915f85 Compare August 15, 2026 12:13
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

diff-shades results comparing this PR (85f309d) to main (74371e2):

--preview style: no changes

--stable style: no changes


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

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.

Crash on async def/with and a semicolon on the same line

2 participants