All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
4 from dataclasses import dataclass, field
18 from black.brackets import COMMA_PRIORITY, DOT_PRIORITY, BracketTracker
19 from black.mode import Mode, Preview
20 from black.nodes import (
29 is_one_sequence_between,
31 is_type_ignore_comment,
32 is_with_or_async_with_stmt,
37 from black.strings import str_width
38 from blib2to3.pgen2 import token
39 from blib2to3.pytree import Leaf, Node
45 LN = Union[Leaf, Node]
50 """Holds leaves and comments. Can be printed with `str(line)`."""
52 mode: Mode = field(repr=False)
54 leaves: List[Leaf] = field(default_factory=list)
55 # keys ordered like `leaves`
56 comments: Dict[LeafID, List[Leaf]] = field(default_factory=dict)
57 bracket_tracker: BracketTracker = field(default_factory=BracketTracker)
58 inside_brackets: bool = False
59 should_split_rhs: bool = False
60 magic_trailing_comma: Optional[Leaf] = None
63 self, leaf: Leaf, preformatted: bool = False, track_bracket: bool = False
65 """Add a new `leaf` to the end of the line.
67 Unless `preformatted` is True, the `leaf` will receive a new consistent
68 whitespace prefix and metadata applied by :class:`BracketTracker`.
69 Trailing commas are maybe removed, unpacked for loop variables are
70 demoted from being delimiters.
72 Inline comments are put aside.
74 has_value = leaf.type in BRACKETS or bool(leaf.value.strip())
78 if token.COLON == leaf.type and self.is_class_paren_empty:
80 if self.leaves and not preformatted:
81 # Note: at this point leaf.prefix should be empty except for
82 # imports, for which we only preserve newlines.
83 leaf.prefix += whitespace(
85 complex_subscript=self.is_complex_subscript(leaf),
88 if self.inside_brackets or not preformatted or track_bracket:
89 self.bracket_tracker.mark(leaf)
90 if self.mode.magic_trailing_comma:
91 if self.has_magic_trailing_comma(leaf):
92 self.magic_trailing_comma = leaf
93 elif self.has_magic_trailing_comma(leaf, ensure_removable=True):
94 self.remove_trailing_comma()
95 if not self.append_comment(leaf):
96 self.leaves.append(leaf)
98 def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
99 """Like :func:`append()` but disallow invalid standalone comment structure.
101 Raises ValueError when any `leaf` is appended after a standalone comment
102 or when a standalone comment is not the first leaf on the line.
104 if self.bracket_tracker.depth == 0:
106 raise ValueError("cannot append to standalone comments")
108 if self.leaves and leaf.type == STANDALONE_COMMENT:
110 "cannot append standalone comments to a populated line"
113 self.append(leaf, preformatted=preformatted)
116 def is_comment(self) -> bool:
117 """Is this line a standalone comment?"""
118 return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
121 def is_decorator(self) -> bool:
122 """Is this line a decorator?"""
123 return bool(self) and self.leaves[0].type == token.AT
126 def is_import(self) -> bool:
127 """Is this an import line?"""
128 return bool(self) and is_import(self.leaves[0])
131 def is_with_or_async_with_stmt(self) -> bool:
132 """Is this a with_stmt line?"""
133 return bool(self) and is_with_or_async_with_stmt(self.leaves[0])
136 def is_class(self) -> bool:
137 """Is this line a class definition?"""
140 and self.leaves[0].type == token.NAME
141 and self.leaves[0].value == "class"
145 def is_stub_class(self) -> bool:
146 """Is this line a class definition with a body consisting only of "..."?"""
147 return self.is_class and self.leaves[-3:] == [
148 Leaf(token.DOT, ".") for _ in range(3)
152 def is_def(self) -> bool:
153 """Is this a function definition? (Also returns True for async defs.)"""
155 first_leaf = self.leaves[0]
160 second_leaf: Optional[Leaf] = self.leaves[1]
163 return (first_leaf.type == token.NAME and first_leaf.value == "def") or (
164 first_leaf.type == token.ASYNC
165 and second_leaf is not None
166 and second_leaf.type == token.NAME
167 and second_leaf.value == "def"
171 def is_stub_def(self) -> bool:
172 """Is this line a function definition with a body consisting only of "..."?"""
173 return self.is_def and self.leaves[-4:] == [Leaf(token.COLON, ":")] + [
174 Leaf(token.DOT, ".") for _ in range(3)
178 def is_class_paren_empty(self) -> bool:
179 """Is this a class with no base classes but using parentheses?
181 Those are unnecessary and should be removed.
185 and len(self.leaves) == 4
187 and self.leaves[2].type == token.LPAR
188 and self.leaves[2].value == "("
189 and self.leaves[3].type == token.RPAR
190 and self.leaves[3].value == ")"
194 def is_triple_quoted_string(self) -> bool:
195 """Is the line a triple quoted string?"""
196 if not self or self.leaves[0].type != token.STRING:
198 value = self.leaves[0].value
199 if value.startswith(('"""', "'''")):
201 if Preview.accept_raw_docstrings in self.mode and value.startswith(
202 ("r'''", 'r"""', "R'''", 'R"""')
208 def opens_block(self) -> bool:
209 """Does this line open a new level of indentation."""
210 if len(self.leaves) == 0:
212 return self.leaves[-1].type == token.COLON
214 def is_fmt_pass_converted(
215 self, *, first_leaf_matches: Optional[Callable[[Leaf], bool]] = None
217 """Is this line converted from fmt off/skip code?
219 If first_leaf_matches is not None, it only returns True if the first
220 leaf of converted code matches.
222 if len(self.leaves) != 1:
224 leaf = self.leaves[0]
226 leaf.type != STANDALONE_COMMENT
227 or leaf.fmt_pass_converted_first_leaf is None
230 return first_leaf_matches is None or first_leaf_matches(
231 leaf.fmt_pass_converted_first_leaf
234 def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
235 """If so, needs to be split before emitting."""
236 for leaf in self.leaves:
237 if leaf.type == STANDALONE_COMMENT and leaf.bracket_depth <= depth_limit:
242 def contains_uncollapsable_type_comments(self) -> bool:
245 last_leaf = self.leaves[-1]
246 ignored_ids.add(id(last_leaf))
247 if last_leaf.type == token.COMMA or (
248 last_leaf.type == token.RPAR and not last_leaf.value
250 # When trailing commas or optional parens are inserted by Black for
251 # consistency, comments after the previous last element are not moved
252 # (they don't have to, rendering will still be correct). So we ignore
253 # trailing commas and invisible.
254 last_leaf = self.leaves[-2]
255 ignored_ids.add(id(last_leaf))
259 # A type comment is uncollapsable if it is attached to a leaf
260 # that isn't at the end of the line (since that could cause it
261 # to get associated to a different argument) or if there are
262 # comments before it (since that could cause it to get hidden
265 for leaf_id, comments in self.comments.items():
266 for comment in comments:
267 if is_type_comment(comment):
269 not is_type_ignore_comment(comment)
270 and leaf_id not in ignored_ids
278 def contains_unsplittable_type_ignore(self) -> bool:
282 # If a 'type: ignore' is attached to the end of a line, we
283 # can't split the line, because we can't know which of the
284 # subexpressions the ignore was meant to apply to.
286 # We only want this to apply to actual physical lines from the
287 # original source, though: we don't want the presence of a
288 # 'type: ignore' at the end of a multiline expression to
289 # justify pushing it all onto one line. Thus we
290 # (unfortunately) need to check the actual source lines and
291 # only report an unsplittable 'type: ignore' if this line was
292 # one line in the original code.
294 # Grab the first and last line numbers, skipping generated leaves
295 first_line = next((leaf.lineno for leaf in self.leaves if leaf.lineno != 0), 0)
297 (leaf.lineno for leaf in reversed(self.leaves) if leaf.lineno != 0), 0
300 if first_line == last_line:
301 # We look at the last two leaves since a comma or an
302 # invisible paren could have been added at the end of the
304 for node in self.leaves[-2:]:
305 for comment in self.comments.get(id(node), []):
306 if is_type_ignore_comment(comment):
311 def contains_multiline_strings(self) -> bool:
312 return any(is_multiline_string(leaf) for leaf in self.leaves)
314 def has_magic_trailing_comma(
315 self, closing: Leaf, ensure_removable: bool = False
317 """Return True if we have a magic trailing comma, that is when:
318 - there's a trailing comma here
319 - it's not a one-tuple
320 - it's not a single-element subscript
321 Additionally, if ensure_removable:
322 - it's not from square bracket indexing
323 (specifically, single-element square bracket indexing)
326 closing.type in CLOSING_BRACKETS
328 and self.leaves[-1].type == token.COMMA
332 if closing.type == token.RBRACE:
335 if closing.type == token.RSQB:
338 and closing.parent.type == syms.trailer
339 and closing.opening_bracket
340 and is_one_sequence_between(
341 closing.opening_bracket,
344 brackets=(token.LSQB, token.RSQB),
349 if not ensure_removable:
352 comma = self.leaves[-1]
353 if comma.parent is None:
356 comma.parent.type != syms.subscriptlist
357 or closing.opening_bracket is None
358 or not is_one_sequence_between(
359 closing.opening_bracket,
362 brackets=(token.LSQB, token.RSQB),
369 if closing.opening_bracket is not None and not is_one_sequence_between(
370 closing.opening_bracket, closing, self.leaves
376 def append_comment(self, comment: Leaf) -> bool:
377 """Add an inline or standalone comment to the line."""
379 comment.type == STANDALONE_COMMENT
380 and self.bracket_tracker.any_open_brackets()
385 if comment.type != token.COMMENT:
389 comment.type = STANDALONE_COMMENT
393 last_leaf = self.leaves[-1]
395 last_leaf.type == token.RPAR
396 and not last_leaf.value
398 and len(list(last_leaf.parent.leaves())) <= 3
399 and not is_type_comment(comment)
401 # Comments on an optional parens wrapping a single leaf should belong to
402 # the wrapped node except if it's a type comment. Pinning the comment like
403 # this avoids unstable formatting caused by comment migration.
404 if len(self.leaves) < 2:
405 comment.type = STANDALONE_COMMENT
409 last_leaf = self.leaves[-2]
410 self.comments.setdefault(id(last_leaf), []).append(comment)
413 def comments_after(self, leaf: Leaf) -> List[Leaf]:
414 """Generate comments that should appear directly after `leaf`."""
415 return self.comments.get(id(leaf), [])
417 def remove_trailing_comma(self) -> None:
418 """Remove the trailing comma and moves the comments attached to it."""
419 trailing_comma = self.leaves.pop()
420 trailing_comma_comments = self.comments.pop(id(trailing_comma), [])
421 self.comments.setdefault(id(self.leaves[-1]), []).extend(
422 trailing_comma_comments
425 def is_complex_subscript(self, leaf: Leaf) -> bool:
426 """Return True iff `leaf` is part of a slice with non-trivial exprs."""
427 open_lsqb = self.bracket_tracker.get_open_lsqb()
428 if open_lsqb is None:
431 subscript_start = open_lsqb.next_sibling
433 if isinstance(subscript_start, Node):
434 if subscript_start.type == syms.listmaker:
437 if subscript_start.type == syms.subscriptlist:
438 subscript_start = child_towards(subscript_start, leaf)
439 return subscript_start is not None and any(
440 n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
443 def enumerate_with_length(
444 self, reversed: bool = False
445 ) -> Iterator[Tuple[Index, Leaf, int]]:
446 """Return an enumeration of leaves with their length.
448 Stops prematurely on multiline strings and standalone comments.
451 Callable[[Sequence[Leaf]], Iterator[Tuple[Index, Leaf]]],
452 enumerate_reversed if reversed else enumerate,
454 for index, leaf in op(self.leaves):
455 length = len(leaf.prefix) + len(leaf.value)
456 if "\n" in leaf.value:
457 return # Multiline strings, we can't continue.
459 for comment in self.comments_after(leaf):
460 length += len(comment.value)
462 yield index, leaf, length
464 def clone(self) -> "Line":
468 inside_brackets=self.inside_brackets,
469 should_split_rhs=self.should_split_rhs,
470 magic_trailing_comma=self.magic_trailing_comma,
473 def __str__(self) -> str:
474 """Render the line."""
478 indent = " " * self.depth
479 leaves = iter(self.leaves)
481 res = f"{first.prefix}{indent}{first.value}"
484 for comment in itertools.chain.from_iterable(self.comments.values()):
489 def __bool__(self) -> bool:
490 """Return True if the line has leaves or comments."""
491 return bool(self.leaves or self.comments)
496 """Intermediate split result from a right hand split."""
501 opening_bracket: Leaf
502 closing_bracket: Leaf
507 """Class that holds information about a block of formatted lines.
509 This is introduced so that the EmptyLineTracker can look behind the standalone
510 comments and adjust their empty lines for class or def lines.
514 previous_block: Optional["LinesBlock"]
517 content_lines: List[str] = field(default_factory=list)
520 def all_lines(self) -> List[str]:
521 empty_line = str(Line(mode=self.mode))
523 [empty_line * self.before] + self.content_lines + [empty_line * self.after]
528 class EmptyLineTracker:
529 """Provides a stateful method that returns the number of potential extra
530 empty lines needed before and after the currently processed line.
532 Note: this tracker works on lines that haven't been split yet. It assumes
533 the prefix of the first leaf consists of optional newlines. Those newlines
534 are consumed by `maybe_empty_lines()` and included in the computation.
538 previous_line: Optional[Line] = None
539 previous_block: Optional[LinesBlock] = None
540 previous_defs: List[Line] = field(default_factory=list)
541 semantic_leading_comment: Optional[LinesBlock] = None
543 def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
544 """Return the number of extra empty lines before and after the `current_line`.
546 This is for separating `def`, `async def` and `class` with extra empty
547 lines (two on module-level).
549 before, after = self._maybe_empty_lines(current_line)
550 previous_after = self.previous_block.after if self.previous_block else 0
552 # Black should not insert empty lines at the beginning
555 if self.previous_line is None
556 else before - previous_after
559 Preview.module_docstring_newlines in current_line.mode
560 and self.previous_block
561 and self.previous_block.previous_block is None
562 and len(self.previous_block.original_line.leaves) == 1
563 and self.previous_block.original_line.is_triple_quoted_string
569 previous_block=self.previous_block,
570 original_line=current_line,
575 # Maintain the semantic_leading_comment state.
576 if current_line.is_comment:
577 if self.previous_line is None or (
578 not self.previous_line.is_decorator
579 # `or before` means this comment already has an empty line before
580 and (not self.previous_line.is_comment or before)
581 and (self.semantic_leading_comment is None or before)
583 self.semantic_leading_comment = block
584 # `or before` means this decorator already has an empty line before
585 elif not current_line.is_decorator or before:
586 self.semantic_leading_comment = None
588 self.previous_line = current_line
589 self.previous_block = block
592 def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
594 if current_line.depth == 0:
595 max_allowed = 1 if self.mode.is_pyi else 2
596 if current_line.leaves:
597 # Consume the first leaf's extra newlines.
598 first_leaf = current_line.leaves[0]
599 before = first_leaf.prefix.count("\n")
600 before = min(before, max_allowed)
601 first_leaf.prefix = ""
605 user_had_newline = bool(before)
606 depth = current_line.depth
609 while self.previous_defs and self.previous_defs[-1].depth >= depth:
610 previous_def = self.previous_defs.pop()
612 if previous_def is not None:
613 assert self.previous_line is not None
615 if depth and not current_line.is_def and self.previous_line.is_def:
616 # Empty lines between attributes and methods should be preserved.
617 before = 1 if user_had_newline else 0
619 Preview.blank_line_after_nested_stub_class in self.mode
620 and previous_def.is_class
621 and not previous_def.is_stub_class
633 and previous_def.depth
634 and current_line.leaves[-1].type == token.COLON
636 current_line.leaves[0].value
637 not in ("with", "try", "for", "while", "if", "match")
640 # We shouldn't add two newlines between an indented function and
641 # a dependent non-indented clause. This is to avoid issues with
642 # conditional function definitions that are technically top-level
643 # and therefore get two trailing newlines, but look weird and
644 # inconsistent when they're followed by elif, else, etc. This is
645 # worse because these functions only get *one* preceding newline
651 if current_line.is_decorator or current_line.is_def or current_line.is_class:
652 return self._maybe_empty_lines_for_class_or_def(
653 current_line, before, user_had_newline
658 and self.previous_line.is_import
659 and not current_line.is_import
660 and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
661 and depth == self.previous_line.depth
663 return (before or 1), 0
667 and self.previous_line.is_class
668 and current_line.is_triple_quoted_string
670 if Preview.no_blank_line_before_class_docstring in current_line.mode:
674 if self.previous_line and self.previous_line.opens_block:
678 def _maybe_empty_lines_for_class_or_def( # noqa: C901
679 self, current_line: Line, before: int, user_had_newline: bool
680 ) -> Tuple[int, int]:
681 if not current_line.is_decorator:
682 self.previous_defs.append(current_line)
683 if self.previous_line is None:
684 # Don't insert empty lines before the first line in the file.
687 if self.previous_line.is_decorator:
688 if self.mode.is_pyi and current_line.is_stub_class:
689 # Insert an empty line after a decorated stub class
694 if self.previous_line.depth < current_line.depth and (
695 self.previous_line.is_class or self.previous_line.is_def
699 comment_to_add_newlines: Optional[LinesBlock] = None
701 self.previous_line.is_comment
702 and self.previous_line.depth == current_line.depth
705 slc = self.semantic_leading_comment
708 and slc.previous_block is not None
709 and not slc.previous_block.original_line.is_class
710 and not slc.previous_block.original_line.opens_block
713 comment_to_add_newlines = slc
718 if current_line.is_class or self.previous_line.is_class:
719 if self.previous_line.depth < current_line.depth:
721 elif self.previous_line.depth > current_line.depth:
723 elif current_line.is_stub_class and self.previous_line.is_stub_class:
724 # No blank line between classes with an empty body
728 # Remove case `self.previous_line.depth > current_line.depth` below when
729 # this becomes stable.
731 # Don't inspect the previous line if it's part of the body of the previous
732 # statement in the same level, we always want a blank line if there's
733 # something with a body preceding.
735 Preview.blank_line_between_nested_and_def_stub_file in current_line.mode
736 and self.previous_line.depth > current_line.depth
740 current_line.is_def or current_line.is_decorator
741 ) and not self.previous_line.is_def:
742 if current_line.depth:
743 # In classes empty lines between attributes and methods should
745 newlines = min(1, before)
747 # Blank line between a block of functions (maybe with preceding
748 # decorators) and a block of non-functions
750 elif self.previous_line.depth > current_line.depth:
755 newlines = 1 if current_line.depth else 2
756 # If a user has left no space after a dummy implementation, don't insert
757 # new lines. This is useful for instance for @overload or Protocols.
759 Preview.dummy_implementations in self.mode
760 and self.previous_line.is_stub_def
761 and not user_had_newline
764 if comment_to_add_newlines is not None:
765 previous_block = comment_to_add_newlines.previous_block
766 if previous_block is not None:
767 comment_to_add_newlines.before = (
768 max(comment_to_add_newlines.before, newlines) - previous_block.after
774 def enumerate_reversed(sequence: Sequence[T]) -> Iterator[Tuple[Index, T]]:
775 """Like `reversed(enumerate(sequence))` if that were possible."""
776 index = len(sequence) - 1
777 for element in reversed(sequence):
778 yield (index, element)
783 new_line: Line, old_line: Line, leaves: List[Leaf], preformatted: bool = False
786 Append leaves (taken from @old_line) to @new_line, making sure to fix the
787 underlying Node structure where appropriate.
789 All of the leaves in @leaves are duplicated. The duplicates are then
790 appended to @new_line and used to replace their originals in the underlying
791 Node structure. Any comments attached to the old leaves are reattached to
795 set(@leaves) is a subset of set(@old_line.leaves).
797 for old_leaf in leaves:
798 new_leaf = Leaf(old_leaf.type, old_leaf.value)
799 replace_child(old_leaf, new_leaf)
800 new_line.append(new_leaf, preformatted=preformatted)
802 for comment_leaf in old_line.comments_after(old_leaf):
803 new_line.append(comment_leaf, preformatted=True)
806 def is_line_short_enough( # noqa: C901
807 line: Line, *, mode: Mode, line_str: str = ""
809 """For non-multiline strings, return True if `line` is no longer than `line_length`.
810 For multiline strings, looks at the context around `line` to determine
811 if it should be inlined or split up.
812 Uses the provided `line_str` rendering, if any, otherwise computes a new one.
815 line_str = line_to_string(line)
817 width = str_width if mode.preview else len
819 if Preview.multiline_string_handling not in mode:
821 width(line_str) <= mode.line_length
822 and "\n" not in line_str # multiline strings
823 and not line.contains_standalone_comments()
826 if line.contains_standalone_comments():
828 if "\n" not in line_str:
829 # No multiline strings (MLS) present
830 return width(line_str) <= mode.line_length
832 first, *_, last = line_str.split("\n")
833 if width(first) > mode.line_length or width(last) > mode.line_length:
836 # Traverse the AST to examine the context of the multiline string (MLS),
837 # tracking aspects such as depth and comma existence,
838 # to determine whether to split the MLS or keep it together.
839 # Depth (which is based on the existing bracket_depth concept)
840 # is needed to determine nesting level of the MLS.
841 # Includes special case for trailing commas.
842 commas: List[int] = [] # tracks number of commas per depth level
843 multiline_string: Optional[Leaf] = None
844 # store the leaves that contain parts of the MLS
845 multiline_string_contexts: List[LN] = []
847 max_level_to_update: Union[int, float] = math.inf # track the depth of the MLS
848 for i, leaf in enumerate(line.leaves):
849 if max_level_to_update == math.inf:
850 had_comma: Optional[int] = None
851 if leaf.bracket_depth + 1 > len(commas):
853 elif leaf.bracket_depth + 1 < len(commas):
854 had_comma = commas.pop()
856 had_comma is not None
857 and multiline_string is not None
858 and multiline_string.bracket_depth == leaf.bracket_depth + 1
860 # Have left the level with the MLS, stop tracking commas
861 max_level_to_update = leaf.bracket_depth
863 # MLS was in parens with at least one comma - force split
866 if leaf.bracket_depth <= max_level_to_update and leaf.type == token.COMMA:
867 # Ignore non-nested trailing comma
868 # directly after MLS/MLS-containing expression
869 ignore_ctxs: List[Optional[LN]] = [None]
870 ignore_ctxs += multiline_string_contexts
871 if not (leaf.prev_sibling in ignore_ctxs and i == len(line.leaves) - 1):
872 commas[leaf.bracket_depth] += 1
873 if max_level_to_update != math.inf:
874 max_level_to_update = min(max_level_to_update, leaf.bracket_depth)
876 if is_multiline_string(leaf):
877 if len(multiline_string_contexts) > 0:
878 # >1 multiline string cannot fit on a single line - force split
880 multiline_string = leaf
882 # fetch the leaf components of the MLS in the AST
883 while str(ctx) in line_str:
884 multiline_string_contexts.append(ctx)
885 if ctx.parent is None:
889 # May not have a triple-quoted multiline string at all,
890 # in case of a regular string with embedded newlines and line continuations
891 if len(multiline_string_contexts) == 0:
894 return all(val == 0 for val in commas)
897 def can_be_split(line: Line) -> bool:
898 """Return False if the line cannot be split *for sure*.
900 This is not an exhaustive search but a cheap heuristic that we can use to
901 avoid some unfortunate formattings (mostly around wrapping unsplittable code
902 in unnecessary parentheses).
908 if leaves[0].type == token.STRING and leaves[1].type == token.DOT:
912 for leaf in leaves[-2::-1]:
913 if leaf.type in OPENING_BRACKETS:
914 if next.type not in CLOSING_BRACKETS:
918 elif leaf.type == token.DOT:
920 elif leaf.type == token.NAME:
921 if not (next.type == token.DOT or next.type in OPENING_BRACKETS):
924 elif leaf.type not in CLOSING_BRACKETS:
927 if dot_count > 1 and call_count > 1:
933 def can_omit_invisible_parens(
937 """Does `rhs.body` have a shape safe to reformat without optional parens around it?
939 Returns True for only a subset of potentially nice looking formattings but
940 the point is to not return false positives that end up producing lines that
944 bt = line.bracket_tracker
945 if not bt.delimiters:
946 # Without delimiters the optional parentheses are useless.
949 max_priority = bt.max_delimiter_priority()
950 delimiter_count = bt.delimiter_count_with_priority(max_priority)
951 if delimiter_count > 1:
952 # With more than one delimiter of a kind the optional parentheses read better.
955 if delimiter_count == 1:
957 Preview.wrap_multiple_context_managers_in_parens in line.mode
958 and max_priority == COMMA_PRIORITY
959 and rhs.head.is_with_or_async_with_stmt
961 # For two context manager with statements, the optional parentheses read
962 # better. In this case, `rhs.body` is the context managers part of
963 # the with statement. `rhs.head` is the `with (` part on the previous
966 # Otherwise it may also read better, but we don't do it today and requires
967 # careful considerations for all possible cases. See
968 # https://github.com/psf/black/issues/2156.
970 if max_priority == DOT_PRIORITY:
971 # A single stranded method call doesn't require optional parentheses.
974 assert len(line.leaves) >= 2, "Stranded delimiter"
976 # With a single delimiter, omit if the expression starts or ends with
978 first = line.leaves[0]
979 second = line.leaves[1]
980 if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS:
981 if _can_omit_opening_paren(line, first=first, line_length=line_length):
984 # Note: we are not returning False here because a line might have *both*
985 # a leading opening bracket and a trailing closing bracket. If the
986 # opening bracket doesn't match our rule, maybe the closing will.
988 penultimate = line.leaves[-2]
989 last = line.leaves[-1]
992 last.type == token.RPAR
993 or last.type == token.RBRACE
995 # don't use indexing for omitting optional parentheses;
997 last.type == token.RSQB
999 and last.parent.type != syms.trailer
1002 if penultimate.type in OPENING_BRACKETS:
1003 # Empty brackets don't help.
1006 if is_multiline_string(first):
1007 # Additional wrapping of a multiline string in this situation is
1011 if _can_omit_closing_paren(line, last=last, line_length=line_length):
1017 def _can_omit_opening_paren(line: Line, *, first: Leaf, line_length: int) -> bool:
1018 """See `can_omit_invisible_parens`."""
1020 length = 4 * line.depth
1022 for _index, leaf, leaf_length in line.enumerate_with_length():
1023 if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first:
1026 length += leaf_length
1027 if length > line_length:
1030 if leaf.type in OPENING_BRACKETS:
1031 # There are brackets we can further split on.
1035 # checked the entire string and line length wasn't exceeded
1036 if len(line.leaves) == _index + 1:
1042 def _can_omit_closing_paren(line: Line, *, last: Leaf, line_length: int) -> bool:
1043 """See `can_omit_invisible_parens`."""
1044 length = 4 * line.depth
1045 seen_other_brackets = False
1046 for _index, leaf, leaf_length in line.enumerate_with_length():
1047 length += leaf_length
1048 if leaf is last.opening_bracket:
1049 if seen_other_brackets or length <= line_length:
1052 elif leaf.type in OPENING_BRACKETS:
1053 # There are brackets we can further split on.
1054 seen_other_brackets = True
1059 def line_to_string(line: Line) -> str:
1060 """Returns the string representation of @line.
1062 WARNING: This is known to be computationally expensive.
1064 return str(line).strip("\n")