From 2433e8529dd9b2188faa88b4796ebffcaf5d0c2a Mon Sep 17 00:00:00 2001 From: Pedro Mezacasa Muller Date: Sat, 18 Jan 2025 02:43:54 -0300 Subject: [PATCH] Fix bug where # fmt: skip is not being respect with one-liner functions (#4535) --- CHANGES.md | 3 +++ src/black/comments.py | 41 ++++++++++++++++++++++++++++++----- tests/data/cases/fmtskip10.py | 1 + 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 tests/data/cases/fmtskip10.py diff --git a/CHANGES.md b/CHANGES.md index 416aabcdf13..ae5d4341fbe 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,9 @@ - Fix crash when formatting `with` statements containing tuple generators/unpacking (#4538) +- Fix a bug where one-liner functions marked with `# fmt: skip` would still be + formatted (#4552) + ### Preview style diff --git a/src/black/comments.py b/src/black/comments.py index b7aeca2a6a7..72c4cd9b1d9 100644 --- a/src/black/comments.py +++ b/src/black/comments.py @@ -318,18 +318,48 @@ def _generate_ignored_nodes_from_fmt_skip( """Generate all leaves that should be ignored by the `# fmt: skip` from `leaf`.""" prev_sibling = leaf.prev_sibling parent = leaf.parent + ignored_nodes: list[LN] = [] # Need to properly format the leaf prefix to compare it to comment.value, # which is also formatted comments = list_comments(leaf.prefix, is_endmarker=False) if not comments or comment.value != comments[0].value: return if prev_sibling is not None: + # Generates the nodes to be ignored by `fmt: skip`. + + # Nodes to ignore are those on the same line as the `# fmt: skip` comment, + # excluding the `# fmt: skip` node itself. + + # Traversal process (starting at the `# fmt: skip` node): + # 1. Move to the `prev_sibling` of the current node. + # 2. If `prev_sibling` has children, go to its rightmost leaf. + # 3. If there’s no `prev_sibling`, move up to the parent node and repeat. + # 4. Continue until: + # a. You encounter an `INDENT` or `NEWLINE` node (indicates + # start of the line). + # b. You reach the root node. + + # Include all visited LEAVES in the ignored list, except INDENT + # or NEWLINE leaves. + leaf.prefix = "" - siblings = [prev_sibling] - while "\n" not in prev_sibling.prefix and prev_sibling.prev_sibling is not None: - prev_sibling = prev_sibling.prev_sibling - siblings.insert(0, prev_sibling) - yield from siblings + current_node = prev_sibling + ignored_nodes = [current_node] + if current_node.prev_sibling is None and current_node.parent is not None: + current_node = current_node.parent + while "\n" not in current_node.prefix and current_node.prev_sibling is not None: + leaf_nodes = list(current_node.prev_sibling.leaves()) + current_node = leaf_nodes[-1] if leaf_nodes else current_node + + if current_node.type in (token.NEWLINE, token.INDENT): + current_node.prefix = "" + break + + ignored_nodes.insert(0, current_node) + + if current_node.prev_sibling is None and current_node.parent is not None: + current_node = current_node.parent + yield from ignored_nodes elif ( parent is not None and parent.type == syms.suite and leaf.type == token.NEWLINE ): @@ -337,7 +367,6 @@ def _generate_ignored_nodes_from_fmt_skip( # statements. The ignored nodes should be previous siblings of the # parent suite node. leaf.prefix = "" - ignored_nodes: list[LN] = [] parent_sibling = parent.prev_sibling while parent_sibling is not None and parent_sibling.type != syms.suite: ignored_nodes.insert(0, parent_sibling) diff --git a/tests/data/cases/fmtskip10.py b/tests/data/cases/fmtskip10.py new file mode 100644 index 00000000000..d8c2a56d4e4 --- /dev/null +++ b/tests/data/cases/fmtskip10.py @@ -0,0 +1 @@ +def foo(): return "mock" # fmt: skip \ No newline at end of file