Visitar URL original
resolved comments · psf/black@5d6bfd7 · GitHub
Skip to content

Commit 5d6bfd7

Browse files
committed
resolved comments
1 parent 005a602 commit 5d6bfd7

2 files changed

Lines changed: 90 additions & 104 deletions

File tree

‎CHANGES.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
- Fix bug where python 3.12 generics syntax split line happens weirdly (#4777)
2121
- Standardize type comments to form `# type: <value>` (#4645)
2222
- Fix `fix_fmt_skip_in_one_liners` preview feature to respect `# fmt: skip` for compound
23-
statements with semicolon-separated bodies (#4783, #4800)
23+
statements with semicolon-separated bodies (#4800)
2424

2525
### Configuration
2626

‎src/black/comments.py‎

Lines changed: 89 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from black.nodes import (
99
CLOSING_BRACKETS,
1010
STANDALONE_COMMENT,
11+
STATEMENT,
1112
WHITESPACE,
1213
container_of,
1314
first_leaf_of,
@@ -26,6 +27,10 @@
2627
FMT_SKIP: Final = {"# fmt: skip", "# fmt:skip"}
2728
FMT_ON: Final = {"# fmt: on", "# fmt:on", "# yapf: enable"}
2829

30+
# Compound statements we care about for fmt: skip handling
31+
# (excludes except_clause and case_block which aren't standalone compound statements)
32+
_COMPOUND_STATEMENTS: Final = STATEMENT - {syms.except_clause, syms.case_block}
33+
2934
COMMENT_EXCEPTIONS = " !:#'"
3035
_COMMENT_PREFIX = "# "
3136
_COMMENT_LIST_SEPARATOR = ";"
@@ -322,112 +327,99 @@ def generate_ignored_nodes(
322327

323328

324329
def _find_compound_statement_context(
325-
parent: Optional[LN],
326-
) -> tuple[Optional[Node], Optional[Node]]:
327-
"""Find compound statement and suite nodes for fmt: skip handling."""
330+
parent: Optional[LN], mode: Mode
331+
) -> Optional[Node]:
332+
"""Return the body node of a compound statement if we should respect fmt: skip.
333+
334+
This handles one-line compound statements like:
335+
if condition: body # fmt: skip
336+
337+
When Black expands such statements, they temporarily look like:
338+
if condition:
339+
body # fmt: skip
340+
341+
In both cases, we want to return the body node (either the simple_stmt directly
342+
or the suite containing it).
343+
"""
344+
if Preview.fix_fmt_skip_in_one_liners not in mode:
345+
return None
346+
328347
if parent is None or parent.type != syms.simple_stmt:
329-
return None, None
348+
return None
349+
350+
assert isinstance(parent, Node)
330351

331-
# Case 1: simple_stmt -> suite -> compound_stmt (after reformatting)
352+
# Case 1: Expanded form after Black's initial formatting pass.
353+
# The one-liner has been split across multiple lines:
354+
# if True:
355+
# print("a"); print("b") # fmt: skip
356+
# Structure: compound_stmt -> suite -> simple_stmt
332357
if (
333-
parent.parent is not None
358+
isinstance(parent.parent, Node)
334359
and parent.parent.type == syms.suite
335-
and parent.parent.parent is not None
360+
and isinstance(parent.parent.parent, Node)
361+
and parent.parent.parent.type in _COMPOUND_STATEMENTS
336362
):
337-
assert isinstance(parent.parent, Node)
338-
suite_node = parent.parent
339-
assert isinstance(suite_node.parent, Node)
340-
compound_parent = suite_node.parent
341-
return compound_parent, suite_node
342-
343-
# Case 2: simple_stmt -> compound_stmt (original structure)
344-
compound_types = (
345-
syms.if_stmt,
346-
syms.while_stmt,
347-
syms.for_stmt,
348-
syms.try_stmt,
349-
syms.with_stmt,
350-
syms.funcdef,
351-
syms.classdef,
352-
)
353-
if parent.parent is not None and parent.parent.type in compound_types:
354-
assert isinstance(parent.parent, Node)
355-
compound_parent = parent.parent
356-
# In original single-line structure, the simple_stmt IS the body
357-
assert isinstance(parent, Node) # simple_stmt is always a Node
358-
return compound_parent, parent
359-
360-
return None, None
361-
362-
363-
def _get_compound_statement_header(
364-
compound_parent: Node, suite_node: Node, parent: LN
365-
) -> list[LN]:
366-
"""Get header nodes for compound statement if it should be preserved."""
367-
compound_types = (
368-
syms.if_stmt,
369-
syms.while_stmt,
370-
syms.for_stmt,
371-
syms.try_stmt,
372-
syms.with_stmt,
373-
syms.funcdef,
374-
syms.classdef,
375-
)
376-
if compound_parent.type not in compound_types:
377-
return []
363+
return parent.parent
378364

379-
# Check if the body contains semicolon-separated statements
380-
has_semicolon = False
381-
if suite_node.type == syms.suite:
382-
# After reformatting, check if the suite contains semicolons
383-
for child in suite_node.children:
384-
if hasattr(child, "children"):
385-
for grandchild in child.children:
386-
if getattr(grandchild, "type", None) == token.SEMI:
387-
has_semicolon = True
388-
break
389-
if has_semicolon:
390-
break
391-
else:
392-
# Original structure - check the simple_stmt for semicolons
393-
for child in suite_node.children:
394-
if getattr(child, "type", None) == token.SEMI:
395-
has_semicolon = True
396-
break
365+
# Case 2: Original one-line form from the input source.
366+
# The statement is still on a single line:
367+
# if True: print("a"); print("b") # fmt: skip
368+
# Structure: compound_stmt -> simple_stmt
369+
if (
370+
isinstance(parent.parent, Node)
371+
and parent.parent.type in _COMPOUND_STATEMENTS
372+
):
373+
return parent
397374

398-
# Only apply our fix for compound statements with semicolon-separated bodies
399-
if not has_semicolon:
400-
return []
375+
return None
401376

402-
# Check if this is a single-line compound statement
403-
if suite_node.type == syms.suite:
404-
# Case 1: After reformatting, body is in a suite
405-
stmt_children = [
406-
child
407-
for child in suite_node.children
408-
if child.type not in (token.NEWLINE, token.INDENT, token.DEDENT)
409-
]
410-
single_line_body = len(stmt_children) == 1 and (
411-
stmt_children[0] == parent
412-
or any(
413-
c == parent
414-
for c in stmt_children[0].children
415-
if hasattr(stmt_children[0], "children")
416-
)
417-
)
418-
else:
419-
# Case 2: Original structure, suite_node is the simple_stmt body
420-
single_line_body = suite_node == parent
421377

422-
if not single_line_body:
423-
return []
378+
def _should_keep_compound_statement_inline(
379+
body_node: Node, simple_stmt_parent: Node
380+
) -> bool:
381+
"""Check if a compound statement should be kept on one line.
382+
383+
Returns True only for compound statements with semicolon-separated bodies,
384+
like: if True: print("a"); print("b") # fmt: skip
385+
"""
386+
# Check if there are semicolons in the body
387+
for leaf in body_node.leaves():
388+
if leaf.type == token.SEMI:
389+
# Verify it's a single-line body (one simple_stmt)
390+
if body_node.type == syms.suite:
391+
# After formatting: check suite has one simple_stmt child
392+
simple_stmts = [
393+
child
394+
for child in body_node.children
395+
if child.type == syms.simple_stmt
396+
]
397+
return len(simple_stmts) == 1 and simple_stmts[0] is simple_stmt_parent
398+
else:
399+
# Original form: body_node IS the simple_stmt
400+
return body_node is simple_stmt_parent
401+
return False
402+
424403

425-
# Include the compound statement header
404+
def _get_compound_statement_header(body_node: Node, simple_stmt_parent: Node) -> list[LN]:
405+
"""Get header nodes for a compound statement that should be preserved inline."""
406+
if not _should_keep_compound_statement_inline(body_node, simple_stmt_parent):
407+
return []
408+
409+
# Get the compound statement (parent of body)
410+
compound_stmt = body_node.parent
411+
if compound_stmt is None or compound_stmt.type not in _COMPOUND_STATEMENTS:
412+
return []
413+
414+
# Collect all header leaves before the body
426415
header_leaves: list[LN] = []
427-
for child in compound_parent.children:
428-
if child == suite_node:
416+
for child in compound_stmt.children:
417+
if child is body_node:
429418
break
430-
if child.type not in (token.NEWLINE, token.INDENT):
419+
if isinstance(child, Leaf):
420+
if child.type not in (token.NEWLINE, token.INDENT):
421+
header_leaves.append(child)
422+
else:
431423
header_leaves.extend(child.leaves())
432424
return header_leaves
433425

@@ -494,15 +486,9 @@ def _generate_ignored_nodes_from_fmt_skip(
494486
if current_node.prev_sibling is None and current_node.parent is not None:
495487
current_node = current_node.parent
496488
# Special handling for compound statements with semicolon-separated bodies
497-
compound_parent, suite_node = _find_compound_statement_context(parent)
498-
if (
499-
compound_parent is not None
500-
and suite_node is not None
501-
and parent is not None
502-
):
503-
header_nodes = _get_compound_statement_header(
504-
compound_parent, suite_node, parent
505-
)
489+
body_node = _find_compound_statement_context(parent, mode)
490+
if body_node is not None and isinstance(parent, Node):
491+
header_nodes = _get_compound_statement_header(body_node, parent)
506492
if header_nodes:
507493
ignored_nodes = header_nodes + ignored_nodes
508494

0 commit comments

Comments
 (0)