Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
lengths (#5147)
- Fix multiline docstring indentation when leading tabs are used inside indented
docstrings (#5148)
- Fix a crash on a `# fmt: skip` line placed directly after an opening bracket when a
standalone comment is also present among the contents (#5161)

### Preview style

Expand Down
21 changes: 13 additions & 8 deletions src/black/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -1271,34 +1271,39 @@ def is_line_short_enough(line: Line, *, mode: Mode, line_str: str = "") -> bool:

max_level_to_update: int | float = math.inf # track the depth of the MLS
for i, leaf in enumerate(line.leaves):
# A closing bracket continued from a previous line break (e.g. a leftover
# `)` left on its own line) is never marked by the bracket tracker, so it
# has no `bracket_depth`. Such a leaf is not inside any bracket that opened
# on this line, so treat it as depth 0.
bracket_depth = getattr(leaf, "bracket_depth", 0)
if max_level_to_update == math.inf:
had_comma: int | None = None
if leaf.bracket_depth + 1 > len(commas):
if bracket_depth + 1 > len(commas):
commas.append(0)
elif leaf.bracket_depth + 1 < len(commas):
elif bracket_depth + 1 < len(commas):
had_comma = commas.pop()
if (
had_comma is not None
and multiline_string is not None
and multiline_string.bracket_depth == leaf.bracket_depth + 1
and multiline_string.bracket_depth == bracket_depth + 1
):
# Have left the level with the MLS, stop tracking commas
max_level_to_update = leaf.bracket_depth
max_level_to_update = bracket_depth
if had_comma > 0:
# MLS was in parens with at least one comma - force split
return False

if leaf.bracket_depth <= max_level_to_update and leaf.type == token.COMMA:
if bracket_depth <= max_level_to_update and leaf.type == token.COMMA:
# Inside brackets, ignore trailing comma
# directly after MLS/MLS-containing expression
ignore_ctxs: list[LN | None] = [None]
ignore_ctxs += multiline_string_contexts
if (line.inside_brackets or leaf.bracket_depth > 0) and (
if (line.inside_brackets or bracket_depth > 0) and (
i != len(line.leaves) - 1 or leaf.prev_sibling not in ignore_ctxs
):
commas[leaf.bracket_depth] += 1
commas[bracket_depth] += 1
if max_level_to_update != math.inf:
max_level_to_update = min(max_level_to_update, leaf.bracket_depth)
max_level_to_update = min(max_level_to_update, bracket_depth)

if is_multiline_string(leaf):
if leaf.parent and (
Expand Down
50 changes: 50 additions & 0 deletions tests/data/cases/fmtskip_after_bracket_with_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Regression tests for a crash with `AttributeError: 'Leaf' object has no
# attribute 'bracket_depth'`. A `# fmt: skip` line directly after an opening
# bracket combined with a standalone comment among the contents used to crash
# inside `is_line_short_enough`.

from m import (
# fmt: skip
# comment
a
)

f(
# fmt: skip
# comment
a
)

x[
# fmt: skip
# comment
a
]

from m import ( # fmt: skip
# comment
a
)

# output

# Regression tests for a crash with `AttributeError: 'Leaf' object has no
# attribute 'bracket_depth'`. A `# fmt: skip` line directly after an opening
# bracket combined with a standalone comment among the contents used to crash
# inside `is_line_short_enough`.

from m import (# fmt: skip # comment
a
)

f(# fmt: skip # comment
a
)

x[# fmt: skip # comment
a
]

from m import ( # fmt: skip # comment
a
)