close
Skip to content

Fix fmt: skip failing to parse multiline case statements with backslash continuation#5123

Open
ParamChordiya wants to merge 5 commits intopsf:mainfrom
ParamChordiya:fix/multiline-case-fmtskip
Open

Fix fmt: skip failing to parse multiline case statements with backslash continuation#5123
ParamChordiya wants to merge 5 commits intopsf:mainfrom
ParamChordiya:fix/multiline-case-fmtskip

Conversation

@ParamChordiya
Copy link
Copy Markdown
Contributor

Summary

  • Fixes Fail to parse multiline case statement with # fmt: skip #5122: black >= 26 crashes with Cannot parse when # fmt: skip is applied to a multiline case pattern using backslash line continuation (\)
  • Added _prefix_has_real_newline() helper to distinguish real newlines from backslash-continued ones
  • Updated the backward-traversal loop in _generate_ignored_nodes_from_fmt_skip to use the new helper
  • Added test case fmtskip14.py covering the reported scenario and multiple backslash continuations

Root cause

_generate_ignored_nodes_from_fmt_skip walks backward through the CST to collect all nodes on the same logical line as # fmt: skip. The while condition used "\n" not in current_node.prefix to detect a line boundary and stop.

For a multiline case pattern like:

case ("GET", "parent", _, "resource", resource_id) \
        | ("GET", "resource", resource_id):  # fmt: skip

the | token has prefix ' \\\n ' (backslash + newline). The old check treated this as a line boundary, so traversal stopped after collecting only the second group and the colon — missing the first group entirely. The resulting STANDALONE_COMMENT was malformed, and the second formatting pass crashed with a parse error.

Fix

_prefix_has_real_newline(prefix) returns True only for bare newlines (not preceded by \). The while loop now continues through backslash continuations and collects the entire or-pattern correctly.

Test plan

  • python -m pytest tests/test_format.py -q — 212 passed (includes new fmtskip14)
  • python -m pytest tests/test_black.py -q --deselect tests/test_black.py::BlackTestCase::test_code_option_safe — 158 passed (pre-existing failure excluded)
  • Manual verification: original reproduction case from Fail to parse multiline case statement with # fmt: skip #5122 is left unchanged by black

ParamChordiya and others added 4 commits May 5, 2026 18:21
…sh continuation

When # fmt: skip appears on a multiline case pattern using backslash line
continuation (e.g. case A \ | B:  # fmt: skip), the node traversal in
_generate_ignored_nodes_from_fmt_skip stopped prematurely. The while loop
used "\n" not in prefix to detect line boundaries, but the | token's prefix
contains \<newline> (a line continuation), which was misread as a real line
break. Only the second half of the or-pattern was collected, producing
garbled output that failed to re-parse on the second formatting pass.

Fix by adding _prefix_has_real_newline() which treats a newline preceded by
a backslash as a continuation rather than a boundary. The traversal now
walks back through the entire or-pattern and collects all nodes correctly.

Fixes psf#5122
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

diff-shades results comparing this PR (a46f277) to main (9fd9ea2):

--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.

Fail to parse multiline case statement with # fmt: skip

1 participant