Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/lines.py: 20%
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 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 is_docstring,
17 is_import,
18 is_multiline_string,
19 is_one_sequence_between,
20 is_type_comment,
21 is_type_ignore_comment,
22 is_with_or_async_with_stmt,
23 make_simple_prefix,
24 replace_child,
25 syms,
26 whitespace,
27)
28from black.strings import str_width
29from blib2to3.pgen2 import token
30from blib2to3.pytree import Leaf, Node
32# types
33T = TypeVar("T")
34Index = int
35LeafID = int
36LN = Union[Leaf, Node]
39@dataclass
40class Line:
41 """Holds leaves and comments. Can be printed with `str(line)`."""
43 mode: Mode = field(repr=False)
44 depth: int = 0
45 leaves: list[Leaf] = field(default_factory=list)
46 # keys ordered like `leaves`
47 comments: dict[LeafID, list[Leaf]] = field(default_factory=dict)
48 bracket_tracker: BracketTracker = field(default_factory=BracketTracker)
49 inside_brackets: bool = False
50 should_split_rhs: bool = False
51 magic_trailing_comma: Leaf | None = None
53 def append(
54 self, leaf: Leaf, preformatted: bool = False, track_bracket: bool = False
55 ) -> None:
56 """Add a new `leaf` to the end of the line.
58 Unless `preformatted` is True, the `leaf` will receive a new consistent
59 whitespace prefix and metadata applied by :class:`BracketTracker`.
60 Trailing commas are maybe removed, unpacked for loop variables are
61 demoted from being delimiters.
63 Inline comments are put aside.
64 """
65 has_value = (
66 leaf.type in BRACKETS
67 # empty fstring and tstring middles must not be truncated
68 or leaf.type in (token.FSTRING_MIDDLE, token.TSTRING_MIDDLE)
69 or bool(leaf.value.strip())
70 )
71 if not has_value:
72 return
74 if leaf.type == token.COLON and self.is_class_paren_empty:
75 del self.leaves[-2:]
76 if self.leaves and not preformatted:
77 # Note: at this point leaf.prefix should be empty except for
78 # imports, for which we only preserve newlines.
79 leaf.prefix += whitespace(
80 leaf,
81 complex_subscript=self.is_complex_subscript(leaf),
82 mode=self.mode,
83 )
84 if self.inside_brackets or not preformatted or track_bracket:
85 self.bracket_tracker.mark(leaf)
86 if self.mode.magic_trailing_comma:
87 if self.has_magic_trailing_comma(leaf):
88 self.magic_trailing_comma = leaf
89 elif self.has_magic_trailing_comma(leaf):
90 self.remove_trailing_comma()
91 if not self.append_comment(leaf):
92 self.leaves.append(leaf)
94 def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
95 """Like :func:`append()` but disallow invalid standalone comment structure.
97 Raises ValueError when any `leaf` is appended after a standalone comment
98 or when a standalone comment is not the first leaf on the line.
99 """
100 if (
101 self.bracket_tracker.depth == 0
102 or self.bracket_tracker.any_open_for_or_lambda()
103 ):
104 if self.is_comment:
105 raise ValueError("cannot append to standalone comments")
107 if self.leaves and leaf.type == STANDALONE_COMMENT:
108 raise ValueError(
109 "cannot append standalone comments to a populated line"
110 )
112 self.append(leaf, preformatted=preformatted)
114 @property
115 def is_comment(self) -> bool:
116 """Is this line a standalone comment?"""
117 return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
119 @property
120 def is_decorator(self) -> bool:
121 """Is this line a decorator?"""
122 return bool(self) and self.leaves[0].type == token.AT
124 @property
125 def is_import(self) -> bool:
126 """Is this an import line?"""
127 return bool(self) and is_import(self.leaves[0])
129 @property
130 def is_with_or_async_with_stmt(self) -> bool:
131 """Is this a with_stmt line?"""
132 return bool(self) and is_with_or_async_with_stmt(self.leaves[0])
134 @property
135 def is_class(self) -> bool:
136 """Is this line a class definition?"""
137 return (
138 bool(self)
139 and self.leaves[0].type == token.NAME
140 and self.leaves[0].value == "class"
141 )
143 @property
144 def is_stub_class(self) -> bool:
145 """Is this line a class definition with a body consisting only of "..."?"""
146 return self.is_class and self.leaves[-3:] == [
147 Leaf(token.DOT, ".") for _ in range(3)
148 ]
150 @property
151 def is_def(self) -> bool:
152 """Is this a function definition? (Also returns True for async defs.)"""
153 try:
154 first_leaf = self.leaves[0]
155 except IndexError:
156 return False
158 try:
159 second_leaf: Leaf | None = self.leaves[1]
160 except IndexError:
161 second_leaf = None
162 return (first_leaf.type == token.NAME and first_leaf.value == "def") or (
163 first_leaf.type == token.ASYNC
164 and second_leaf is not None
165 and second_leaf.type == token.NAME
166 and second_leaf.value == "def"
167 )
169 @property
170 def is_stub_def(self) -> bool:
171 """Is this line a function definition with a body consisting only of "..."?"""
172 return self.is_def and self.leaves[-4:] == [Leaf(token.COLON, ":")] + [
173 Leaf(token.DOT, ".") for _ in range(3)
174 ]
176 @property
177 def is_class_paren_empty(self) -> bool:
178 """Is this a class with no base classes but using parentheses?
180 Those are unnecessary and should be removed.
181 """
182 return (
183 bool(self)
184 and len(self.leaves) == 4
185 and self.is_class
186 and self.leaves[2].type == token.LPAR
187 and self.leaves[2].value == "("
188 and self.leaves[3].type == token.RPAR
189 and self.leaves[3].value == ")"
190 )
192 @property
193 def _is_triple_quoted_string(self) -> bool:
194 """Is the line a triple quoted string?"""
195 if not self or self.leaves[0].type != token.STRING:
196 return False
197 value = self.leaves[0].value
198 if value.startswith(('"""', "'''")):
199 return True
200 if value.startswith(("r'''", 'r"""', "R'''", 'R"""')):
201 return True
202 return False
204 @property
205 def is_docstring(self) -> bool:
206 """Is the line a docstring?"""
207 return bool(self) and is_docstring(self.leaves[0])
209 @property
210 def is_chained_assignment(self) -> bool:
211 """Is the line a chained assignment"""
212 return [leaf.type for leaf in self.leaves].count(token.EQUAL) > 1
214 @property
215 def opens_block(self) -> bool:
216 """Does this line open a new level of indentation."""
217 if len(self.leaves) == 0:
218 return False
219 return self.leaves[-1].type == token.COLON
221 def is_fmt_pass_converted(
222 self, *, first_leaf_matches: Callable[[Leaf], bool] | None = None
223 ) -> bool:
224 """Is this line converted from fmt off/skip code?
226 If first_leaf_matches is not None, it only returns True if the first
227 leaf of converted code matches.
228 """
229 if len(self.leaves) != 1:
230 return False
231 leaf = self.leaves[0]
232 if (
233 leaf.type != STANDALONE_COMMENT
234 or leaf.fmt_pass_converted_first_leaf is None
235 ):
236 return False
237 return first_leaf_matches is None or first_leaf_matches(
238 leaf.fmt_pass_converted_first_leaf
239 )
241 def contains_standalone_comments(self) -> bool:
242 """If so, needs to be split before emitting."""
243 for leaf in self.leaves:
244 if leaf.type == STANDALONE_COMMENT:
245 return True
247 return False
249 def contains_implicit_multiline_string_with_comments(self) -> bool:
250 """Chck if we have an implicit multiline string with comments on the line"""
251 for leaf_type, leaf_group_iterator in itertools.groupby(
252 self.leaves, lambda leaf: leaf.type
253 ):
254 if leaf_type != token.STRING:
255 continue
256 leaf_list = list(leaf_group_iterator)
257 if len(leaf_list) == 1:
258 continue
259 for leaf in leaf_list:
260 if self.comments_after(leaf):
261 return True
262 return False
264 def contains_uncollapsable_type_comments(self) -> bool:
265 ignored_ids = set()
266 try:
267 last_leaf = self.leaves[-1]
268 ignored_ids.add(id(last_leaf))
269 if last_leaf.type == token.COMMA or (
270 last_leaf.type == token.RPAR and not last_leaf.value
271 ):
272 # When trailing commas or optional parens are inserted by Black for
273 # consistency, comments after the previous last element are not moved
274 # (they don't have to, rendering will still be correct). So we ignore
275 # trailing commas and invisible.
276 last_leaf = self.leaves[-2]
277 ignored_ids.add(id(last_leaf))
278 except IndexError:
279 return False
281 # A type comment is uncollapsable if it is attached to a leaf
282 # that isn't at the end of the line (since that could cause it
283 # to get associated to a different argument) or if there are
284 # comments before it (since that could cause it to get hidden
285 # behind a comment.
286 comment_seen = False
287 for leaf_id, comments in self.comments.items():
288 for comment in comments:
289 if is_type_comment(comment, mode=self.mode):
290 if comment_seen or (
291 not is_type_ignore_comment(comment, mode=self.mode)
292 and leaf_id not in ignored_ids
293 ):
294 return True
296 comment_seen = True
298 return False
300 def contains_unsplittable_type_ignore(self) -> bool:
301 if not self.leaves:
302 return False
304 # If a 'type: ignore' is attached to the end of a line, we
305 # can't split the line, because we can't know which of the
306 # subexpressions the ignore was meant to apply to.
307 #
308 # We only want this to apply to actual physical lines from the
309 # original source, though: we don't want the presence of a
310 # 'type: ignore' at the end of a multiline expression to
311 # justify pushing it all onto one line. Thus we
312 # (unfortunately) need to check the actual source lines and
313 # only report an unsplittable 'type: ignore' if this line was
314 # one line in the original code.
316 # Grab the first and last line numbers, skipping generated leaves
317 first_line = next((leaf.lineno for leaf in self.leaves if leaf.lineno != 0), 0)
318 last_line = next(
319 (leaf.lineno for leaf in reversed(self.leaves) if leaf.lineno != 0), 0
320 )
322 if first_line == last_line:
323 # We look at the last two leaves since a comma or an
324 # invisible paren could have been added at the end of the
325 # line.
326 for node in self.leaves[-2:]:
327 for comment in self.comments.get(id(node), []):
328 if is_type_ignore_comment(comment, mode=self.mode):
329 return True
331 return False
333 def contains_multiline_strings(self) -> bool:
334 return any(is_multiline_string(leaf) for leaf in self.leaves)
336 def has_magic_trailing_comma(self, closing: Leaf) -> bool:
337 """Return True if we have a magic trailing comma, that is when:
338 - there's a trailing comma here
339 - it's not from single-element square bracket indexing
340 - it's not a one-tuple
341 """
342 if not (
343 closing.type in CLOSING_BRACKETS
344 and self.leaves
345 and self.leaves[-1].type == token.COMMA
346 ):
347 return False
349 if closing.type == token.RBRACE:
350 return True
352 if closing.type == token.RSQB:
353 if (
354 closing.parent is not None
355 and closing.parent.type == syms.trailer
356 and closing.opening_bracket is not None
357 and is_one_sequence_between(
358 closing.opening_bracket,
359 closing,
360 self.leaves,
361 brackets=(token.LSQB, token.RSQB),
362 )
363 ):
364 assert closing.prev_sibling is not None
365 assert closing.prev_sibling.type == syms.subscriptlist
366 return False
368 return True
370 if self.is_import:
371 return True
373 if closing.opening_bracket is not None and not is_one_sequence_between(
374 closing.opening_bracket, closing, self.leaves
375 ):
376 return True
378 return False
380 def append_comment(self, comment: Leaf) -> bool:
381 """Add an inline or standalone comment to the line."""
382 if (
383 comment.type == STANDALONE_COMMENT
384 and self.bracket_tracker.any_open_brackets()
385 ):
386 comment.prefix = ""
387 return False
389 if comment.type != token.COMMENT:
390 return False
392 if not self.leaves:
393 comment.type = STANDALONE_COMMENT
394 comment.prefix = ""
395 return False
397 last_leaf = self.leaves[-1]
398 if (
399 last_leaf.type == token.RPAR
400 and not last_leaf.value
401 and last_leaf.parent
402 and len(list(last_leaf.parent.leaves())) <= 3
403 and not is_type_comment(comment, mode=self.mode)
404 ):
405 # Comments on an optional parens wrapping a single leaf should belong to
406 # the wrapped node except if it's a type comment. Pinning the comment like
407 # this avoids unstable formatting caused by comment migration.
408 if len(self.leaves) < 2:
409 comment.type = STANDALONE_COMMENT
410 comment.prefix = ""
411 return False
413 last_leaf = self.leaves[-2]
414 self.comments.setdefault(id(last_leaf), []).append(comment)
415 return True
417 def comments_after(self, leaf: Leaf) -> list[Leaf]:
418 """Generate comments that should appear directly after `leaf`."""
419 return self.comments.get(id(leaf), [])
421 def remove_trailing_comma(self) -> None:
422 """Remove the trailing comma and moves the comments attached to it."""
423 trailing_comma = self.leaves.pop()
424 trailing_comma_comments = self.comments.pop(id(trailing_comma), [])
425 self.comments.setdefault(id(self.leaves[-1]), []).extend(
426 trailing_comma_comments
427 )
429 def is_complex_subscript(self, leaf: Leaf) -> bool:
430 """Return True iff `leaf` is part of a slice with non-trivial exprs."""
431 open_lsqb = self.bracket_tracker.get_open_lsqb()
432 if open_lsqb is None:
433 return False
435 subscript_start = open_lsqb.next_sibling
437 if isinstance(subscript_start, Node):
438 if subscript_start.type == syms.listmaker:
439 return False
441 if subscript_start.type == syms.subscriptlist:
442 subscript_start = child_towards(subscript_start, leaf)
444 return subscript_start is not None and any(
445 n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
446 )
448 def enumerate_with_length(
449 self, is_reversed: bool = False
450 ) -> Iterator[tuple[Index, Leaf, int]]:
451 """Return an enumeration of leaves with their length.
453 Stops prematurely on multiline strings and standalone comments.
454 """
455 op = cast(
456 Callable[[Sequence[Leaf]], Iterator[tuple[Index, Leaf]]],
457 enumerate_reversed if is_reversed else enumerate,
458 )
459 for index, leaf in op(self.leaves):
460 length = len(leaf.prefix) + len(leaf.value)
461 if "\n" in leaf.value:
462 return # Multiline strings, we can't continue.
464 for comment in self.comments_after(leaf):
465 length += len(comment.value)
467 yield index, leaf, length
469 def clone(self) -> "Line":
470 return Line(
471 mode=self.mode,
472 depth=self.depth,
473 inside_brackets=self.inside_brackets,
474 should_split_rhs=self.should_split_rhs,
475 magic_trailing_comma=self.magic_trailing_comma,
476 )
478 def __str__(self) -> str:
479 """Render the line."""
480 if not self:
481 return "\n"
483 indent = " " * self.depth
484 leaves = iter(self.leaves)
485 first = next(leaves)
486 res = f"{first.prefix}{indent}{first.value}"
487 res += "".join(str(leaf) for leaf in leaves)
488 comments_iter = itertools.chain.from_iterable(self.comments.values())
489 comments = [str(comment) for comment in comments_iter]
490 res += "".join(comments)
492 return res + "\n"
494 def __bool__(self) -> bool:
495 """Return True if the line has leaves or comments."""
496 return bool(self.leaves or self.comments)
499@dataclass
500class RHSResult:
501 """Intermediate split result from a right hand split."""
503 head: Line
504 body: Line
505 tail: Line
506 opening_bracket: Leaf
507 closing_bracket: Leaf
510@dataclass
511class LinesBlock:
512 """Class that holds information about a block of formatted lines.
514 This is introduced so that the EmptyLineTracker can look behind the standalone
515 comments and adjust their empty lines for class or def lines.
516 """
518 mode: Mode
519 previous_block: Optional["LinesBlock"]
520 original_line: Line
521 before: int = 0
522 content_lines: list[str] = field(default_factory=list)
523 after: int = 0
524 form_feed: bool = False
526 def all_lines(self) -> list[str]:
527 empty_line = str(Line(mode=self.mode))
528 prefix = make_simple_prefix(self.before, self.form_feed, empty_line)
529 return [prefix] + self.content_lines + [empty_line * self.after]
532@dataclass
533class EmptyLineTracker:
534 """Provides a stateful method that returns the number of potential extra
535 empty lines needed before and after the currently processed line.
537 Note: this tracker works on lines that haven't been split yet. It assumes
538 the prefix of the first leaf consists of optional newlines. Those newlines
539 are consumed by `maybe_empty_lines()` and included in the computation.
540 """
542 mode: Mode
543 previous_line: Line | None = None
544 previous_block: LinesBlock | None = None
545 previous_defs: list[Line] = field(default_factory=list)
546 semantic_leading_comment: LinesBlock | None = None
548 def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
549 """Return the number of extra empty lines before and after the `current_line`.
551 This is for separating `def`, `async def` and `class` with extra empty
552 lines (two on module-level).
553 """
554 form_feed = (
555 current_line.depth == 0
556 and bool(current_line.leaves)
557 and "\f\n" in current_line.leaves[0].prefix
558 )
559 before, after = self._maybe_empty_lines(current_line)
560 previous_after = self.previous_block.after if self.previous_block else 0
561 before = max(0, before - previous_after)
562 if Preview.fix_module_docstring_detection in self.mode:
563 # Always have one empty line after a module docstring
564 if self._line_is_module_docstring(current_line):
565 before = 1
566 else:
567 if (
568 # Always have one empty line after a module docstring
569 self.previous_block
570 and self.previous_block.previous_block is None
571 and len(self.previous_block.original_line.leaves) == 1
572 and self.previous_block.original_line.is_docstring
573 and not (current_line.is_class or current_line.is_def)
574 ):
575 before = 1
577 block = LinesBlock(
578 mode=self.mode,
579 previous_block=self.previous_block,
580 original_line=current_line,
581 before=before,
582 after=after,
583 form_feed=form_feed,
584 )
586 # Maintain the semantic_leading_comment state.
587 if current_line.is_comment:
588 if self.previous_line is None or (
589 not self.previous_line.is_decorator
590 # `or before` means this comment already has an empty line before
591 and (not self.previous_line.is_comment or before)
592 and (self.semantic_leading_comment is None or before)
593 ):
594 self.semantic_leading_comment = block
595 # `or before` means this decorator already has an empty line before
596 elif not current_line.is_decorator or before:
597 self.semantic_leading_comment = None
599 self.previous_line = current_line
600 self.previous_block = block
601 return block
603 def _line_is_module_docstring(self, current_line: Line) -> bool:
604 previous_block = self.previous_block
605 if not previous_block:
606 return False
607 if (
608 len(previous_block.original_line.leaves) != 1
609 or not previous_block.original_line.is_docstring
610 or current_line.is_class
611 or current_line.is_def
612 ):
613 return False
614 while previous_block := previous_block.previous_block:
615 if not previous_block.original_line.is_comment:
616 return False
617 return True
619 def _maybe_empty_lines(self, current_line: Line) -> tuple[int, int]:
620 max_allowed = 1
621 if current_line.depth == 0:
622 max_allowed = 1 if self.mode.is_pyi else 2
624 if current_line.leaves:
625 # Consume the first leaf's extra newlines.
626 first_leaf = current_line.leaves[0]
627 before = first_leaf.prefix.count("\n")
628 before = min(before, max_allowed)
629 first_leaf.prefix = ""
630 else:
631 before = 0
633 user_had_newline = bool(before)
634 depth = current_line.depth
636 # Mutate self.previous_defs, remainder of this function should be pure
637 previous_def = None
638 while self.previous_defs and self.previous_defs[-1].depth >= depth:
639 previous_def = self.previous_defs.pop()
640 if current_line.is_def or current_line.is_class:
641 self.previous_defs.append(current_line)
643 if self.previous_line is None:
644 # Don't insert empty lines before the first line in the file.
645 return 0, 0
647 if current_line.is_docstring:
648 if self.previous_line.is_class:
649 return 0, 1
650 if self.previous_line.opens_block and self.previous_line.is_def:
651 return 0, 0
653 if previous_def is not None:
654 assert self.previous_line is not None
655 if self.mode.is_pyi:
656 if previous_def.is_class and not previous_def.is_stub_class:
657 before = 1
658 elif depth and not current_line.is_def and self.previous_line.is_def:
659 # Empty lines between attributes and methods should be preserved.
660 before = 1 if user_had_newline else 0
661 elif depth:
662 before = 0
663 else:
664 before = 1
665 else:
666 if depth:
667 before = 1
668 elif (
669 not depth
670 and previous_def.depth
671 and current_line.leaves[-1].type == token.COLON
672 and (
673 current_line.leaves[0].value
674 not in ("with", "try", "for", "while", "if", "match")
675 )
676 ):
677 # We shouldn't add two newlines between an indented function and
678 # a dependent non-indented clause. This is to avoid issues with
679 # conditional function definitions that are technically top-level
680 # and therefore get two trailing newlines, but look weird and
681 # inconsistent when they're followed by elif, else, etc. This is
682 # worse because these functions only get *one* preceding newline
683 # already.
684 before = 1
685 else:
686 before = 2
688 if current_line.is_decorator or current_line.is_def or current_line.is_class:
689 return self._maybe_empty_lines_for_class_or_def(
690 current_line, before, user_had_newline
691 )
693 if (
694 self.previous_line.is_import
695 and self.previous_line.depth == 0
696 and current_line.depth == 0
697 and not current_line.is_import
698 and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
699 and Preview.always_one_newline_after_import in self.mode
700 ):
701 return 1, 0
703 if (
704 self.previous_line.is_import
705 and not current_line.is_import
706 and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
707 and depth == self.previous_line.depth
708 ):
709 return (before or 1), 0
711 return before, 0
713 def _maybe_empty_lines_for_class_or_def(
714 self, current_line: Line, before: int, user_had_newline: bool
715 ) -> tuple[int, int]:
716 assert self.previous_line is not None
718 if self.previous_line.is_decorator:
719 if self.mode.is_pyi and current_line.is_stub_class:
720 # Insert an empty line after a decorated stub class
721 return 0, 1
722 return 0, 0
724 if self.previous_line.depth < current_line.depth and (
725 self.previous_line.is_class or self.previous_line.is_def
726 ):
727 if self.mode.is_pyi:
728 return 0, 0
729 return 1 if user_had_newline else 0, 0
731 comment_to_add_newlines: LinesBlock | None = None
732 if (
733 self.previous_line.is_comment
734 and self.previous_line.depth == current_line.depth
735 and before == 0
736 ):
737 slc = self.semantic_leading_comment
738 if (
739 slc is not None
740 and slc.previous_block is not None
741 and not slc.previous_block.original_line.is_class
742 and not slc.previous_block.original_line.opens_block
743 and slc.before <= 1
744 ):
745 comment_to_add_newlines = slc
746 else:
747 return 0, 0
749 if self.mode.is_pyi:
750 if current_line.is_class or self.previous_line.is_class:
751 if self.previous_line.depth < current_line.depth:
752 newlines = 0
753 elif self.previous_line.depth > current_line.depth:
754 newlines = 1
755 elif current_line.is_stub_class and self.previous_line.is_stub_class:
756 # No blank line between classes with an empty body
757 newlines = 0
758 else:
759 newlines = 1
760 # Don't inspect the previous line if it's part of the body of the previous
761 # statement in the same level, we always want a blank line if there's
762 # something with a body preceding.
763 elif self.previous_line.depth > current_line.depth:
764 newlines = 1
765 elif (
766 current_line.is_def or current_line.is_decorator
767 ) and not self.previous_line.is_def:
768 if current_line.depth:
769 # In classes empty lines between attributes and methods should
770 # be preserved.
771 newlines = min(1, before)
772 else:
773 # Blank line between a block of functions (maybe with preceding
774 # decorators) and a block of non-functions
775 newlines = 1
776 else:
777 newlines = 0
778 else:
779 newlines = 1 if current_line.depth else 2
780 # If a user has left no space after a dummy implementation, don't insert
781 # new lines. This is useful for instance for @overload or Protocols.
782 if self.previous_line.is_stub_def and not user_had_newline:
783 newlines = 0
784 if comment_to_add_newlines is not None:
785 previous_block = comment_to_add_newlines.previous_block
786 if previous_block is not None:
787 comment_to_add_newlines.before = (
788 max(comment_to_add_newlines.before, newlines) - previous_block.after
789 )
790 newlines = 0
791 return newlines, 0
794def enumerate_reversed(sequence: Sequence[T]) -> Iterator[tuple[Index, T]]:
795 """Like `reversed(enumerate(sequence))` if that were possible."""
796 index = len(sequence) - 1
797 for element in reversed(sequence):
798 yield (index, element)
799 index -= 1
802def append_leaves(
803 new_line: Line, old_line: Line, leaves: list[Leaf], preformatted: bool = False
804) -> None:
805 """
806 Append leaves (taken from @old_line) to @new_line, making sure to fix the
807 underlying Node structure where appropriate.
809 All of the leaves in @leaves are duplicated. The duplicates are then
810 appended to @new_line and used to replace their originals in the underlying
811 Node structure. Any comments attached to the old leaves are reattached to
812 the new leaves.
814 Pre-conditions:
815 set(@leaves) is a subset of set(@old_line.leaves).
816 """
817 for old_leaf in leaves:
818 new_leaf = Leaf(old_leaf.type, old_leaf.value)
819 replace_child(old_leaf, new_leaf)
820 new_line.append(new_leaf, preformatted=preformatted)
822 for comment_leaf in old_line.comments_after(old_leaf):
823 new_line.append(comment_leaf, preformatted=True)
826def is_line_short_enough(line: Line, *, mode: Mode, line_str: str = "") -> bool:
827 """For non-multiline strings, return True if `line` is no longer than `line_length`.
828 For multiline strings, looks at the context around `line` to determine
829 if it should be inlined or split up.
830 Uses the provided `line_str` rendering, if any, otherwise computes a new one.
831 """
832 if not line_str:
833 line_str = line_to_string(line)
835 if Preview.multiline_string_handling not in mode:
836 return (
837 str_width(line_str) <= mode.line_length
838 and "\n" not in line_str # multiline strings
839 and not line.contains_standalone_comments()
840 )
842 if line.contains_standalone_comments():
843 return False
844 if "\n" not in line_str:
845 # No multiline strings (MLS) present
846 return str_width(line_str) <= mode.line_length
848 first, *_, last = line_str.split("\n")
849 if str_width(first) > mode.line_length or str_width(last) > mode.line_length:
850 return False
852 # Traverse the AST to examine the context of the multiline string (MLS),
853 # tracking aspects such as depth and comma existence,
854 # to determine whether to split the MLS or keep it together.
855 # Depth (which is based on the existing bracket_depth concept)
856 # is needed to determine nesting level of the MLS.
857 # Includes special case for trailing commas.
858 commas: list[int] = [] # tracks number of commas per depth level
859 multiline_string: Leaf | None = None
860 # store the leaves that contain parts of the MLS
861 multiline_string_contexts: list[LN] = []
863 max_level_to_update: int | float = math.inf # track the depth of the MLS
864 for i, leaf in enumerate(line.leaves):
865 if max_level_to_update == math.inf:
866 had_comma: int | None = None
867 if leaf.bracket_depth + 1 > len(commas):
868 commas.append(0)
869 elif leaf.bracket_depth + 1 < len(commas):
870 had_comma = commas.pop()
871 if (
872 had_comma is not None
873 and multiline_string is not None
874 and multiline_string.bracket_depth == leaf.bracket_depth + 1
875 ):
876 # Have left the level with the MLS, stop tracking commas
877 max_level_to_update = leaf.bracket_depth
878 if had_comma > 0:
879 # MLS was in parens with at least one comma - force split
880 return False
882 if leaf.bracket_depth <= max_level_to_update and leaf.type == token.COMMA:
883 # Inside brackets, ignore trailing comma
884 # directly after MLS/MLS-containing expression
885 ignore_ctxs: list[LN | None] = [None]
886 ignore_ctxs += multiline_string_contexts
887 if (line.inside_brackets or leaf.bracket_depth > 0) and (
888 i != len(line.leaves) - 1 or leaf.prev_sibling not in ignore_ctxs
889 ):
890 commas[leaf.bracket_depth] += 1
891 if max_level_to_update != math.inf:
892 max_level_to_update = min(max_level_to_update, leaf.bracket_depth)
894 if is_multiline_string(leaf):
895 if leaf.parent and (
896 leaf.parent.type == syms.test
897 or (leaf.parent.parent and leaf.parent.parent.type == syms.dictsetmaker)
898 ):
899 # Keep ternary and dictionary values parenthesized
900 return False
901 if len(multiline_string_contexts) > 0:
902 # >1 multiline string cannot fit on a single line - force split
903 return False
904 multiline_string = leaf
905 ctx: LN = leaf
906 # fetch the leaf components of the MLS in the AST
907 while str(ctx) in line_str:
908 multiline_string_contexts.append(ctx)
909 if ctx.parent is None:
910 break
911 ctx = ctx.parent
913 # May not have a triple-quoted multiline string at all,
914 # in case of a regular string with embedded newlines and line continuations
915 if len(multiline_string_contexts) == 0:
916 return True
918 return all(val == 0 for val in commas)
921def can_be_split(line: Line) -> bool:
922 """Return False if the line cannot be split *for sure*.
924 This is not an exhaustive search but a cheap heuristic that we can use to
925 avoid some unfortunate formattings (mostly around wrapping unsplittable code
926 in unnecessary parentheses).
927 """
928 leaves = line.leaves
929 if len(leaves) < 2:
930 return False
932 if leaves[0].type == token.STRING and leaves[1].type == token.DOT:
933 call_count = 0
934 dot_count = 0
935 next = leaves[-1]
936 for leaf in leaves[-2::-1]:
937 if leaf.type in OPENING_BRACKETS:
938 if next.type not in CLOSING_BRACKETS:
939 return False
941 call_count += 1
942 elif leaf.type == token.DOT:
943 dot_count += 1
944 elif leaf.type == token.NAME:
945 if not (next.type == token.DOT or next.type in OPENING_BRACKETS):
946 return False
948 elif leaf.type not in CLOSING_BRACKETS:
949 return False
951 if dot_count > 1 and call_count > 1:
952 return False
954 return True
957def can_omit_invisible_parens(
958 rhs: RHSResult,
959 line_length: int,
960) -> bool:
961 """Does `rhs.body` have a shape safe to reformat without optional parens around it?
963 Returns True for only a subset of potentially nice looking formattings but
964 the point is to not return false positives that end up producing lines that
965 are too long.
966 """
967 line = rhs.body
969 # We need optional parens in order to split standalone comments to their own lines
970 # if there are no nested parens around the standalone comments
971 closing_bracket: Leaf | None = None
972 for leaf in reversed(line.leaves):
973 if closing_bracket and leaf is closing_bracket.opening_bracket:
974 closing_bracket = None
975 if leaf.type == STANDALONE_COMMENT and not closing_bracket:
976 return False
977 if (
978 not closing_bracket
979 and leaf.type in CLOSING_BRACKETS
980 and leaf.opening_bracket in line.leaves
981 and leaf.value
982 ):
983 closing_bracket = leaf
985 bt = line.bracket_tracker
986 if not bt.delimiters:
987 # Without delimiters the optional parentheses are useless.
988 return True
990 max_priority = bt.max_delimiter_priority()
991 delimiter_count = bt.delimiter_count_with_priority(max_priority)
992 if delimiter_count > 1:
993 # With more than one delimiter of a kind the optional parentheses read better.
994 return False
996 if delimiter_count == 1:
997 if max_priority == COMMA_PRIORITY and rhs.head.is_with_or_async_with_stmt:
998 # For two context manager with statements, the optional parentheses read
999 # better. In this case, `rhs.body` is the context managers part of
1000 # the with statement. `rhs.head` is the `with (` part on the previous
1001 # line.
1002 return False
1003 # Otherwise it may also read better, but we don't do it today and requires
1004 # careful considerations for all possible cases. See
1005 # https://github.com/psf/black/issues/2156.
1007 if max_priority == DOT_PRIORITY:
1008 # A single stranded method call doesn't require optional parentheses.
1009 return True
1011 assert len(line.leaves) >= 2, "Stranded delimiter"
1013 # With a single delimiter, omit if the expression starts or ends with
1014 # a bracket.
1015 first = line.leaves[0]
1016 second = line.leaves[1]
1017 if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS:
1018 if _can_omit_opening_paren(line, first=first, line_length=line_length):
1019 return True
1021 # Note: we are not returning False here because a line might have *both*
1022 # a leading opening bracket and a trailing closing bracket. If the
1023 # opening bracket doesn't match our rule, maybe the closing will.
1025 penultimate = line.leaves[-2]
1026 last = line.leaves[-1]
1028 if (
1029 last.type == token.RPAR
1030 or last.type == token.RBRACE
1031 or (
1032 # don't use indexing for omitting optional parentheses;
1033 # it looks weird
1034 last.type == token.RSQB
1035 and last.parent
1036 and last.parent.type != syms.trailer
1037 )
1038 ):
1039 if penultimate.type in OPENING_BRACKETS:
1040 # Empty brackets don't help.
1041 return False
1043 if is_multiline_string(first):
1044 # Additional wrapping of a multiline string in this situation is
1045 # unnecessary.
1046 return True
1048 if _can_omit_closing_paren(line, last=last, line_length=line_length):
1049 return True
1051 return False
1054def _can_omit_opening_paren(line: Line, *, first: Leaf, line_length: int) -> bool:
1055 """See `can_omit_invisible_parens`."""
1056 remainder = False
1057 length = 4 * line.depth
1058 _index = -1
1059 for _index, leaf, leaf_length in line.enumerate_with_length():
1060 if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first:
1061 remainder = True
1062 if remainder:
1063 length += leaf_length
1064 if length > line_length:
1065 break
1067 if leaf.type in OPENING_BRACKETS:
1068 # There are brackets we can further split on.
1069 remainder = False
1071 else:
1072 # checked the entire string and line length wasn't exceeded
1073 if len(line.leaves) == _index + 1:
1074 return True
1076 return False
1079def _can_omit_closing_paren(line: Line, *, last: Leaf, line_length: int) -> bool:
1080 """See `can_omit_invisible_parens`."""
1081 length = 4 * line.depth
1082 seen_other_brackets = False
1083 for _index, leaf, leaf_length in line.enumerate_with_length():
1084 length += leaf_length
1085 if leaf is last.opening_bracket:
1086 if seen_other_brackets or length <= line_length:
1087 return True
1089 elif leaf.type in OPENING_BRACKETS:
1090 # There are brackets we can further split on.
1091 seen_other_brackets = True
1093 return False
1096def line_to_string(line: Line) -> str:
1097 """Returns the string representation of @line.
1099 WARNING: This is known to be computationally expensive.
1100 """
1101 return str(line).strip("\n")