Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/lines.py: 17%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import itertools
2import math
3from collections.abc import Callable, Iterator, Sequence
4from dataclasses import dataclass, field
5from typing import NamedTuple, Optional, TypeVar, Union, cast
7from black.brackets import COMMA_PRIORITY, DOT_PRIORITY, BracketTracker
8from black.comments import FMT_ON, contains_fmt_directive
9from black.mode import Mode, Preview
10from black.nodes import (
11 BRACKETS,
12 CLOSING_BRACKETS,
13 COMPARATORS,
14 MATH_OPERATORS,
15 OPENING_BRACKETS,
16 STANDALONE_COMMENT,
17 TEST_DESCENDANTS,
18 child_towards,
19 first_leaf,
20 is_docstring,
21 is_generator,
22 is_import,
23 is_multiline_string,
24 is_one_element_subscript,
25 is_one_sequence_between,
26 is_one_tuple,
27 is_tuple,
28 is_type_comment,
29 is_type_ignore_comment,
30 is_with_or_async_with_stmt,
31 last_leaf,
32 make_simple_prefix,
33 replace_child,
34 syms,
35 whitespace,
36)
37from black.strings import str_width
38from blib2to3.pgen2 import token
39from blib2to3.pytree import Leaf, Node
41# types
42T = TypeVar("T")
43Index = int
44LeafID = int
45LN = Union[Leaf, Node]
48@dataclass
49class Line:
50 """Holds leaves and comments. Can be printed with `str(line)`."""
52 mode: Mode = field(repr=False)
53 depth: int = 0
54 leaves: list[Leaf] = field(default_factory=list)
55 # keys ordered like `leaves`
56 comments: dict[LeafID, list[Leaf]] = field(default_factory=dict)
57 bracket_tracker: BracketTracker = field(default_factory=BracketTracker)
58 inside_brackets: bool = False
59 should_split_rhs: bool = False
60 magic_trailing_comma: Leaf | None = None
61 _complex_subscript_cache: dict[LeafID, bool] = field(
62 default_factory=dict, repr=False
63 )
65 def append(
66 self, leaf: Leaf, preformatted: bool = False, track_bracket: bool = False
67 ) -> None:
68 """Add a new `leaf` to the end of the line.
70 Unless `preformatted` is True, the `leaf` will receive a new consistent
71 whitespace prefix and metadata applied by :class:`BracketTracker`.
72 Trailing commas are maybe removed, unpacked for loop variables are
73 demoted from being delimiters.
75 Inline comments are put aside.
76 """
77 has_value = (
78 leaf.type in BRACKETS
79 # empty fstring and tstring middles must not be truncated
80 or leaf.type in (token.FSTRING_MIDDLE, token.TSTRING_MIDDLE)
81 or bool(leaf.value.strip())
82 )
83 if not has_value:
84 return
86 if leaf.type == token.COLON and self.is_class_paren_empty:
87 del self.leaves[-2:]
88 if self.leaves and not preformatted:
89 # Note: at this point leaf.prefix should be empty except for
90 # imports, for which we only preserve newlines.
91 leaf.prefix += whitespace(
92 leaf,
93 complex_subscript=self.is_complex_subscript(leaf),
94 mode=self.mode,
95 )
96 if self.inside_brackets or not preformatted or track_bracket:
97 self.bracket_tracker.mark(leaf)
98 if self.mode.magic_trailing_comma:
99 if self.has_magic_trailing_comma(leaf):
100 self.magic_trailing_comma = leaf
101 elif self.has_magic_trailing_comma(leaf) and not (
102 # The trailing comma of a one-element tuple or subscript is
103 # syntactically required, not magic, so it must never be removed.
104 # This is normally caught by has_magic_trailing_comma, but that
105 # check misses it when the opening bracket was split onto an
106 # earlier line (for example by a standalone comment inside the
107 # brackets), so verify against the tree here before dropping it.
108 leaf.parent is not None
109 and (is_one_tuple(leaf.parent) or is_one_element_subscript(leaf.parent))
110 ):
111 self.remove_trailing_comma()
112 if not self.append_comment(leaf):
113 self.leaves.append(leaf)
115 def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
116 """Like :func:`append()` but disallow invalid standalone comment structure.
118 Raises ValueError when any `leaf` is appended after a standalone comment
119 or when a standalone comment is not the first leaf on the line.
120 """
121 if (
122 self.bracket_tracker.depth == 0
123 or self.bracket_tracker.any_open_for_or_lambda()
124 ):
125 if self.is_comment:
126 raise ValueError("cannot append to standalone comments")
128 if self.leaves and leaf.type == STANDALONE_COMMENT:
129 raise ValueError(
130 "cannot append standalone comments to a populated line"
131 )
133 self.append(leaf, preformatted=preformatted)
135 @property
136 def is_comment(self) -> bool:
137 """Is this line a standalone comment?"""
138 return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
140 @property
141 def is_decorator(self) -> bool:
142 """Is this line a decorator?"""
143 return bool(self) and self.leaves[0].type == token.AT
145 @property
146 def is_import(self) -> bool:
147 """Is this an import line?"""
148 return bool(self) and is_import(self.leaves[0])
150 @property
151 def is_with_or_async_with_stmt(self) -> bool:
152 """Is this a with_stmt line?"""
153 return bool(self) and is_with_or_async_with_stmt(self.leaves[0])
155 @property
156 def is_class(self) -> bool:
157 """Is this line a class definition?"""
158 return (
159 bool(self)
160 and self.leaves[0].type == token.NAME
161 and self.leaves[0].value == "class"
162 )
164 @property
165 def is_stub_class(self) -> bool:
166 """Is this line a class definition with a body consisting only of "..."?"""
167 return self.is_class and self.leaves[-3:] == [
168 Leaf(token.DOT, ".") for _ in range(3)
169 ]
171 @property
172 def is_def(self) -> bool:
173 """Is this a function definition? (Also returns True for async defs.)"""
174 try:
175 first_leaf = self.leaves[0]
176 except IndexError:
177 return False
179 try:
180 second_leaf: Leaf | None = self.leaves[1]
181 except IndexError:
182 second_leaf = None
183 return (first_leaf.type == token.NAME and first_leaf.value == "def") or (
184 first_leaf.type == token.ASYNC
185 and second_leaf is not None
186 and second_leaf.type == token.NAME
187 and second_leaf.value == "def"
188 )
190 @property
191 def is_stub_def(self) -> bool:
192 """Is this line a function definition with a body consisting only of "..."?"""
193 return self.is_def and self.leaves[-4:] == [Leaf(token.COLON, ":")] + [
194 Leaf(token.DOT, ".") for _ in range(3)
195 ]
197 @property
198 def is_class_paren_empty(self) -> bool:
199 """Is this a class with no base classes but using parentheses?
201 Those are unnecessary and should be removed.
202 """
203 return (
204 bool(self)
205 and len(self.leaves) == 4
206 and self.is_class
207 and self.leaves[2].type == token.LPAR
208 and self.leaves[2].value == "("
209 and self.leaves[3].type == token.RPAR
210 and self.leaves[3].value == ")"
211 )
213 @property
214 def is_docstring(self) -> bool:
215 """Is the line a docstring?"""
216 return bool(self) and is_docstring(self.leaves[0])
218 @property
219 def is_chained_assignment(self) -> bool:
220 """Is the line a chained assignment"""
221 return [leaf.type for leaf in self.leaves].count(token.EQUAL) > 1
223 @property
224 def opens_block(self) -> bool:
225 """Does this line open a new level of indentation."""
226 if len(self.leaves) == 0:
227 return False
228 return self.leaves[-1].type == token.COLON
230 def is_fmt_pass_converted(
231 self, *, first_leaf_matches: Callable[[Leaf], bool] | None = None
232 ) -> bool:
233 """Is this line converted from fmt off/skip code?
235 If first_leaf_matches is not None, it only returns True if the first
236 leaf of converted code matches.
237 """
238 if len(self.leaves) != 1:
239 return False
240 leaf = self.leaves[0]
241 if (
242 leaf.type != STANDALONE_COMMENT
243 or leaf.fmt_pass_converted_first_leaf is None
244 ):
245 return False
246 return first_leaf_matches is None or first_leaf_matches(
247 leaf.fmt_pass_converted_first_leaf
248 )
250 def contains_standalone_comments(self) -> bool:
251 """If so, needs to be split before emitting."""
252 for leaf in self.leaves:
253 if leaf.type == STANDALONE_COMMENT:
254 return True
256 return False
258 def contains_implicit_multiline_string_with_comments(self) -> bool:
259 """Check if we have an implicit multiline string with comments on the line"""
260 for leaf_type, leaf_group_iterator in itertools.groupby(
261 self.leaves, lambda leaf: leaf.type
262 ):
263 if leaf_type != token.STRING:
264 continue
265 leaf_list = list(leaf_group_iterator)
266 if len(leaf_list) == 1:
267 continue
268 if leaf_list[-1] is self.leaves[-1] and any(self.comments.values()):
269 # Joining the line would print its comments after these strings.
270 return True
271 for leaf in leaf_list:
272 if self.comments_after(leaf):
273 return True
274 return False
276 def contains_uncollapsable_type_comments(self) -> bool:
277 ignored_ids = set()
278 try:
279 last_leaf = self.leaves[-1]
280 ignored_ids.add(id(last_leaf))
281 if last_leaf.type == token.COMMA or (
282 last_leaf.type == token.RPAR and not last_leaf.value
283 ):
284 # When trailing commas or optional parens are inserted by Black for
285 # consistency, comments after the previous last element are not moved
286 # (they don't have to, rendering will still be correct). So we ignore
287 # trailing commas and invisible.
288 last_leaf = self.leaves[-2]
289 ignored_ids.add(id(last_leaf))
290 except IndexError:
291 return False
293 # A type comment is uncollapsable if it is attached to a leaf
294 # that isn't at the end of the line (since that could cause it
295 # to get associated to a different argument) or if there are
296 # comments before it (since that could cause it to get hidden
297 # behind a comment.
298 comment_seen = False
299 for leaf_id, comments in self.comments.items():
300 for comment in comments:
301 if is_type_comment(comment, mode=self.mode):
302 if comment_seen or (
303 not is_type_ignore_comment(comment, mode=self.mode)
304 and leaf_id not in ignored_ids
305 ):
306 return True
308 comment_seen = True
310 return False
312 def contains_multiple_type_ignores_at_current_depth(self) -> bool:
313 count = 0
314 for leaf in self.leaves:
315 if leaf.bracket_depth != 0:
316 continue
317 for comment in self.comments_after(leaf):
318 if is_type_ignore_comment(comment, mode=self.mode):
319 count += 1
320 if count > 1:
321 return True
322 return False
324 def contains_unsplittable_type_ignore(self) -> bool:
325 if not self.leaves:
326 return False
328 # If a 'type: ignore' is attached to the end of a line, we
329 # can't split the line, because we can't know which of the
330 # subexpressions the ignore was meant to apply to.
331 #
332 # We only want this to apply to actual physical lines from the
333 # original source, though: we don't want the presence of a
334 # 'type: ignore' at the end of a multiline expression to
335 # justify pushing it all onto one line. Thus we
336 # (unfortunately) need to check the actual source lines and
337 # only report an unsplittable 'type: ignore' if this line was
338 # one line in the original code.
340 # Grab the first and last line numbers, skipping generated leaves
341 first_line = next((leaf.lineno for leaf in self.leaves if leaf.lineno != 0), 0)
342 last_line = next(
343 (leaf.lineno for leaf in reversed(self.leaves) if leaf.lineno != 0), 0
344 )
346 if first_line == last_line and first_line != 0:
347 # We look at the last two leaves since a comma or an
348 # invisible paren could have been added at the end of the
349 # line.
350 for node in self.leaves[-2:]:
351 for comment in self.comments.get(id(node), []):
352 if is_type_ignore_comment(comment, mode=self.mode):
353 return True
355 return False
357 def contains_multiline_strings(self) -> bool:
358 return any(is_multiline_string(leaf) for leaf in self.leaves)
360 def has_magic_trailing_comma(self, closing: Leaf) -> bool:
361 """Return True if we have a magic trailing comma, that is when:
362 - there's a trailing comma here
363 - it's not from single-element square bracket indexing
364 - it's not a one-tuple
365 """
366 if not (
367 closing.type in CLOSING_BRACKETS
368 and self.leaves
369 and self.leaves[-1].type == token.COMMA
370 ):
371 return False
373 if closing.type == token.RBRACE:
374 return True
376 if closing.type == token.RSQB:
377 if (
378 closing.parent is not None
379 and closing.parent.type == syms.trailer
380 and closing.opening_bracket is not None
381 and is_one_sequence_between(
382 closing.opening_bracket,
383 closing,
384 self.leaves,
385 brackets=(token.LSQB, token.RSQB),
386 )
387 ):
388 assert closing.prev_sibling is not None
389 assert closing.prev_sibling.type == syms.subscriptlist
390 return False
392 return True
394 if self.is_import:
395 return True
397 if closing.opening_bracket is not None and not is_one_sequence_between(
398 closing.opening_bracket, closing, self.leaves
399 ):
400 return True
402 return False
404 def append_comment(self, comment: Leaf) -> bool:
405 """Add an inline or standalone comment to the line."""
406 if (
407 comment.type == STANDALONE_COMMENT
408 and self.bracket_tracker.any_open_brackets()
409 ):
410 comment.prefix = ""
411 return False
413 if comment.type != token.COMMENT:
414 return False
416 if not self.leaves:
417 comment.type = STANDALONE_COMMENT
418 comment.prefix = ""
419 return False
421 last_leaf = self.leaves[-1]
422 if (
423 last_leaf.type == token.RPAR
424 and not last_leaf.value
425 and last_leaf.parent
426 and len(list(last_leaf.parent.leaves())) <= 3
427 and not is_type_comment(comment, mode=self.mode)
428 and not self.contains_standalone_comments()
429 ):
430 # Comments on an optional parens wrapping a single leaf should belong to
431 # the wrapped node except if it's a type comment. Pinning the comment like
432 # this avoids unstable formatting caused by comment migration. If the
433 # parens contain standalone comments they are going to stay visible, so
434 # the comment belongs to the closing paren, as it was written.
435 if len(self.leaves) >= 2:
436 last_leaf = self.leaves[-2]
437 self.comments.setdefault(id(last_leaf), []).append(comment)
438 return True
440 def comments_after(self, leaf: Leaf) -> list[Leaf]:
441 """Generate comments that should appear directly after `leaf`."""
442 return self.comments.get(id(leaf), [])
444 def remove_trailing_comma(self) -> None:
445 """Remove the trailing comma and moves the comments attached to it."""
446 trailing_comma = self.leaves.pop()
447 trailing_comma_comments = self.comments.pop(id(trailing_comma), [])
448 self.comments.setdefault(id(self.leaves[-1]), []).extend(
449 trailing_comma_comments
450 )
452 def is_complex_subscript(self, leaf: Leaf) -> bool:
453 """Return True iff `leaf` is part of a slice with non-trivial exprs."""
454 open_lsqb = self.bracket_tracker.get_open_lsqb()
455 if open_lsqb is None:
456 return False
458 subscript_start = open_lsqb.next_sibling
460 if isinstance(subscript_start, Node):
461 if subscript_start.type == syms.listmaker:
462 return False
464 if subscript_start.type == syms.subscriptlist:
465 subscript_start = child_towards(subscript_start, leaf)
467 if subscript_start is None:
468 return False
470 # The pre_order walk only depends on subscript_start, which is stable
471 # while a line is built, so cache it per node. Without this, appending
472 # every leaf of a large bracketed expression that holds no TEST_DESCENDANTS
473 # node (e.g. a long run of implicitly concatenated strings) re-walks the
474 # whole subtree each time, which is quadratic.
475 key = id(subscript_start)
476 cached = self._complex_subscript_cache.get(key)
477 if cached is None:
478 cached = any(
479 n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
480 )
481 self._complex_subscript_cache[key] = cached
482 return cached
484 def enumerate_with_length(
485 self, is_reversed: bool = False
486 ) -> Iterator[tuple[Index, Leaf, int]]:
487 """Return an enumeration of leaves with their length.
489 Stops prematurely on multiline strings and standalone comments.
490 """
491 op = cast(
492 Callable[[Sequence[Leaf]], Iterator[tuple[Index, Leaf]]],
493 enumerate_reversed if is_reversed else enumerate,
494 )
495 for index, leaf in op(self.leaves):
496 length = len(leaf.prefix) + len(leaf.value)
497 if "\n" in leaf.value:
498 return # Multiline strings, we can't continue.
500 for comment in self.comments_after(leaf):
501 length += len(comment.value)
503 yield index, leaf, length
505 def clone(self) -> "Line":
506 return Line(
507 mode=self.mode,
508 depth=self.depth,
509 inside_brackets=self.inside_brackets,
510 should_split_rhs=self.should_split_rhs,
511 magic_trailing_comma=self.magic_trailing_comma,
512 )
514 def __str__(self) -> str:
515 """Render the line."""
516 if not self:
517 return "\n"
519 indent = " " * self.depth
520 leaves = iter(self.leaves)
521 first = next(leaves)
522 res = f"{first.prefix}{indent}{first.value}"
523 res += "".join(str(leaf) for leaf in leaves)
524 comments = list(itertools.chain.from_iterable(self.comments.values()))
525 if len(comments) > 1:
526 # Python only recognizes a `# type: ignore` at the start of a comment, so
527 # it has to come first when comments from several lines end up on one.
528 comments.sort(
529 key=lambda comment: not is_type_ignore_comment(comment, mode=self.mode)
530 )
531 res += "".join(str(comment) for comment in comments)
533 return res + "\n"
535 def __bool__(self) -> bool:
536 """Return True if the line has leaves or comments."""
537 return bool(self.leaves or self.comments)
540@dataclass
541class RHSResult:
542 """Intermediate split result from a right hand split."""
544 head: Line
545 body: Line
546 tail: Line
547 opening_bracket: Leaf
548 closing_bracket: Leaf
551@dataclass
552class LinesBlock:
553 """Class that holds information about a block of formatted lines.
555 This is introduced so that the EmptyLineTracker can look behind the standalone
556 comments and adjust their empty lines for class or def lines.
557 """
559 mode: Mode
560 previous_block: Optional["LinesBlock"]
561 original_line: Line
562 before: int = 0
563 content_lines: list[str] = field(default_factory=list)
564 after: int = 0
565 form_feed: bool = False
567 def all_lines(self) -> list[str]:
568 empty_line = str(Line(mode=self.mode))
569 prefix = make_simple_prefix(self.before, self.form_feed, empty_line)
570 return [prefix] + self.content_lines + [empty_line * self.after]
573_WHITESPACE_TOKENS = (
574 token.NEWLINE,
575 token.NL,
576 token.INDENT,
577 token.DEDENT,
578 token.COMMENT,
579 token.ENDMARKER,
580)
583class _DecoratedFuncInfo(NamedTuple):
584 """Tracks the most recently seen decorated function for overload grouping."""
586 name: str
587 depth: int
588 is_multi: bool
591@dataclass
592class EmptyLineTracker:
593 """Provides a stateful method that returns the number of potential extra
594 empty lines needed before and after the currently processed line.
596 Note: this tracker works on lines that haven't been split yet. It assumes
597 the prefix of the first leaf consists of optional newlines. Those newlines
598 are consumed by `maybe_empty_lines()` and included in the computation.
599 """
601 mode: Mode
602 previous_line: Line | None = None
603 previous_block: LinesBlock | None = None
604 previous_defs: list[Line] = field(default_factory=list)
605 semantic_leading_comment: LinesBlock | None = None
606 _pyi_previous_decorated_func: _DecoratedFuncInfo | None = None
608 @staticmethod
609 def _get_funcdef_name(node: Node | Leaf) -> str | None:
610 """Extract the function name from a funcdef or async_funcdef node."""
611 funcdef: Node | Leaf = node
612 if isinstance(node, Node) and node.type == syms.async_funcdef:
613 for sub in node.children:
614 if sub.type == syms.funcdef:
615 funcdef = sub
616 break
617 if not isinstance(funcdef, Node) or funcdef.type != syms.funcdef:
618 return None
619 # Grammar: funcdef = 'def' NAME parameters ':' ...
620 # `# fmt: skip` turns the leaves of a one-line definition into a
621 # STANDALONE_COMMENT, so there may be no name left to read.
622 if len(funcdef.children) < 2 or funcdef.children[1].type != token.NAME:
623 return None
624 name_node = funcdef.children[1]
625 assert isinstance(name_node, Leaf)
626 return name_node.value
628 @staticmethod
629 def _decorated_node_has_func_named(node: Node, name: str) -> bool:
630 """Check if a ``decorated`` node contains a function with the given name."""
631 return any(
632 sub.type in (syms.funcdef, syms.async_funcdef)
633 and EmptyLineTracker._get_funcdef_name(sub) == name
634 for sub in node.children
635 )
637 @staticmethod
638 def _find_adjacent_decorated(
639 node: Node | Leaf, *, reverse: bool = False
640 ) -> Node | None:
641 """Walk siblings skipping whitespace tokens, returning the first
642 ``decorated`` node found or ``None``."""
643 sibling = node.prev_sibling if reverse else node.next_sibling
644 while sibling is not None:
645 if sibling.type == syms.decorated:
646 assert isinstance(sibling, Node)
647 return sibling
648 elif sibling.type in _WHITESPACE_TOKENS:
649 sibling = sibling.prev_sibling if reverse else sibling.next_sibling
650 else:
651 return None
652 return None
654 @staticmethod
655 def _get_suite_first_decorated_funcname(suite: Node) -> str | None:
656 """Return the function name of the first decorated function in a suite."""
657 for child in suite.children:
658 if isinstance(child, Node) and child.type == syms.decorated:
659 for sub in child.children:
660 if sub.type in (syms.funcdef, syms.async_funcdef):
661 return EmptyLineTracker._get_funcdef_name(sub)
662 break
663 if child.type not in (token.NEWLINE, token.NL, token.INDENT, token.DEDENT):
664 break
665 return None
667 @staticmethod
668 def _if_stmt_branch_has_func_named(
669 if_stmt: Node, exclude_suite: Node, name: str
670 ) -> bool:
671 """Check if any branch of an ``if_stmt`` (other than *exclude_suite*)
672 contains a decorated function with the given *name*."""
673 for child in if_stmt.children:
674 if not isinstance(child, Node):
675 continue
676 if child.type != syms.suite:
677 continue
678 if child is exclude_suite:
679 continue
680 for stmt in child.children:
681 if not isinstance(stmt, Node):
682 continue
683 if stmt.type != syms.decorated:
684 continue
685 if EmptyLineTracker._decorated_node_has_func_named(stmt, name):
686 return True
687 break
688 return False
690 @staticmethod
691 def _get_def_name(line: Line) -> str | None:
692 """Extract the function name from a line that is a function definition."""
693 if not line.is_def or not line.leaves:
694 return None
695 if line.leaves[0].value == "def":
696 return line.leaves[1].value
697 # async def: leaves = ['async', 'def', NAME, ...]
698 return line.leaves[2].value
700 @staticmethod
701 def _is_line_decorated(line: Line) -> bool:
702 """Check if a def line is part of a decorated statement."""
703 if not line.is_def or not line.leaves:
704 return False
705 return EmptyLineTracker._find_decorated_node(line) is not None
707 @staticmethod
708 def _find_decorated_node(line: Line) -> Node | None:
709 """Walk up from the first leaf of a line to its ``decorated`` node."""
710 if not line.leaves:
711 return None
712 node = line.leaves[0].parent
713 while node is not None:
714 if node.type == syms.decorated:
715 assert isinstance(node, Node)
716 return node
717 if node.type in (syms.suite, syms.file_input):
718 return None
719 node = node.parent
720 return None
722 @staticmethod
723 def _get_decorator_target_name(line: Line) -> str | None:
724 """For a decorator line, extract the name of the function it decorates.
726 Only handles decorated functions, not decorated classes.
727 """
728 if not line.is_decorator:
729 return None
730 decorated = EmptyLineTracker._find_decorated_node(line)
731 if decorated is None:
732 return None
733 for child in decorated.children:
734 if child.type in (syms.funcdef, syms.async_funcdef):
735 return EmptyLineTracker._get_funcdef_name(child)
736 return None
738 @staticmethod
739 def _decorator_decorates_class(line: Line) -> bool:
740 """Check if a decorator line decorates a class definition."""
741 if not line.is_decorator:
742 return False
743 decorated = EmptyLineTracker._find_decorated_node(line)
744 if decorated is None:
745 return False
746 return any(child.type == syms.classdef for child in decorated.children)
748 @staticmethod
749 def _def_is_followed_by_same_name_decorated_func(
750 line: Line, *, include_conditional_blocks: bool = False
751 ) -> bool:
752 """Check if a decorated function is followed by a same-name decorated func.
754 If *include_conditional_blocks* is true, the next decorated function may
755 be inside an adjacent conditional block.
756 """
757 name = EmptyLineTracker._get_def_name(line)
758 decorated = EmptyLineTracker._find_decorated_node(line)
759 if name is None or decorated is None:
760 return False
762 sibling = decorated.next_sibling
763 while sibling is not None and sibling.type in _WHITESPACE_TOKENS:
764 sibling = sibling.next_sibling
766 if sibling is None or not isinstance(sibling, Node):
767 return False
768 if sibling.type == syms.decorated:
769 return EmptyLineTracker._decorated_node_has_func_named(sibling, name)
770 if not include_conditional_blocks or sibling.type != syms.if_stmt:
771 return False
772 for child in sibling.children:
773 if not isinstance(child, Node):
774 continue
775 if child.type != syms.suite:
776 continue
777 first_decorated_funcname = (
778 EmptyLineTracker._get_suite_first_decorated_funcname(child)
779 )
780 return first_decorated_funcname == name
781 return False
783 def _is_in_current_group(self, current_line: Line) -> bool:
784 """Check if current_line belongs to the same overload group being tracked."""
785 prev = self._pyi_previous_decorated_func
786 if prev is None:
787 return False
788 cur_name = (
789 self._get_decorator_target_name(current_line)
790 if current_line.is_decorator
791 else self._get_def_name(current_line)
792 )
793 return (
794 cur_name is not None
795 and cur_name == prev.name
796 and prev.depth == current_line.depth
797 and (current_line.is_decorator or self._is_line_decorated(current_line))
798 )
800 @staticmethod
801 def _decorated_node_starts_group(decorated_node: Node) -> bool:
802 """Check if a `decorated` AST node is the first in a multi-function group.
804 Returns True when the next statement-level sibling is also a decorated
805 function with the same name.
806 """
807 name = None
808 for child in decorated_node.children:
809 if child.type in (syms.funcdef, syms.async_funcdef):
810 name = EmptyLineTracker._get_funcdef_name(child)
811 break
812 if name is None:
813 return False
814 adjacent = EmptyLineTracker._find_adjacent_decorated(decorated_node)
815 return adjacent is not None and EmptyLineTracker._decorated_node_has_func_named(
816 adjacent, name
817 )
819 @staticmethod
820 def _is_start_of_decorated_group(line: Line) -> bool:
821 """Check if a decorator line starts a multi-function group.
823 A multi-function group is 2+ consecutive decorated functions sharing the
824 same name (e.g. @overload groups, @property + setter pairs).
825 """
826 if not line.is_decorator:
827 return False
828 decorated_node = EmptyLineTracker._find_decorated_node(line)
829 if decorated_node is None or decorated_node.parent is None:
830 return False
831 return EmptyLineTracker._decorated_node_starts_group(decorated_node)
833 @staticmethod
834 def _get_block_first_decorated_funcname(line: Line) -> str | None:
835 """Return the function name of the first decorated function in a block.
837 *line* must be a block-opening line (ending with ``:``) such as
838 ``if ...:``. Returns ``None`` when the block doesn't start with a
839 decorated function.
840 """
841 if not line.leaves or line.leaves[-1].type != token.COLON:
842 return None
843 suite = line.leaves[-1].next_sibling
844 if suite is None or not isinstance(suite, Node) or suite.type != syms.suite:
845 return None
846 return EmptyLineTracker._get_suite_first_decorated_funcname(suite)
848 @staticmethod
849 def _block_is_part_of_overload_group(line: Line) -> bool:
850 """Check if a block-opening line contains a decorated function that is
851 part of a larger overload group — either because the ``if_stmt``'s next
852 sibling is a same-name decorated function, or because another branch of
853 the same ``if_stmt`` has one.
854 """
855 func_name = EmptyLineTracker._get_block_first_decorated_funcname(line)
856 if func_name is None:
857 return False
859 suite = line.leaves[-1].next_sibling
860 if suite is None or not isinstance(suite, Node):
861 return False
862 if_stmt = suite.parent
863 if if_stmt is None:
864 return False
866 # Check if the if_stmt's next sibling is a same-name decorated function.
867 adjacent = EmptyLineTracker._find_adjacent_decorated(if_stmt)
868 if adjacent is not None and EmptyLineTracker._decorated_node_has_func_named(
869 adjacent, func_name
870 ):
871 return True
873 # Check other branches (elif/else) of the same if_stmt.
874 return EmptyLineTracker._if_stmt_branch_has_func_named(
875 if_stmt, suite, func_name
876 )
878 @staticmethod
879 def _is_decorator_in_conditional_overload(line: Line) -> bool:
880 """Check if a decorator is inside an if/else block that is part of a
881 broader overload group (a sibling or another branch of the same
882 ``if_stmt`` contains a same-name decorated function)."""
883 name = EmptyLineTracker._get_decorator_target_name(line)
884 if name is None:
885 return False
887 decorated = EmptyLineTracker._find_decorated_node(line)
888 if decorated is None:
889 return False
891 suite = decorated.parent
892 if suite is None or suite.type != syms.suite:
893 return False
895 if_stmt = suite.parent
896 if if_stmt is None or if_stmt.type != syms.if_stmt:
897 return False
899 # Check if_stmt's adjacent siblings for same-name decorated function.
900 for reverse in (True, False):
901 adjacent = EmptyLineTracker._find_adjacent_decorated(
902 if_stmt, reverse=reverse
903 )
904 if (
905 adjacent is not None
906 and EmptyLineTracker._decorated_node_has_func_named(adjacent, name)
907 ):
908 return True
910 # Check other branches of the same if_stmt.
911 return EmptyLineTracker._if_stmt_branch_has_func_named(if_stmt, suite, name)
913 def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
914 """Return the number of extra empty lines before and after the `current_line`.
916 This is for separating `def`, `async def` and `class` with extra empty
917 lines (two on module-level).
918 """
919 form_feed = (
920 current_line.depth == 0
921 and bool(current_line.leaves)
922 and "\f\n" in current_line.leaves[0].prefix
923 )
924 before, after = self._maybe_empty_lines(current_line)
925 previous_after = self.previous_block.after if self.previous_block else 0
926 before = max(0, before - previous_after)
928 # Always have one empty line after a module docstring
929 if self._line_is_module_docstring(current_line):
930 before = 1
932 block = LinesBlock(
933 mode=self.mode,
934 previous_block=self.previous_block,
935 original_line=current_line,
936 before=before,
937 after=after,
938 form_feed=form_feed,
939 )
941 # Maintain the semantic_leading_comment state.
942 if current_line.is_comment:
943 if self.previous_line is None or (
944 not self.previous_line.is_decorator
945 # `or before` means this comment already has an empty line before
946 and (not self.previous_line.is_comment or before)
947 and (self.semantic_leading_comment is None or before)
948 ):
949 self.semantic_leading_comment = block
950 # `or before` means this decorator already has an empty line before
951 elif not current_line.is_decorator or before:
952 self.semantic_leading_comment = None
954 # Maintain _pyi_previous_decorated_func state for overload groups.
955 # The tuple is (name, depth, is_multi) where is_multi indicates
956 # the group has 2+ same-name decorated functions.
957 overload_groups = (
958 self.mode.is_pyi and Preview.pyi_overload_group_blank_lines in self.mode
959 )
960 if overload_groups:
961 if current_line.is_def and self._is_line_decorated(current_line):
962 name = self._get_def_name(current_line)
963 if name is not None:
964 prev = self._pyi_previous_decorated_func
965 is_multi = (
966 prev is not None
967 and prev.name == name
968 and prev.depth == current_line.depth
969 )
970 self._pyi_previous_decorated_func = _DecoratedFuncInfo(
971 name=name,
972 depth=current_line.depth,
973 is_multi=is_multi
974 or (prev is not None and prev.name == name and prev.is_multi),
975 )
976 elif (
977 not current_line.is_decorator
978 and not current_line.is_comment
979 and (
980 self._pyi_previous_decorated_func is None
981 or (
982 current_line.depth <= self._pyi_previous_decorated_func.depth
983 # Don't reset on else/elif — they continue an if/else
984 # chain that may contain overloads at a deeper depth.
985 and not (
986 current_line.leaves
987 and current_line.leaves[0].value in ("else", "elif")
988 )
989 )
990 )
991 ):
992 # Only reset when we see a non-decorator line at the same or
993 # lower depth. Body lines (docstrings, ...) at deeper depth
994 # should not clear the state.
995 self._pyi_previous_decorated_func = None
997 self.previous_line = current_line
998 self.previous_block = block
999 return block
1001 def _line_is_module_docstring(self, current_line: Line) -> bool:
1002 previous_block = self.previous_block
1003 if not previous_block:
1004 return False
1005 if (
1006 len(previous_block.original_line.leaves) != 1
1007 or not previous_block.original_line.is_docstring
1008 or previous_block.original_line.depth != 0
1009 or current_line.is_class
1010 or current_line.is_def
1011 ):
1012 return False
1013 while previous_block := previous_block.previous_block:
1014 if not previous_block.original_line.is_comment:
1015 return False
1016 return True
1018 def _maybe_empty_lines(self, current_line: Line) -> tuple[int, int]:
1019 max_allowed = 1
1020 if current_line.depth == 0:
1021 max_allowed = 1 if self.mode.is_pyi else 2
1022 overload_groups = (
1023 self.mode.is_pyi and Preview.pyi_overload_group_blank_lines in self.mode
1024 )
1026 if current_line.leaves:
1027 # Consume the first leaf's extra newlines.
1028 first_leaf = current_line.leaves[0]
1029 before = first_leaf.prefix.count("\n")
1030 # The blank lines that terminate a `# fmt: off` region live in the
1031 # prefix of the `# fmt: on` comment, not in the verbatim block, so
1032 # capping them here would edit formatting that was opted out of.
1033 # Likewise for a comment kept from the prefix of a line outside
1034 # --line-ranges.
1035 if (
1036 not current_line.is_fmt_pass_converted()
1037 and not (
1038 first_leaf.type == STANDALONE_COMMENT
1039 and contains_fmt_directive(first_leaf.value, FMT_ON)
1040 and self.previous_line is not None
1041 and self.previous_line.is_fmt_pass_converted()
1042 )
1043 and not (
1044 current_line.is_comment
1045 and first_leaf.line_ranges_selected is not None
1046 )
1047 ):
1048 before = min(before, max_allowed)
1049 first_leaf.prefix = ""
1050 else:
1051 before = 0
1053 user_had_newline = bool(before)
1054 depth = current_line.depth
1056 # Mutate self.previous_defs, remainder of this function should be pure
1057 previous_def = None
1058 while self.previous_defs and self.previous_defs[-1].depth >= depth:
1059 previous_def = self.previous_defs.pop()
1060 if current_line.is_def or current_line.is_class:
1061 self.previous_defs.append(current_line)
1063 if self.previous_line is None:
1064 # Don't insert empty lines before the first line in the file.
1065 return 0, 0
1067 if current_line.is_docstring:
1068 if self.previous_line.is_class:
1069 return 0, 1
1070 if self.previous_line.opens_block and self.previous_line.is_def:
1071 return 0, 0
1073 if previous_def is not None:
1074 assert self.previous_line is not None
1075 # Note: for decorator/def/class lines, `before` computed here is
1076 # passed to _maybe_empty_lines_for_class_or_def which may override
1077 # it. This block still matters for non-decorator/def/class lines
1078 # (e.g. a `var: int` statement following an overload group).
1079 if self.mode.is_pyi:
1080 if previous_def.is_class and not previous_def.is_stub_class:
1081 before = 1
1082 elif (
1083 overload_groups
1084 and self._pyi_previous_decorated_func is not None
1085 and self._pyi_previous_decorated_func.is_multi
1086 and not current_line.is_comment
1087 and self.previous_line.depth >= current_line.depth
1088 and not (
1089 current_line.leaves
1090 and current_line.leaves[0].value in ("else", "elif")
1091 )
1092 ):
1093 if self._is_in_current_group(current_line):
1094 before = 0
1095 elif current_line.opens_block and (
1096 self._get_block_first_decorated_funcname(current_line)
1097 == self._pyi_previous_decorated_func.name
1098 ):
1099 before = 0
1100 else:
1101 before = 1
1102 elif (
1103 overload_groups
1104 and current_line.opens_block
1105 and current_line.leaves
1106 and current_line.leaves[0].value in ("else", "elif")
1107 and self._block_is_part_of_overload_group(current_line)
1108 ):
1109 # else/elif continuing a conditional overload group:
1110 # don't insert a blank line above.
1111 before = 0
1112 elif (
1113 Preview.pyi_blank_line_after_function_docstring in self.mode
1114 and previous_def.is_def
1115 and self.previous_line.is_docstring
1116 and self.previous_line.depth == previous_def.depth + 1
1117 and not self._def_is_followed_by_same_name_decorated_func(
1118 previous_def,
1119 include_conditional_blocks=overload_groups,
1120 )
1121 ):
1122 before = 1
1123 elif depth and not current_line.is_def and self.previous_line.is_def:
1124 if (
1125 overload_groups
1126 and current_line.opens_block
1127 and self.previous_line.depth <= current_line.depth
1128 and self._block_is_part_of_overload_group(current_line)
1129 ):
1130 before = 1
1131 else:
1132 # Empty lines between attributes and methods should
1133 # be preserved.
1134 before = 1 if user_had_newline else 0
1135 elif (
1136 overload_groups
1137 and current_line.is_comment
1138 and self._pyi_previous_decorated_func is not None
1139 and self._pyi_previous_decorated_func.depth == current_line.depth
1140 ):
1141 # Own-line comments after a decorated function in .pyi:
1142 # preserve a single user blank line but never insert one.
1143 # For non-overload cases the comment_to_add_newlines
1144 # mechanism will retroactively add needed blank lines.
1145 before = 1 if user_had_newline else 0
1146 elif depth:
1147 before = 0
1148 else:
1149 before = 1
1150 else:
1151 if depth:
1152 before = 1
1153 elif (
1154 not depth
1155 and previous_def.depth
1156 and current_line.leaves[-1].type == token.COLON
1157 and (
1158 current_line.leaves[0].value
1159 not in ("with", "try", "for", "while", "if", "match")
1160 )
1161 ):
1162 # We shouldn't add two newlines between an indented function and
1163 # a dependent non-indented clause. This is to avoid issues with
1164 # conditional function definitions that are technically top-level
1165 # and therefore get two trailing newlines, but look weird and
1166 # inconsistent when they're followed by elif, else, etc. This is
1167 # worse because these functions only get *one* preceding newline
1168 # already.
1169 before = 1
1170 else:
1171 before = 2
1173 if current_line.is_decorator or current_line.is_def or current_line.is_class:
1174 return self._maybe_empty_lines_for_class_or_def(
1175 current_line, before, user_had_newline
1176 )
1178 if (
1179 Preview.fmt_off_class_blank_lines in self.mode
1180 and self.previous_line.is_import
1181 and self.previous_line.depth == 0
1182 and current_line.depth == 0
1183 and current_line.is_fmt_pass_converted(
1184 first_leaf_matches=lambda leaf: leaf.value == "class"
1185 )
1186 ):
1187 return 2, 0
1189 if (
1190 self.previous_line.is_import
1191 and self.previous_line.depth == 0
1192 and current_line.depth == 0
1193 and not current_line.is_import
1194 and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
1195 ):
1196 return 1, 0
1198 if (
1199 self.previous_line.is_import
1200 and not current_line.is_import
1201 and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
1202 and depth == self.previous_line.depth
1203 ):
1204 return (before or 1), 0
1206 return before, 0
1208 def _maybe_empty_lines_for_class_or_def(
1209 self, current_line: Line, before: int, user_had_newline: bool
1210 ) -> tuple[int, int]:
1211 assert self.previous_line is not None
1212 overload_groups = (
1213 self.mode.is_pyi and Preview.pyi_overload_group_blank_lines in self.mode
1214 )
1216 if self.previous_line.is_decorator:
1217 if self.mode.is_pyi and current_line.is_stub_class:
1218 # Insert an empty line after a decorated stub class
1219 return 0, 1
1220 return 0, 0
1222 if self.previous_line.depth < current_line.depth and (
1223 self.previous_line.is_class or self.previous_line.is_def
1224 ):
1225 if self.mode.is_pyi:
1226 return 0, 0
1227 return 1 if user_had_newline else 0, 0
1229 comment_to_add_newlines: LinesBlock | None = None
1230 if (
1231 self.previous_line.is_comment
1232 and self.previous_line.depth == current_line.depth
1233 and before == 0
1234 ):
1235 slc = self.semantic_leading_comment
1236 if (
1237 slc is not None
1238 and slc.previous_block is not None
1239 and not slc.previous_block.original_line.is_class
1240 and not slc.previous_block.original_line.opens_block
1241 and slc.before <= 1
1242 ):
1243 comment_to_add_newlines = slc
1244 else:
1245 return 0, 0
1247 if self.mode.is_pyi:
1248 if current_line.is_class or self.previous_line.is_class:
1249 if self.previous_line.depth < current_line.depth:
1250 newlines = 0
1251 elif self.previous_line.depth > current_line.depth:
1252 newlines = 1
1253 elif current_line.is_stub_class and self.previous_line.is_stub_class:
1254 # No blank line between classes with an empty body
1255 newlines = 0
1256 else:
1257 newlines = 1
1258 # Don't inspect only the previous line if it's part of the body of the
1259 # preceding statement. We always want a blank line after something with a
1260 # body.
1261 elif self.previous_line.depth > current_line.depth:
1262 if overload_groups and self._is_in_current_group(current_line):
1263 newlines = 0
1264 else:
1265 newlines = 1
1266 elif (
1267 overload_groups
1268 and self._pyi_previous_decorated_func is not None
1269 and self._pyi_previous_decorated_func.is_multi
1270 and self.previous_line.depth >= current_line.depth
1271 ):
1272 newlines = 0 if self._is_in_current_group(current_line) else 1
1273 elif overload_groups and self._is_in_current_group(current_line):
1274 # A comment between overloads may prevent is_multi from being
1275 # set, but _is_in_current_group still detects name continuity.
1276 newlines = 0
1277 elif (
1278 overload_groups
1279 and current_line.is_decorator
1280 and self.previous_line.depth >= current_line.depth
1281 and self._is_start_of_decorated_group(current_line)
1282 and (
1283 self._pyi_previous_decorated_func is None
1284 or (
1285 self._pyi_previous_decorated_func.name
1286 != self._get_decorator_target_name(current_line)
1287 )
1288 or self._pyi_previous_decorated_func.depth != current_line.depth
1289 )
1290 ):
1291 newlines = 1
1292 elif (
1293 current_line.is_def or current_line.is_decorator
1294 ) and not self.previous_line.is_def:
1295 if (
1296 overload_groups
1297 and current_line.is_decorator
1298 and self.previous_line.is_comment
1299 and self._is_decorator_in_conditional_overload(current_line)
1300 ):
1301 # Comment before an overload inside a conditional block:
1302 # remove blank lines between the comment and decorator.
1303 newlines = 0
1304 elif current_line.depth:
1305 # In classes empty lines between attributes and methods should
1306 # be preserved.
1307 newlines = min(1, before)
1308 else:
1309 # Blank line between a block of functions (maybe with preceding
1310 # decorators) and a block of non-functions
1311 newlines = 1
1312 elif (
1313 Preview.pyi_blank_line_before_decorated_class in self.mode
1314 and current_line.is_decorator
1315 and self._decorator_decorates_class(current_line)
1316 ):
1317 newlines = 1
1318 else:
1319 newlines = 0
1320 else:
1321 newlines = 1 if current_line.depth else 2
1322 # If a user has left no space after a dummy implementation, don't insert
1323 # new lines. This is useful for instance for @overload or Protocols.
1324 if (
1325 self.previous_line.is_stub_def
1326 and not user_had_newline
1327 and (
1328 Preview.blank_line_after_stub_method not in self.mode
1329 or self.previous_line.depth == current_line.depth
1330 )
1331 ):
1332 newlines = 0
1333 if comment_to_add_newlines is not None:
1334 previous_block = comment_to_add_newlines.previous_block
1335 if previous_block is not None:
1336 comment_to_add_newlines.before = (
1337 max(comment_to_add_newlines.before, newlines) - previous_block.after
1338 )
1339 newlines = 0
1340 return newlines, 0
1343def enumerate_reversed(sequence: Sequence[T]) -> Iterator[tuple[Index, T]]:
1344 """Like `reversed(enumerate(sequence))` if that were possible."""
1345 index = len(sequence) - 1
1346 for element in reversed(sequence):
1347 yield (index, element)
1348 index -= 1
1351def append_leaves(
1352 new_line: Line, old_line: Line, leaves: list[Leaf], preformatted: bool = False
1353) -> None:
1354 """
1355 Append leaves (taken from @old_line) to @new_line, making sure to fix the
1356 underlying Node structure where appropriate.
1358 All of the leaves in @leaves are duplicated. The duplicates are then
1359 appended to @new_line and used to replace their originals in the underlying
1360 Node structure. Any comments attached to the old leaves are reattached to
1361 the new leaves.
1363 Pre-conditions:
1364 set(@leaves) is a subset of set(@old_line.leaves).
1365 """
1366 # @leaves is a slice of @old_line.leaves, so the leaves are in tree (DFS)
1367 # order and the children replaced within any one parent are reached at
1368 # strictly increasing positions. Remembering where the last child of each
1369 # parent was found lets the lookup resume from there instead of rescanning the
1370 # whole child list through Base.remove on every leaf, which is otherwise
1371 # O(n^2) when a node has many children replaced (e.g. wrapping the operand
1372 # tuple of "%s" % (a, b, c, ...) or copying a very long line for a second
1373 # formatting pass).
1374 search_start: dict[int, int] = {}
1375 for old_leaf in leaves:
1376 new_leaf = old_leaf.clone()
1377 new_leaf.prefix = ""
1378 parent = old_leaf.parent
1379 if parent is not None:
1380 children = parent.children
1381 index = search_start.get(id(parent), 0)
1382 while index < len(children) and children[index] is not old_leaf:
1383 index += 1
1384 if index < len(children):
1385 # set_child swaps the child in place (the old one keeps the same
1386 # position), so the next sibling to replace is always further on.
1387 parent.set_child(index, new_leaf)
1388 search_start[id(parent)] = index + 1
1389 else:
1390 # The resume hint missed (unexpected ordering); fall back to the
1391 # full scan so behaviour is unchanged.
1392 replace_child(old_leaf, new_leaf)
1393 new_line.append(new_leaf, preformatted=preformatted)
1395 for comment_leaf in old_line.comments_after(old_leaf):
1396 new_line.append(comment_leaf, preformatted=True)
1399def is_line_short_enough(line: Line, *, mode: Mode, line_str: str = "") -> bool:
1400 """For non-multiline strings, return True if `line` is no longer than `line_length`.
1401 For multiline strings, looks at the context around `line` to determine
1402 if it should be inlined or split up.
1403 Uses the provided `line_str` rendering, if any, otherwise computes a new one.
1404 """
1405 if not line_str:
1406 line_str = line_to_string(line)
1408 if line.contains_standalone_comments():
1409 return False
1410 if "\n" not in line_str:
1411 # No multiline strings (MLS) present
1412 return str_width(line_str) <= mode.line_length
1414 first, *_, last = line_str.split("\n")
1415 if str_width(first) > mode.line_length or str_width(last) > mode.line_length:
1416 return False
1418 # Traverse the AST to examine the context of the multiline string (MLS),
1419 # tracking aspects such as depth and comma existence,
1420 # to determine whether to split the MLS or keep it together.
1421 # Depth (which is based on the existing bracket_depth concept)
1422 # is needed to determine nesting level of the MLS.
1423 # Includes special case for trailing commas.
1424 commas: list[int] = [] # tracks number of commas per depth level
1425 multiline_string: Leaf | None = None
1426 # store the leaves that contain parts of the MLS
1427 multiline_string_contexts: list[LN] = []
1429 # `id()`s of the leaves on this line, used to find which ancestors of the
1430 # multiline string are rendered in full on this line (see below).
1431 line_leaf_ids = {id(leaf) for leaf in line.leaves}
1433 max_level_to_update: int | float = math.inf # track the depth of the MLS
1434 for i, leaf in enumerate(line.leaves):
1435 if max_level_to_update == math.inf:
1436 had_comma: int | None = None
1437 if leaf.bracket_depth + 1 > len(commas):
1438 commas.append(0)
1439 elif leaf.bracket_depth + 1 < len(commas):
1440 had_comma = commas.pop()
1441 if (
1442 had_comma is not None
1443 and multiline_string is not None
1444 and multiline_string.bracket_depth == leaf.bracket_depth + 1
1445 ):
1446 # Have left the level with the MLS, stop tracking commas
1447 max_level_to_update = leaf.bracket_depth
1448 if had_comma > 0:
1449 # MLS was in parens with at least one comma - force split
1450 return False
1452 if leaf.bracket_depth <= max_level_to_update and leaf.type == token.COMMA:
1453 # Inside brackets, ignore trailing comma
1454 # directly after MLS/MLS-containing expression
1455 ignore_ctxs: list[LN | None] = [None]
1456 ignore_ctxs += multiline_string_contexts
1457 if (line.inside_brackets or leaf.bracket_depth > 0) and (
1458 i != len(line.leaves) - 1 or leaf.prev_sibling not in ignore_ctxs
1459 ):
1460 commas[leaf.bracket_depth] += 1
1461 if max_level_to_update != math.inf:
1462 max_level_to_update = min(max_level_to_update, leaf.bracket_depth)
1464 if is_multiline_string(leaf):
1465 if leaf.parent and (
1466 leaf.parent.type == syms.test
1467 or (leaf.parent.parent and leaf.parent.parent.type == syms.dictsetmaker)
1468 ):
1469 # Keep ternary and dictionary values parenthesized
1470 return False
1471 if len(multiline_string_contexts) > 0:
1472 # >1 multiline string cannot fit on a single line - force split
1473 return False
1474 multiline_string = leaf
1475 ctx: LN = leaf
1476 # fetch the leaf components of the MLS in the AST. An ancestor is
1477 # part of the MLS context while it is rendered in full on this line,
1478 # i.e. its first and last leaves both belong to the line (a line is
1479 # a contiguous run of leaves). Walking the leaf ids instead of
1480 # re-rendering `str(ctx)` and substring-searching `line_str` at every
1481 # level keeps this linear; the old form was quadratic on lines with a
1482 # large multiline-string-bearing collection (e.g. a dict literal with
1483 # many triple-quoted values).
1484 while (
1485 id(first_leaf(ctx)) in line_leaf_ids
1486 and id(last_leaf(ctx)) in line_leaf_ids
1487 ):
1488 multiline_string_contexts.append(ctx)
1489 if ctx.parent is None:
1490 break
1491 ctx = ctx.parent
1493 # May not have a triple-quoted multiline string at all,
1494 # in case of a regular string with embedded newlines and line continuations
1495 if len(multiline_string_contexts) == 0:
1496 return True
1498 return all(val == 0 for val in commas)
1501def can_be_split(line: Line) -> bool:
1502 """Return False if the line cannot be split *for sure*.
1504 This is not an exhaustive search but a cheap heuristic that we can use to
1505 avoid some unfortunate formattings (mostly around wrapping unsplittable code
1506 in unnecessary parentheses).
1507 """
1508 leaves = line.leaves
1509 if len(leaves) < 2:
1510 return False
1512 if leaves[0].type == token.STRING and leaves[1].type == token.DOT:
1513 call_count = 0
1514 dot_count = 0
1515 next = leaves[-1]
1516 for leaf in leaves[-2::-1]:
1517 if leaf.type in OPENING_BRACKETS:
1518 if next.type not in CLOSING_BRACKETS:
1519 return False
1521 call_count += 1
1522 elif leaf.type == token.DOT:
1523 dot_count += 1
1524 elif leaf.type == token.NAME:
1525 if not (next.type == token.DOT or next.type in OPENING_BRACKETS):
1526 return False
1528 elif leaf.type not in CLOSING_BRACKETS:
1529 return False
1531 if dot_count > 1 and call_count > 1:
1532 return False
1534 return True
1537def _is_annotated_assignment(head: Line) -> bool:
1538 """Does `head` (an assignment's leaves up to the `=`) contain an annotation?
1540 Detects a `:` at the top bracket level, as in `x: dict[str, int] = ...`.
1541 Colons nested inside brackets (e.g. slices like `x[a:b]`) don't count.
1542 """
1543 depth = 0
1544 for leaf in head.leaves:
1545 if not leaf.value:
1546 continue
1547 if leaf.type in OPENING_BRACKETS:
1548 depth += 1
1549 elif leaf.type in CLOSING_BRACKETS:
1550 depth -= 1
1551 elif leaf.type == token.COLON and depth == 0:
1552 return True
1553 return False
1556def is_symmetric_collection_binop(line: Line, line_length: int) -> bool:
1557 """Is `line` a binary operation between single-line collection displays?"""
1558 if len(line.bracket_tracker.delimiters) != 1:
1559 return False
1561 # Delimiters is keyed by leaf ID, not line position.
1562 delimiter_id = next(iter(line.bracket_tracker.delimiters))
1563 try:
1564 left_closing_index = next(
1565 index for index, leaf in enumerate(line.leaves) if id(leaf) == delimiter_id
1566 )
1567 except StopIteration:
1568 return False
1570 # Math operators are split *before* the delimiter, so BracketTracker keys
1571 # them by the preceding leaf.
1572 delimiter_index = left_closing_index + 1
1573 if delimiter_index >= len(line.leaves) - 1:
1574 return False
1576 first = line.leaves[0]
1577 left_closing = line.leaves[left_closing_index]
1578 delimiter = line.leaves[delimiter_index]
1579 right_opening = line.leaves[delimiter_index + 1]
1580 last = line.leaves[-1]
1582 collection_display = {
1583 (token.LSQB, token.RSQB),
1584 (token.LPAR, token.RPAR),
1585 (token.LBRACE, token.RBRACE),
1586 }
1588 def is_collection_display(opening: Leaf, closing: Leaf) -> bool:
1589 if (opening.type, closing.type) not in collection_display:
1590 return False
1591 return opening.type != token.LPAR or (
1592 opening.parent is not None
1593 and is_tuple(opening.parent)
1594 and not is_generator(opening.parent)
1595 )
1597 if (
1598 not is_collection_display(first, left_closing)
1599 or not is_collection_display(right_opening, last)
1600 or delimiter.type not in MATH_OPERATORS | COMPARATORS
1601 or left_closing.opening_bracket is not first
1602 or last.opening_bracket is not right_opening
1603 ):
1604 return False
1606 # Keep the existing asymmetric split when either display is already forced
1607 # to split by a magic trailing comma.
1608 if line.mode.magic_trailing_comma and (
1609 line.leaves[left_closing_index - 1].type == token.COMMA
1610 or line.leaves[-2].type == token.COMMA
1611 ):
1612 return False
1614 def rendered_width(start: int, end: int) -> int | None:
1615 leaves = line.leaves[start:end]
1616 rendered = " " * line.depth
1617 # End-of-line comments do not determine whether the operand itself fits.
1618 for index, leaf in enumerate(leaves):
1619 rendered += leaf.value if index == 0 else str(leaf)
1620 if "\n" in rendered:
1621 return None
1622 return str_width(rendered)
1624 left_width = rendered_width(0, delimiter_index)
1625 right_width = rendered_width(delimiter_index, len(line.leaves))
1626 return (
1627 left_width is not None
1628 and right_width is not None
1629 and left_width <= line_length
1630 and right_width <= line_length
1631 )
1634def can_omit_invisible_parens(
1635 rhs: RHSResult,
1636 line_length: int,
1637 mode: Mode,
1638) -> bool:
1639 """Does `rhs.body` have a shape safe to reformat without optional parens around it?
1641 Returns True for only a subset of potentially nice looking formattings but
1642 the point is to not return false positives that end up producing lines that
1643 are too long.
1644 """
1645 line = rhs.body
1647 # Multiple type ignores must stay on separate physical lines. Keeping the
1648 # optional parens gives the line transformer a safe place to split them.
1649 if (
1650 line.contains_multiple_type_ignores_at_current_depth()
1651 and not line.bracket_tracker.delimiters
1652 and any(leaf.type == token.DOT for leaf in line.leaves)
1653 ):
1654 return False
1656 # Don't omit optional parens when the opening paren carries an inline comment.
1657 # Omitting them re-parents the comment onto a different leaf after the next
1658 # parse, which can make the RHS splitter choose a different shape on each
1659 # pass (unstable formatting / "different code on the second pass"). See
1660 # issues #3701, #3706, and #4384.
1661 if rhs.opening_bracket.type == token.LPAR and not rhs.opening_bracket.value:
1662 if rhs.head.comments.get(id(rhs.opening_bracket)):
1663 return False
1665 # We can't omit parens if doing so would result in a type: ignore comment
1666 # sharing a line with other comments, as that breaks type: ignore parsing.
1667 # Check if the opening bracket (last leaf of head) has comments that would merge
1668 # with comments from the first line of the body.
1669 if rhs.head.leaves:
1670 opening_bracket = rhs.head.leaves[-1]
1671 head_comments = rhs.head.comments.get(id(opening_bracket), [])
1673 # If there are comments on the opening bracket line, check if any would
1674 # conflict with type: ignore comments in the body
1675 if head_comments:
1676 has_type_ignore_in_head = any(
1677 is_type_ignore_comment(comment, mode=rhs.head.mode)
1678 for comment in head_comments
1679 )
1680 has_other_comment_in_head = any(
1681 not is_type_ignore_comment(comment, mode=rhs.head.mode)
1682 for comment in head_comments
1683 )
1685 # Check for comments in the body that would potentially end up on the
1686 # same line as the head comments when parens are removed
1687 has_type_ignore_in_body = False
1688 has_other_comment_in_body = False
1689 for leaf in rhs.body.leaves:
1690 for comment in rhs.body.comments.get(id(leaf), []):
1691 if is_type_ignore_comment(comment, mode=rhs.body.mode):
1692 has_type_ignore_in_body = True
1693 else:
1694 has_other_comment_in_body = True
1696 # Preserve parens if we have both type: ignore and other comments that
1697 # could end up on the same line
1698 if (has_type_ignore_in_head and has_other_comment_in_body) or (
1699 has_other_comment_in_head and has_type_ignore_in_body
1700 ):
1701 return False
1703 # We need optional parens in order to split standalone comments to their own lines
1704 # if there are no nested parens around the standalone comments
1705 closing_bracket: Leaf | None = None
1706 for leaf in reversed(line.leaves):
1707 if closing_bracket and leaf is closing_bracket.opening_bracket:
1708 closing_bracket = None
1709 if leaf.type == STANDALONE_COMMENT and not closing_bracket:
1710 return False
1711 if (
1712 not closing_bracket
1713 and leaf.type in CLOSING_BRACKETS
1714 and leaf.opening_bracket in line.leaves
1715 and leaf.value
1716 ):
1717 closing_bracket = leaf
1719 # For assignments to a subscripted target whose head is too long to fit
1720 # (e.g. `x[long_key][another_long_key] = expr`), the target must be split
1721 # at its subscript brackets no matter what, so optional parens around a
1722 # RHS that fits on the resulting tail line (`] = expr`) are unnecessary.
1723 # When the head fits on one line, paren-wrapping the RHS remains the
1724 # preferred style and this check must not fire. It must also come before
1725 # the delimiter_count > 1 early return below, which would otherwise
1726 # reject bodies with multiple delimiters such as `10 - 5`.
1727 if (
1728 Preview.fix_unnecessary_parens_in_indexed_assignment in mode
1729 and len(rhs.head.leaves) >= 3
1730 and rhs.head.leaves[-2].type == token.EQUAL
1731 # The target must actually end with a subscript: a visible `]`
1732 # immediately before the `=`. Invisible parens (e.g. around tuple
1733 # targets like `(x,) = ...`) have an empty value and don't count.
1734 and rhs.head.leaves[-3].type == token.RSQB
1735 and rhs.head.leaves[-3].value
1736 # In annotated assignments (`x: dict[str, int] = ...`) the `]` before
1737 # the `=` belongs to the annotation; splitting on the annotation's
1738 # brackets would be wrong, so leave the optional parens alone.
1739 and not _is_annotated_assignment(rhs.head)
1740 # The head must be too long to fit, forcing the subscript split.
1741 and not is_line_short_enough(rhs.head, mode=mode)
1742 ):
1743 # 4 extra characters for the `] = ` prefix on the tail line.
1744 tail_line_length = 4 * line.depth + 4
1745 for _index, _leaf, leaf_length in line.enumerate_with_length():
1746 tail_line_length += leaf_length
1747 if tail_line_length <= line_length:
1748 return True
1750 bt = line.bracket_tracker
1751 if not bt.delimiters:
1752 # Without delimiters the optional parentheses are useless.
1753 return True
1755 max_priority = bt.max_delimiter_priority()
1756 delimiter_count = bt.delimiter_count_with_priority(max_priority)
1757 if delimiter_count > 1:
1758 # With more than one delimiter of a kind the optional parentheses read better.
1759 return False
1761 if delimiter_count == 1:
1762 if max_priority == COMMA_PRIORITY and rhs.head.is_with_or_async_with_stmt:
1763 # For two context manager with statements, the optional parentheses read
1764 # better. In this case, `rhs.body` is the context managers part of
1765 # the with statement. `rhs.head` is the `with (` part on the previous
1766 # line.
1767 return False
1768 if (
1769 Preview.symmetric_collection_operations in mode
1770 and is_symmetric_collection_binop(line, line_length)
1771 ):
1772 # Retaining the optional parentheses lets the delimiter splitter put
1773 # each display operand on its own line instead of exploding just one.
1774 return False
1775 # Otherwise it may also read better, but we don't do it today and requires
1776 # careful considerations for all possible cases. See
1777 # https://github.com/psf/black/issues/2156.
1779 if max_priority == DOT_PRIORITY:
1780 # A single stranded method call doesn't require optional parentheses.
1781 return True
1783 assert len(line.leaves) >= 2, "Stranded delimiter"
1785 # With a single delimiter, omit if the expression starts or ends with
1786 # a bracket.
1787 first = line.leaves[0]
1788 second = line.leaves[1]
1789 if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS:
1790 if _can_omit_opening_paren(line, first=first, line_length=line_length):
1791 return True
1793 # Note: we are not returning False here because a line might have *both*
1794 # a leading opening bracket and a trailing closing bracket. If the
1795 # opening bracket doesn't match our rule, maybe the closing will.
1797 penultimate = line.leaves[-2]
1798 last = line.leaves[-1]
1800 if (
1801 last.type == token.RPAR
1802 or last.type == token.RBRACE
1803 or (
1804 # don't use indexing for omitting optional parentheses;
1805 # it looks weird
1806 last.type == token.RSQB and last.parent and last.parent.type != syms.trailer
1807 )
1808 ):
1809 if penultimate.type in OPENING_BRACKETS:
1810 # Empty brackets don't help.
1811 return False
1813 if is_multiline_string(first):
1814 # Additional wrapping of a multiline string in this situation is
1815 # unnecessary.
1816 return True
1818 if _can_omit_closing_paren(line, last=last, line_length=line_length):
1819 return True
1821 return False
1824def _can_omit_opening_paren(line: Line, *, first: Leaf, line_length: int) -> bool:
1825 """See `can_omit_invisible_parens`."""
1826 remainder = False
1827 length = 4 * line.depth
1828 _index = -1
1829 for _index, leaf, leaf_length in line.enumerate_with_length():
1830 if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first:
1831 remainder = True
1832 if remainder:
1833 length += leaf_length
1834 if length > line_length:
1835 break
1837 if leaf.type in OPENING_BRACKETS:
1838 # There are brackets we can further split on.
1839 remainder = False
1841 else:
1842 # checked the entire string and line length wasn't exceeded
1843 if len(line.leaves) == _index + 1:
1844 return True
1846 return False
1849def _can_omit_closing_paren(line: Line, *, last: Leaf, line_length: int) -> bool:
1850 """See `can_omit_invisible_parens`."""
1851 length = 4 * line.depth
1852 seen_other_brackets = False
1853 for _index, leaf, leaf_length in line.enumerate_with_length():
1854 length += leaf_length
1855 if leaf is last.opening_bracket:
1856 if seen_other_brackets or length <= line_length:
1857 return True
1859 elif leaf.type in OPENING_BRACKETS:
1860 # There are brackets we can further split on.
1861 seen_other_brackets = True
1863 return False
1866def line_to_string(line: Line) -> str:
1867 """Returns the string representation of @line.
1869 WARNING: This is known to be computationally expensive.
1870 """
1871 return str(line).strip("\n")