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