From 4d06bfa965c08c184787362cedada010edf90f78 Mon Sep 17 00:00:00 2001 From: Anuj Soni Date: Sat, 18 Oct 2025 23:00:37 +0530 Subject: [PATCH 1/9] fix_fmt_skip_in_one_liners --- src/black/comments.py | 83 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/black/comments.py b/src/black/comments.py index 25c20a8e677..8312dddaf58 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -321,6 +321,78 @@ def generate_ignored_nodes( container = container.next_sibling +def _find_compound_statement_context( + parent: Optional[LN], +) -> tuple[Optional[Node], Optional[Node]]: + """Find compound statement and suite nodes for fmt: skip handling.""" + if parent is None or parent.type != syms.simple_stmt: + return None, None + + # Case 1: simple_stmt -> suite -> compound_stmt (after reformatting) + if (parent.parent is not None + and parent.parent.type == syms.suite + and parent.parent.parent is not None): + assert isinstance(parent.parent, Node) + suite_node = parent.parent + assert isinstance(suite_node.parent, Node) + compound_parent = suite_node.parent + return compound_parent, suite_node + + # Case 2: simple_stmt -> compound_stmt (original structure) + compound_types = ( + syms.if_stmt, syms.while_stmt, syms.for_stmt, + syms.try_stmt, syms.with_stmt, syms.funcdef, syms.classdef + ) + if (parent.parent is not None + and parent.parent.type in compound_types): + assert isinstance(parent.parent, Node) + compound_parent = parent.parent + # Find the suite node in the compound statement + for child in compound_parent.children: + if child.type == syms.suite: + assert isinstance(child, Node) + return compound_parent, child + + return None, None + + +def _get_compound_statement_header( + compound_parent: Node, suite_node: Node, parent: LN +) -> list[LN]: + """Get header nodes for compound statement if it should be preserved.""" + compound_types = ( + syms.if_stmt, syms.while_stmt, syms.for_stmt, + syms.try_stmt, syms.with_stmt, syms.funcdef, syms.classdef + ) + if compound_parent.type not in compound_types: + return [] + + # Check if this is a single-line compound statement + stmt_children = [ + child for child in suite_node.children + if child.type not in (token.NEWLINE, token.INDENT, token.DEDENT) + ] + + single_line_body = ( + len(stmt_children) == 1 + and (stmt_children[0] == parent + or any(c == parent for c in stmt_children[0].children + if hasattr(stmt_children[0], 'children'))) + ) + + if not single_line_body: + return [] + + # Include the compound statement header + header_leaves: list[LN] = [] + for child in compound_parent.children: + if child == suite_node: + break + if child.type not in (token.NEWLINE, token.INDENT): + header_leaves.extend(child.leaves()) + return header_leaves + + def _generate_ignored_nodes_from_fmt_skip( leaf: Leaf, comment: ProtoComment, mode: Mode ) -> Iterator[LN]: @@ -382,6 +454,17 @@ def _generate_ignored_nodes_from_fmt_skip( if current_node.prev_sibling is None and current_node.parent is not None: current_node = current_node.parent + # Special handling for compound statements with semicolon-separated bodies + compound_parent, suite_node = _find_compound_statement_context(parent) + if (compound_parent is not None + and suite_node is not None + and parent is not None): + header_nodes = _get_compound_statement_header( + compound_parent, suite_node, parent + ) + if header_nodes: + ignored_nodes = header_nodes + ignored_nodes + yield from ignored_nodes elif ( parent is not None and parent.type == syms.suite and leaf.type == token.NEWLINE From 3ae6d46933242f3f4cabf56dc9dd17bf7257ea16 Mon Sep 17 00:00:00 2001 From: Anuj Soni Date: Sun, 19 Oct 2025 14:50:40 +0530 Subject: [PATCH 2/9] added testcase and changed changelog --- CHANGES.md | 2 ++ src/black/comments.py | 56 +++++++++++++++++++++++++---------- tests/data/cases/fmtskip10.py | 3 ++ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0742a2d7562..6f970d357d4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,8 @@ comments (#4764) - Fix bug where python 3.12 generics syntax split line happens weirdly (#4777) - Standardize type comments to form `# type: ` (#4645) +- Fix `fix_fmt_skip_in_one_liners` preview feature to respect `# fmt: skip` for + compound statements with semicolon-separated bodies (#4783) ### Configuration diff --git a/src/black/comments.py b/src/black/comments.py index 8312dddaf58..ba002b06063 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -347,11 +347,8 @@ def _find_compound_statement_context( and parent.parent.type in compound_types): assert isinstance(parent.parent, Node) compound_parent = parent.parent - # Find the suite node in the compound statement - for child in compound_parent.children: - if child.type == syms.suite: - assert isinstance(child, Node) - return compound_parent, child + # In original single-line structure, the simple_stmt IS the body + return compound_parent, parent return None, None @@ -367,18 +364,45 @@ def _get_compound_statement_header( if compound_parent.type not in compound_types: return [] - # Check if this is a single-line compound statement - stmt_children = [ - child for child in suite_node.children - if child.type not in (token.NEWLINE, token.INDENT, token.DEDENT) - ] + # Check if the body contains semicolon-separated statements + has_semicolon = False + if suite_node.type == syms.suite: + # After reformatting, check if the suite contains semicolons + for child in suite_node.children: + if hasattr(child, 'children'): + for grandchild in child.children: + if getattr(grandchild, 'type', None) == token.SEMI: + has_semicolon = True + break + if has_semicolon: + break + else: + # Original structure - check the simple_stmt for semicolons + for child in suite_node.children: + if getattr(child, 'type', None) == token.SEMI: + has_semicolon = True + break - single_line_body = ( - len(stmt_children) == 1 - and (stmt_children[0] == parent - or any(c == parent for c in stmt_children[0].children - if hasattr(stmt_children[0], 'children'))) - ) + # Only apply our fix for compound statements with semicolon-separated bodies + if not has_semicolon: + return [] + + # Check if this is a single-line compound statement + if suite_node.type == syms.suite: + # Case 1: After reformatting, body is in a suite + stmt_children = [ + child for child in suite_node.children + if child.type not in (token.NEWLINE, token.INDENT, token.DEDENT) + ] + single_line_body = ( + len(stmt_children) == 1 + and (stmt_children[0] == parent + or any(c == parent for c in stmt_children[0].children + if hasattr(stmt_children[0], 'children'))) + ) + else: + # Case 2: Original structure, suite_node is the simple_stmt body + single_line_body = (suite_node == parent) if not single_line_body: return [] diff --git a/tests/data/cases/fmtskip10.py b/tests/data/cases/fmtskip10.py index 0c017719b2d..ed7ffacd07c 100644 --- a/tests/data/cases/fmtskip10.py +++ b/tests/data/cases/fmtskip10.py @@ -2,6 +2,9 @@ def foo(): return "mock" # fmt: skip if True: print("yay") # fmt: skip for i in range(10): print(i) # fmt: skip +if True: print("this"); print("that") # fmt: skip +while True: print("loop"); break # fmt: skip +for x in [1, 2]: print(x); print("done") # fmt: skip j = 1 # fmt: skip while j < 10: j += 1 # fmt: skip From 48eb60eb0874ae486b0b5ee86985966cb075477c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 19 Oct 2025 09:21:22 +0000 Subject: [PATCH 3/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4f412cf5fde..e2213be7177 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,8 +19,8 @@ comments (#4764) - Fix bug where python 3.12 generics syntax split line happens weirdly (#4777) - Standardize type comments to form `# type: ` (#4645) -- Fix `fix_fmt_skip_in_one_liners` preview feature to respect `# fmt: skip` for - compound statements with semicolon-separated bodies (#4783) +- Fix `fix_fmt_skip_in_one_liners` preview feature to respect `# fmt: skip` for compound + statements with semicolon-separated bodies (#4783) ### Configuration From c600ecaf6d584ec90e9c2e7174353f9d3fea5367 Mon Sep 17 00:00:00 2001 From: Anuj Soni Date: Sun, 19 Oct 2025 14:53:06 +0530 Subject: [PATCH 4/9] Fix mypy type error in _find_compound_statement_context Add type assertion for simple_stmt nodes to ensure mypy compliance. The simple_stmt is always a Node, so this assertion is safe. --- src/black/comments.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/black/comments.py b/src/black/comments.py index ba002b06063..78b96650954 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -348,6 +348,7 @@ def _find_compound_statement_context( assert isinstance(parent.parent, Node) compound_parent = parent.parent # In original single-line structure, the simple_stmt IS the body + assert isinstance(parent, Node) # simple_stmt is always a Node return compound_parent, parent return None, None From 005a6022e91a9c9bf594670cf2131e416071683b Mon Sep 17 00:00:00 2001 From: Anuj Soni Date: Sun, 19 Oct 2025 19:15:43 +0530 Subject: [PATCH 5/9] fixed tox and changelog CI issues --- CHANGES.md | 2 +- src/black/comments.py | 60 +++++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e2213be7177..33f208bbeda 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,7 +20,7 @@ - Fix bug where python 3.12 generics syntax split line happens weirdly (#4777) - Standardize type comments to form `# type: ` (#4645) - Fix `fix_fmt_skip_in_one_liners` preview feature to respect `# fmt: skip` for compound - statements with semicolon-separated bodies (#4783) + statements with semicolon-separated bodies (#4783, #4800) ### Configuration diff --git a/src/black/comments.py b/src/black/comments.py index 78b96650954..12cb446aa31 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -329,9 +329,11 @@ def _find_compound_statement_context( return None, None # Case 1: simple_stmt -> suite -> compound_stmt (after reformatting) - if (parent.parent is not None - and parent.parent.type == syms.suite - and parent.parent.parent is not None): + if ( + parent.parent is not None + and parent.parent.type == syms.suite + and parent.parent.parent is not None + ): assert isinstance(parent.parent, Node) suite_node = parent.parent assert isinstance(suite_node.parent, Node) @@ -340,11 +342,15 @@ def _find_compound_statement_context( # Case 2: simple_stmt -> compound_stmt (original structure) compound_types = ( - syms.if_stmt, syms.while_stmt, syms.for_stmt, - syms.try_stmt, syms.with_stmt, syms.funcdef, syms.classdef + syms.if_stmt, + syms.while_stmt, + syms.for_stmt, + syms.try_stmt, + syms.with_stmt, + syms.funcdef, + syms.classdef, ) - if (parent.parent is not None - and parent.parent.type in compound_types): + if parent.parent is not None and parent.parent.type in compound_types: assert isinstance(parent.parent, Node) compound_parent = parent.parent # In original single-line structure, the simple_stmt IS the body @@ -359,8 +365,13 @@ def _get_compound_statement_header( ) -> list[LN]: """Get header nodes for compound statement if it should be preserved.""" compound_types = ( - syms.if_stmt, syms.while_stmt, syms.for_stmt, - syms.try_stmt, syms.with_stmt, syms.funcdef, syms.classdef + syms.if_stmt, + syms.while_stmt, + syms.for_stmt, + syms.try_stmt, + syms.with_stmt, + syms.funcdef, + syms.classdef, ) if compound_parent.type not in compound_types: return [] @@ -370,9 +381,9 @@ def _get_compound_statement_header( if suite_node.type == syms.suite: # After reformatting, check if the suite contains semicolons for child in suite_node.children: - if hasattr(child, 'children'): + if hasattr(child, "children"): for grandchild in child.children: - if getattr(grandchild, 'type', None) == token.SEMI: + if getattr(grandchild, "type", None) == token.SEMI: has_semicolon = True break if has_semicolon: @@ -380,7 +391,7 @@ def _get_compound_statement_header( else: # Original structure - check the simple_stmt for semicolons for child in suite_node.children: - if getattr(child, 'type', None) == token.SEMI: + if getattr(child, "type", None) == token.SEMI: has_semicolon = True break @@ -392,18 +403,21 @@ def _get_compound_statement_header( if suite_node.type == syms.suite: # Case 1: After reformatting, body is in a suite stmt_children = [ - child for child in suite_node.children + child + for child in suite_node.children if child.type not in (token.NEWLINE, token.INDENT, token.DEDENT) ] - single_line_body = ( - len(stmt_children) == 1 - and (stmt_children[0] == parent - or any(c == parent for c in stmt_children[0].children - if hasattr(stmt_children[0], 'children'))) + single_line_body = len(stmt_children) == 1 and ( + stmt_children[0] == parent + or any( + c == parent + for c in stmt_children[0].children + if hasattr(stmt_children[0], "children") + ) ) else: # Case 2: Original structure, suite_node is the simple_stmt body - single_line_body = (suite_node == parent) + single_line_body = suite_node == parent if not single_line_body: return [] @@ -481,9 +495,11 @@ def _generate_ignored_nodes_from_fmt_skip( current_node = current_node.parent # Special handling for compound statements with semicolon-separated bodies compound_parent, suite_node = _find_compound_statement_context(parent) - if (compound_parent is not None - and suite_node is not None - and parent is not None): + if ( + compound_parent is not None + and suite_node is not None + and parent is not None + ): header_nodes = _get_compound_statement_header( compound_parent, suite_node, parent ) From 5d6bfd7aa9b23ad7bd4ada6916c09ecba2cce391 Mon Sep 17 00:00:00 2001 From: Anuj Soni Date: Mon, 20 Oct 2025 11:04:58 +0530 Subject: [PATCH 6/9] resolved comments --- CHANGES.md | 2 +- src/black/comments.py | 192 ++++++++++++++++++++---------------------- 2 files changed, 90 insertions(+), 104 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 33f208bbeda..30e537fe260 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,7 +20,7 @@ - Fix bug where python 3.12 generics syntax split line happens weirdly (#4777) - Standardize type comments to form `# type: ` (#4645) - Fix `fix_fmt_skip_in_one_liners` preview feature to respect `# fmt: skip` for compound - statements with semicolon-separated bodies (#4783, #4800) + statements with semicolon-separated bodies (#4800) ### Configuration diff --git a/src/black/comments.py b/src/black/comments.py index 12cb446aa31..5d783edbc38 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -8,6 +8,7 @@ from black.nodes import ( CLOSING_BRACKETS, STANDALONE_COMMENT, + STATEMENT, WHITESPACE, container_of, first_leaf_of, @@ -26,6 +27,10 @@ FMT_SKIP: Final = {"# fmt: skip", "# fmt:skip"} FMT_ON: Final = {"# fmt: on", "# fmt:on", "# yapf: enable"} +# Compound statements we care about for fmt: skip handling +# (excludes except_clause and case_block which aren't standalone compound statements) +_COMPOUND_STATEMENTS: Final = STATEMENT - {syms.except_clause, syms.case_block} + COMMENT_EXCEPTIONS = " !:#'" _COMMENT_PREFIX = "# " _COMMENT_LIST_SEPARATOR = ";" @@ -322,112 +327,99 @@ def generate_ignored_nodes( def _find_compound_statement_context( - parent: Optional[LN], -) -> tuple[Optional[Node], Optional[Node]]: - """Find compound statement and suite nodes for fmt: skip handling.""" + parent: Optional[LN], mode: Mode +) -> Optional[Node]: + """Return the body node of a compound statement if we should respect fmt: skip. + + This handles one-line compound statements like: + if condition: body # fmt: skip + + When Black expands such statements, they temporarily look like: + if condition: + body # fmt: skip + + In both cases, we want to return the body node (either the simple_stmt directly + or the suite containing it). + """ + if Preview.fix_fmt_skip_in_one_liners not in mode: + return None + if parent is None or parent.type != syms.simple_stmt: - return None, None + return None + + assert isinstance(parent, Node) - # Case 1: simple_stmt -> suite -> compound_stmt (after reformatting) + # Case 1: Expanded form after Black's initial formatting pass. + # The one-liner has been split across multiple lines: + # if True: + # print("a"); print("b") # fmt: skip + # Structure: compound_stmt -> suite -> simple_stmt if ( - parent.parent is not None + isinstance(parent.parent, Node) and parent.parent.type == syms.suite - and parent.parent.parent is not None + and isinstance(parent.parent.parent, Node) + and parent.parent.parent.type in _COMPOUND_STATEMENTS ): - assert isinstance(parent.parent, Node) - suite_node = parent.parent - assert isinstance(suite_node.parent, Node) - compound_parent = suite_node.parent - return compound_parent, suite_node - - # Case 2: simple_stmt -> compound_stmt (original structure) - compound_types = ( - syms.if_stmt, - syms.while_stmt, - syms.for_stmt, - syms.try_stmt, - syms.with_stmt, - syms.funcdef, - syms.classdef, - ) - if parent.parent is not None and parent.parent.type in compound_types: - assert isinstance(parent.parent, Node) - compound_parent = parent.parent - # In original single-line structure, the simple_stmt IS the body - assert isinstance(parent, Node) # simple_stmt is always a Node - return compound_parent, parent - - return None, None - - -def _get_compound_statement_header( - compound_parent: Node, suite_node: Node, parent: LN -) -> list[LN]: - """Get header nodes for compound statement if it should be preserved.""" - compound_types = ( - syms.if_stmt, - syms.while_stmt, - syms.for_stmt, - syms.try_stmt, - syms.with_stmt, - syms.funcdef, - syms.classdef, - ) - if compound_parent.type not in compound_types: - return [] + return parent.parent - # Check if the body contains semicolon-separated statements - has_semicolon = False - if suite_node.type == syms.suite: - # After reformatting, check if the suite contains semicolons - for child in suite_node.children: - if hasattr(child, "children"): - for grandchild in child.children: - if getattr(grandchild, "type", None) == token.SEMI: - has_semicolon = True - break - if has_semicolon: - break - else: - # Original structure - check the simple_stmt for semicolons - for child in suite_node.children: - if getattr(child, "type", None) == token.SEMI: - has_semicolon = True - break + # Case 2: Original one-line form from the input source. + # The statement is still on a single line: + # if True: print("a"); print("b") # fmt: skip + # Structure: compound_stmt -> simple_stmt + if ( + isinstance(parent.parent, Node) + and parent.parent.type in _COMPOUND_STATEMENTS + ): + return parent - # Only apply our fix for compound statements with semicolon-separated bodies - if not has_semicolon: - return [] + return None - # Check if this is a single-line compound statement - if suite_node.type == syms.suite: - # Case 1: After reformatting, body is in a suite - stmt_children = [ - child - for child in suite_node.children - if child.type not in (token.NEWLINE, token.INDENT, token.DEDENT) - ] - single_line_body = len(stmt_children) == 1 and ( - stmt_children[0] == parent - or any( - c == parent - for c in stmt_children[0].children - if hasattr(stmt_children[0], "children") - ) - ) - else: - # Case 2: Original structure, suite_node is the simple_stmt body - single_line_body = suite_node == parent - if not single_line_body: - return [] +def _should_keep_compound_statement_inline( + body_node: Node, simple_stmt_parent: Node +) -> bool: + """Check if a compound statement should be kept on one line. + + Returns True only for compound statements with semicolon-separated bodies, + like: if True: print("a"); print("b") # fmt: skip + """ + # Check if there are semicolons in the body + for leaf in body_node.leaves(): + if leaf.type == token.SEMI: + # Verify it's a single-line body (one simple_stmt) + if body_node.type == syms.suite: + # After formatting: check suite has one simple_stmt child + simple_stmts = [ + child + for child in body_node.children + if child.type == syms.simple_stmt + ] + return len(simple_stmts) == 1 and simple_stmts[0] is simple_stmt_parent + else: + # Original form: body_node IS the simple_stmt + return body_node is simple_stmt_parent + return False + - # Include the compound statement header +def _get_compound_statement_header(body_node: Node, simple_stmt_parent: Node) -> list[LN]: + """Get header nodes for a compound statement that should be preserved inline.""" + if not _should_keep_compound_statement_inline(body_node, simple_stmt_parent): + return [] + + # Get the compound statement (parent of body) + compound_stmt = body_node.parent + if compound_stmt is None or compound_stmt.type not in _COMPOUND_STATEMENTS: + return [] + + # Collect all header leaves before the body header_leaves: list[LN] = [] - for child in compound_parent.children: - if child == suite_node: + for child in compound_stmt.children: + if child is body_node: break - if child.type not in (token.NEWLINE, token.INDENT): + if isinstance(child, Leaf): + if child.type not in (token.NEWLINE, token.INDENT): + header_leaves.append(child) + else: header_leaves.extend(child.leaves()) return header_leaves @@ -494,15 +486,9 @@ def _generate_ignored_nodes_from_fmt_skip( if current_node.prev_sibling is None and current_node.parent is not None: current_node = current_node.parent # Special handling for compound statements with semicolon-separated bodies - compound_parent, suite_node = _find_compound_statement_context(parent) - if ( - compound_parent is not None - and suite_node is not None - and parent is not None - ): - header_nodes = _get_compound_statement_header( - compound_parent, suite_node, parent - ) + body_node = _find_compound_statement_context(parent, mode) + if body_node is not None and isinstance(parent, Node): + header_nodes = _get_compound_statement_header(body_node, parent) if header_nodes: ignored_nodes = header_nodes + ignored_nodes From 3c59c8f0eb72e19a8dcccef98544d86cddfecfe0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 05:36:57 +0000 Subject: [PATCH 7/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/black/comments.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/black/comments.py b/src/black/comments.py index 5d783edbc38..d54a88fa5ab 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -330,20 +330,20 @@ def _find_compound_statement_context( parent: Optional[LN], mode: Mode ) -> Optional[Node]: """Return the body node of a compound statement if we should respect fmt: skip. - + This handles one-line compound statements like: if condition: body # fmt: skip - + When Black expands such statements, they temporarily look like: if condition: body # fmt: skip - + In both cases, we want to return the body node (either the simple_stmt directly or the suite containing it). """ if Preview.fix_fmt_skip_in_one_liners not in mode: return None - + if parent is None or parent.type != syms.simple_stmt: return None @@ -379,7 +379,7 @@ def _should_keep_compound_statement_inline( body_node: Node, simple_stmt_parent: Node ) -> bool: """Check if a compound statement should be kept on one line. - + Returns True only for compound statements with semicolon-separated bodies, like: if True: print("a"); print("b") # fmt: skip """ @@ -405,12 +405,12 @@ def _get_compound_statement_header(body_node: Node, simple_stmt_parent: Node) -> """Get header nodes for a compound statement that should be preserved inline.""" if not _should_keep_compound_statement_inline(body_node, simple_stmt_parent): return [] - + # Get the compound statement (parent of body) compound_stmt = body_node.parent if compound_stmt is None or compound_stmt.type not in _COMPOUND_STATEMENTS: return [] - + # Collect all header leaves before the body header_leaves: list[LN] = [] for child in compound_stmt.children: From 16b26f78d93e6aa1b1de155ea46d55bac66faf60 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Sun, 26 Oct 2025 10:17:15 -0500 Subject: [PATCH 8/9] Run Black Signed-off-by: cobalt <61329810+cobaltt7@users.noreply.github.com> --- src/black/comments.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/black/comments.py b/src/black/comments.py index d54a88fa5ab..4e701011f80 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -366,10 +366,7 @@ def _find_compound_statement_context( # The statement is still on a single line: # if True: print("a"); print("b") # fmt: skip # Structure: compound_stmt -> simple_stmt - if ( - isinstance(parent.parent, Node) - and parent.parent.type in _COMPOUND_STATEMENTS - ): + if isinstance(parent.parent, Node) and parent.parent.type in _COMPOUND_STATEMENTS: return parent return None @@ -401,7 +398,9 @@ def _should_keep_compound_statement_inline( return False -def _get_compound_statement_header(body_node: Node, simple_stmt_parent: Node) -> list[LN]: +def _get_compound_statement_header( + body_node: Node, simple_stmt_parent: Node +) -> list[LN]: """Get header nodes for a compound statement that should be preserved inline.""" if not _should_keep_compound_statement_inline(body_node, simple_stmt_parent): return [] From ea9f08869e000de720e28f1032998b393a9af2ce Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Sun, 26 Oct 2025 10:31:55 -0500 Subject: [PATCH 9/9] Small refactors, I realized it's cleaner this way Signed-off-by: cobalt <61329810+cobaltt7@users.noreply.github.com> --- src/black/comments.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/black/comments.py b/src/black/comments.py index 4e701011f80..53d9df3a7fe 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -326,9 +326,7 @@ def generate_ignored_nodes( container = container.next_sibling -def _find_compound_statement_context( - parent: Optional[LN], mode: Mode -) -> Optional[Node]: +def _find_compound_statement_context(parent: Node) -> Optional[Node]: """Return the body node of a compound statement if we should respect fmt: skip. This handles one-line compound statements like: @@ -341,22 +339,19 @@ def _find_compound_statement_context( In both cases, we want to return the body node (either the simple_stmt directly or the suite containing it). """ - if Preview.fix_fmt_skip_in_one_liners not in mode: + if parent.type != syms.simple_stmt: return None - if parent is None or parent.type != syms.simple_stmt: + if not isinstance(parent.parent, Node): return None - assert isinstance(parent, Node) - # Case 1: Expanded form after Black's initial formatting pass. # The one-liner has been split across multiple lines: # if True: # print("a"); print("b") # fmt: skip # Structure: compound_stmt -> suite -> simple_stmt if ( - isinstance(parent.parent, Node) - and parent.parent.type == syms.suite + parent.parent.type == syms.suite and isinstance(parent.parent.parent, Node) and parent.parent.parent.type in _COMPOUND_STATEMENTS ): @@ -366,7 +361,7 @@ def _find_compound_statement_context( # The statement is still on a single line: # if True: print("a"); print("b") # fmt: skip # Structure: compound_stmt -> simple_stmt - if isinstance(parent.parent, Node) and parent.parent.type in _COMPOUND_STATEMENTS: + if parent.parent.type in _COMPOUND_STATEMENTS: return parent return None @@ -485,11 +480,12 @@ def _generate_ignored_nodes_from_fmt_skip( if current_node.prev_sibling is None and current_node.parent is not None: current_node = current_node.parent # Special handling for compound statements with semicolon-separated bodies - body_node = _find_compound_statement_context(parent, mode) - if body_node is not None and isinstance(parent, Node): - header_nodes = _get_compound_statement_header(body_node, parent) - if header_nodes: - ignored_nodes = header_nodes + ignored_nodes + if Preview.fix_fmt_skip_in_one_liners in mode and isinstance(parent, Node): + body_node = _find_compound_statement_context(parent) + if body_node is not None: + header_nodes = _get_compound_statement_header(body_node, parent) + if header_nodes: + ignored_nodes = header_nodes + ignored_nodes yield from ignored_nodes elif (