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.
2 Generating lines of code.
4 from functools import partial, wraps
6 from typing import Collection, Iterator, List, Optional, Set, Union
8 from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT
9 from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS
10 from black.nodes import Visitor, syms, first_child_is_arith, ensure_visible
11 from black.nodes import is_docstring, is_empty_tuple, is_one_tuple, is_one_tuple_between
12 from black.nodes import is_walrus_assignment, is_yield, is_vararg, is_multiline_string
13 from black.nodes import is_stub_suite, is_stub_body, is_atom_with_invisible_parens
14 from black.nodes import wrap_in_parentheses
15 from black.brackets import max_delimiter_priority_in_atom
16 from black.brackets import DOT_PRIORITY, COMMA_PRIORITY
17 from black.lines import Line, line_to_string, is_line_short_enough
18 from black.lines import can_omit_invisible_parens, can_be_split, append_leaves
19 from black.comments import generate_comments, list_comments, FMT_OFF
20 from black.numerics import normalize_numeric_literal
21 from black.strings import get_string_prefix, fix_docstring
22 from black.strings import normalize_string_prefix, normalize_string_quotes
23 from black.trans import Transformer, CannotTransform, StringMerger
24 from black.trans import StringSplitter, StringParenWrapper, StringParenStripper
25 from black.mode import Mode
26 from black.mode import Feature
28 from blib2to3.pytree import Node, Leaf
29 from blib2to3.pgen2 import token
34 LN = Union[Leaf, Node]
37 class CannotSplit(CannotTransform):
38 """A readable split that fits the allotted line length is impossible."""
41 # This isn't a dataclass because @dataclass + Generic breaks mypyc.
42 # See also https://github.com/mypyc/mypyc/issues/827.
43 class LineGenerator(Visitor[Line]):
44 """Generates reformatted Line objects. Empty lines are not emitted.
46 Note: destroys the tree it's visiting by mutating prefixes of its leaves
47 in ways that will no longer stringify to valid Python code on the tree.
50 def __init__(self, mode: Mode, remove_u_prefix: bool = False) -> None:
52 self.remove_u_prefix = remove_u_prefix
53 self.current_line: Line
56 def line(self, indent: int = 0) -> Iterator[Line]:
59 If the line is empty, only emit if it makes sense.
60 If the line is too long, split it first and then generate.
62 If any lines were generated, set up a new current_line.
64 if not self.current_line:
65 self.current_line.depth += indent
66 return # Line is empty, don't emit. Creating a new one unnecessary.
68 complete_line = self.current_line
69 self.current_line = Line(mode=self.mode, depth=complete_line.depth + indent)
72 def visit_default(self, node: LN) -> Iterator[Line]:
73 """Default `visit_*()` implementation. Recurses to children of `node`."""
74 if isinstance(node, Leaf):
75 any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
76 for comment in generate_comments(node):
78 # any comment within brackets is subject to splitting
79 self.current_line.append(comment)
80 elif comment.type == token.COMMENT:
81 # regular trailing comment
82 self.current_line.append(comment)
83 yield from self.line()
86 # regular standalone comment
87 yield from self.line()
89 self.current_line.append(comment)
90 yield from self.line()
92 normalize_prefix(node, inside_brackets=any_open_brackets)
93 if self.mode.string_normalization and node.type == token.STRING:
94 node.value = normalize_string_prefix(
95 node.value, remove_u_prefix=self.remove_u_prefix
97 node.value = normalize_string_quotes(node.value)
98 if node.type == token.NUMBER:
99 normalize_numeric_literal(node)
100 if node.type not in WHITESPACE:
101 self.current_line.append(node)
102 yield from super().visit_default(node)
104 def visit_INDENT(self, node: Leaf) -> Iterator[Line]:
105 """Increase indentation level, maybe yield a line."""
106 # In blib2to3 INDENT never holds comments.
107 yield from self.line(+1)
108 yield from self.visit_default(node)
110 def visit_DEDENT(self, node: Leaf) -> Iterator[Line]:
111 """Decrease indentation level, maybe yield a line."""
112 # The current line might still wait for trailing comments. At DEDENT time
113 # there won't be any (they would be prefixes on the preceding NEWLINE).
114 # Emit the line then.
115 yield from self.line()
117 # While DEDENT has no value, its prefix may contain standalone comments
118 # that belong to the current indentation level. Get 'em.
119 yield from self.visit_default(node)
121 # Finally, emit the dedent.
122 yield from self.line(-1)
125 self, node: Node, keywords: Set[str], parens: Set[str]
127 """Visit a statement.
129 This implementation is shared for `if`, `while`, `for`, `try`, `except`,
130 `def`, `with`, `class`, `assert`, `match`, `case` and assignments.
132 The relevant Python language `keywords` for a given statement will be
133 NAME leaves within it. This methods puts those on a separate line.
135 `parens` holds a set of string leaf values immediately after which
136 invisible parens should be put.
138 normalize_invisible_parens(node, parens_after=parens)
139 for child in node.children:
140 if child.type == token.NAME and child.value in keywords: # type: ignore
141 yield from self.line()
143 yield from self.visit(child)
145 def visit_suite(self, node: Node) -> Iterator[Line]:
147 if self.mode.is_pyi and is_stub_suite(node):
148 yield from self.visit(node.children[2])
150 yield from self.visit_default(node)
152 def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
153 """Visit a statement without nested statements."""
154 if first_child_is_arith(node):
155 wrap_in_parentheses(node, node.children[0], visible=False)
156 is_suite_like = node.parent and node.parent.type in STATEMENT
158 if self.mode.is_pyi and is_stub_body(node):
159 yield from self.visit_default(node)
161 yield from self.line(+1)
162 yield from self.visit_default(node)
163 yield from self.line(-1)
169 or not is_stub_suite(node.parent)
171 yield from self.line()
172 yield from self.visit_default(node)
174 def visit_async_stmt(self, node: Node) -> Iterator[Line]:
175 """Visit `async def`, `async for`, `async with`."""
176 yield from self.line()
178 children = iter(node.children)
179 for child in children:
180 yield from self.visit(child)
182 if child.type == token.ASYNC:
185 internal_stmt = next(children)
186 for child in internal_stmt.children:
187 yield from self.visit(child)
189 def visit_decorators(self, node: Node) -> Iterator[Line]:
190 """Visit decorators."""
191 for child in node.children:
192 yield from self.line()
193 yield from self.visit(child)
195 def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]:
196 """Remove a semicolon and put the other statement on a separate line."""
197 yield from self.line()
199 def visit_ENDMARKER(self, leaf: Leaf) -> Iterator[Line]:
200 """End of file. Process outstanding comments and end with a newline."""
201 yield from self.visit_default(leaf)
202 yield from self.line()
204 def visit_STANDALONE_COMMENT(self, leaf: Leaf) -> Iterator[Line]:
205 if not self.current_line.bracket_tracker.any_open_brackets():
206 yield from self.line()
207 yield from self.visit_default(leaf)
209 def visit_factor(self, node: Node) -> Iterator[Line]:
210 """Force parentheses between a unary op and a binary power:
214 _operator, operand = node.children
216 operand.type == syms.power
217 and len(operand.children) == 3
218 and operand.children[1].type == token.DOUBLESTAR
220 lpar = Leaf(token.LPAR, "(")
221 rpar = Leaf(token.RPAR, ")")
222 index = operand.remove() or 0
223 node.insert_child(index, Node(syms.atom, [lpar, operand, rpar]))
224 yield from self.visit_default(node)
226 def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
227 if is_docstring(leaf) and "\\\n" not in leaf.value:
228 # We're ignoring docstrings with backslash newline escapes because changing
229 # indentation of those changes the AST representation of the code.
230 docstring = normalize_string_prefix(leaf.value, self.remove_u_prefix)
231 prefix = get_string_prefix(docstring)
232 docstring = docstring[len(prefix) :] # Remove the prefix
233 quote_char = docstring[0]
234 # A natural way to remove the outer quotes is to do:
235 # docstring = docstring.strip(quote_char)
236 # but that breaks on """""x""" (which is '""x').
237 # So we actually need to remove the first character and the next two
238 # characters but only if they are the same as the first.
239 quote_len = 1 if docstring[1] != quote_char else 3
240 docstring = docstring[quote_len:-quote_len]
241 docstring_started_empty = not docstring
243 if is_multiline_string(leaf):
244 indent = " " * 4 * self.current_line.depth
245 docstring = fix_docstring(docstring, indent)
247 docstring = docstring.strip()
250 # Add some padding if the docstring starts / ends with a quote mark.
251 if docstring[0] == quote_char:
252 docstring = " " + docstring
253 if docstring[-1] == quote_char:
255 if docstring[-1] == "\\":
256 backslash_count = len(docstring) - len(docstring.rstrip("\\"))
257 if backslash_count % 2:
258 # Odd number of tailing backslashes, add some padding to
259 # avoid escaping the closing string quote.
261 elif not docstring_started_empty:
264 # We could enforce triple quotes at this point.
265 quote = quote_char * quote_len
266 leaf.value = prefix + quote + docstring + quote
268 yield from self.visit_default(leaf)
270 def __post_init__(self) -> None:
271 """You are in a twisty little maze of passages."""
272 self.current_line = Line(mode=self.mode)
276 self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
277 self.visit_if_stmt = partial(
278 v, keywords={"if", "else", "elif"}, parens={"if", "elif"}
280 self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"})
281 self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"})
282 self.visit_try_stmt = partial(
283 v, keywords={"try", "except", "else", "finally"}, parens=Ø
285 self.visit_except_clause = partial(v, keywords={"except"}, parens=Ø)
286 self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø)
287 self.visit_funcdef = partial(v, keywords={"def"}, parens=Ø)
288 self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
289 self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS)
290 self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
291 self.visit_import_from = partial(v, keywords=Ø, parens={"import"})
292 self.visit_del_stmt = partial(v, keywords=Ø, parens={"del"})
293 self.visit_async_funcdef = self.visit_async_stmt
294 self.visit_decorated = self.visit_decorators
297 self.visit_match_stmt = partial(v, keywords={"match"}, parens=Ø)
298 self.visit_case_block = partial(v, keywords={"case"}, parens=Ø)
302 line: Line, mode: Mode, features: Collection[Feature] = ()
304 """Transform a `line`, potentially splitting it into many lines.
306 They should fit in the allotted `line_length` but might not be able to.
308 `features` are syntactical features that may be used in the output.
314 line_str = line_to_string(line)
316 ll = mode.line_length
317 sn = mode.string_normalization
318 string_merge = StringMerger(ll, sn)
319 string_paren_strip = StringParenStripper(ll, sn)
320 string_split = StringSplitter(ll, sn)
321 string_paren_wrap = StringParenWrapper(ll, sn)
323 transformers: List[Transformer]
325 not line.contains_uncollapsable_type_comments()
326 and not line.should_split_rhs
327 and not line.magic_trailing_comma
329 is_line_short_enough(line, line_length=mode.line_length, line_str=line_str)
330 or line.contains_unsplittable_type_ignore()
332 and not (line.inside_brackets and line.contains_standalone_comments())
334 # Only apply basic string preprocessing, since lines shouldn't be split here.
335 if mode.experimental_string_processing:
336 transformers = [string_merge, string_paren_strip]
340 transformers = [left_hand_split]
344 self: object, line: Line, features: Collection[Feature]
346 """Wraps calls to `right_hand_split`.
348 The calls increasingly `omit` right-hand trailers (bracket pairs with
349 content), meaning the trailers get glued together to split on another
350 bracket pair instead.
352 for omit in generate_trailers_to_omit(line, mode.line_length):
354 right_hand_split(line, mode.line_length, features, omit=omit)
356 # Note: this check is only able to figure out if the first line of the
357 # *current* transformation fits in the line length. This is true only
358 # for simple cases. All others require running more transforms via
359 # `transform_line()`. This check doesn't know if those would succeed.
360 if is_line_short_enough(lines[0], line_length=mode.line_length):
364 # All splits failed, best effort split with no omits.
365 # This mostly happens to multiline strings that are by definition
366 # reported as not fitting a single line, as well as lines that contain
367 # trailing commas (those have to be exploded).
368 yield from right_hand_split(
369 line, line_length=mode.line_length, features=features
372 # HACK: nested functions (like _rhs) compiled by mypyc don't retain their
373 # __name__ attribute which is needed in `run_transformer` further down.
374 # Unfortunately a nested class breaks mypyc too. So a class must be created
375 # via type ... https://github.com/mypyc/mypyc/issues/884
376 rhs = type("rhs", (), {"__call__": _rhs})()
378 if mode.experimental_string_processing:
379 if line.inside_brackets:
385 standalone_comment_split,
398 if line.inside_brackets:
399 transformers = [delimiter_split, standalone_comment_split, rhs]
403 for transform in transformers:
404 # We are accumulating lines in `result` because we might want to abort
405 # mission and return the original line in the end, or attempt a different
408 result = run_transformer(line, transform, mode, features, line_str=line_str)
409 except CannotTransform:
419 def left_hand_split(line: Line, _features: Collection[Feature] = ()) -> Iterator[Line]:
420 """Split line into many lines, starting with the first matching bracket pair.
422 Note: this usually looks weird, only use this for function definitions.
423 Prefer RHS otherwise. This is why this function is not symmetrical with
424 :func:`right_hand_split` which also handles optional parentheses.
426 tail_leaves: List[Leaf] = []
427 body_leaves: List[Leaf] = []
428 head_leaves: List[Leaf] = []
429 current_leaves = head_leaves
430 matching_bracket: Optional[Leaf] = None
431 for leaf in line.leaves:
433 current_leaves is body_leaves
434 and leaf.type in CLOSING_BRACKETS
435 and leaf.opening_bracket is matching_bracket
437 current_leaves = tail_leaves if body_leaves else head_leaves
438 current_leaves.append(leaf)
439 if current_leaves is head_leaves:
440 if leaf.type in OPENING_BRACKETS:
441 matching_bracket = leaf
442 current_leaves = body_leaves
443 if not matching_bracket:
444 raise CannotSplit("No brackets found")
446 head = bracket_split_build_line(head_leaves, line, matching_bracket)
447 body = bracket_split_build_line(body_leaves, line, matching_bracket, is_body=True)
448 tail = bracket_split_build_line(tail_leaves, line, matching_bracket)
449 bracket_split_succeeded_or_raise(head, body, tail)
450 for result in (head, body, tail):
455 def right_hand_split(
458 features: Collection[Feature] = (),
459 omit: Collection[LeafID] = (),
461 """Split line into many lines, starting with the last matching bracket pair.
463 If the split was by optional parentheses, attempt splitting without them, too.
464 `omit` is a collection of closing bracket IDs that shouldn't be considered for
467 Note: running this function modifies `bracket_depth` on the leaves of `line`.
469 tail_leaves: List[Leaf] = []
470 body_leaves: List[Leaf] = []
471 head_leaves: List[Leaf] = []
472 current_leaves = tail_leaves
473 opening_bracket: Optional[Leaf] = None
474 closing_bracket: Optional[Leaf] = None
475 for leaf in reversed(line.leaves):
476 if current_leaves is body_leaves:
477 if leaf is opening_bracket:
478 current_leaves = head_leaves if body_leaves else tail_leaves
479 current_leaves.append(leaf)
480 if current_leaves is tail_leaves:
481 if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit:
482 opening_bracket = leaf.opening_bracket
483 closing_bracket = leaf
484 current_leaves = body_leaves
485 if not (opening_bracket and closing_bracket and head_leaves):
486 # If there is no opening or closing_bracket that means the split failed and
487 # all content is in the tail. Otherwise, if `head_leaves` are empty, it means
488 # the matching `opening_bracket` wasn't available on `line` anymore.
489 raise CannotSplit("No brackets found")
491 tail_leaves.reverse()
492 body_leaves.reverse()
493 head_leaves.reverse()
494 head = bracket_split_build_line(head_leaves, line, opening_bracket)
495 body = bracket_split_build_line(body_leaves, line, opening_bracket, is_body=True)
496 tail = bracket_split_build_line(tail_leaves, line, opening_bracket)
497 bracket_split_succeeded_or_raise(head, body, tail)
499 Feature.FORCE_OPTIONAL_PARENTHESES not in features
500 # the opening bracket is an optional paren
501 and opening_bracket.type == token.LPAR
502 and not opening_bracket.value
503 # the closing bracket is an optional paren
504 and closing_bracket.type == token.RPAR
505 and not closing_bracket.value
506 # it's not an import (optional parens are the only thing we can split on
507 # in this case; attempting a split without them is a waste of time)
508 and not line.is_import
509 # there are no standalone comments in the body
510 and not body.contains_standalone_comments(0)
511 # and we can actually remove the parens
512 and can_omit_invisible_parens(body, line_length, omit_on_explode=omit)
514 omit = {id(closing_bracket), *omit}
516 yield from right_hand_split(line, line_length, features=features, omit=omit)
519 except CannotSplit as e:
522 or is_line_short_enough(body, line_length=line_length)
525 "Splitting failed, body is still too long and can't be split."
528 elif head.contains_multiline_strings() or tail.contains_multiline_strings():
530 "The current optional pair of parentheses is bound to fail to"
531 " satisfy the splitting algorithm because the head or the tail"
532 " contains multiline strings which by definition never fit one"
536 ensure_visible(opening_bracket)
537 ensure_visible(closing_bracket)
538 for result in (head, body, tail):
543 def bracket_split_succeeded_or_raise(head: Line, body: Line, tail: Line) -> None:
544 """Raise :exc:`CannotSplit` if the last left- or right-hand split failed.
546 Do nothing otherwise.
548 A left- or right-hand split is based on a pair of brackets. Content before
549 (and including) the opening bracket is left on one line, content inside the
550 brackets is put on a separate line, and finally content starting with and
551 following the closing bracket is put on a separate line.
553 Those are called `head`, `body`, and `tail`, respectively. If the split
554 produced the same line (all content in `head`) or ended up with an empty `body`
555 and the `tail` is just the closing bracket, then it's considered failed.
557 tail_len = len(str(tail).strip())
560 raise CannotSplit("Splitting brackets produced the same line")
564 f"Splitting brackets on an empty body to save {tail_len} characters is"
569 def bracket_split_build_line(
570 leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False
572 """Return a new line with given `leaves` and respective comments from `original`.
574 If `is_body` is True, the result line is one-indented inside brackets and as such
575 has its first leaf's prefix normalized and a trailing comma added when expected.
577 result = Line(mode=original.mode, depth=original.depth)
579 result.inside_brackets = True
582 # Since body is a new indent level, remove spurious leading whitespace.
583 normalize_prefix(leaves[0], inside_brackets=True)
584 # Ensure a trailing comma for imports and standalone function arguments, but
585 # be careful not to add one after any comments or within type annotations.
588 and opening_bracket.value == "("
589 and not any(leaf.type == token.COMMA for leaf in leaves)
590 # In particular, don't add one within a parenthesized return annotation.
591 # Unfortunately the indicator we're in a return annotation (RARROW) may
592 # be defined directly in the parent node, the parent of the parent ...
593 # and so on depending on how complex the return annotation is.
594 # This isn't perfect and there's some false negatives but they are in
595 # contexts were a comma is actually fine.
597 node.prev_sibling.type == RARROW
600 getattr(leaves[0].parent, "parent", None),
602 if isinstance(node, Node) and isinstance(node.prev_sibling, Leaf)
606 if original.is_import or no_commas:
607 for i in range(len(leaves) - 1, -1, -1):
608 if leaves[i].type == STANDALONE_COMMENT:
611 if leaves[i].type != token.COMMA:
612 new_comma = Leaf(token.COMMA, ",")
613 leaves.insert(i + 1, new_comma)
618 result.append(leaf, preformatted=True)
619 for comment_after in original.comments_after(leaf):
620 result.append(comment_after, preformatted=True)
621 if is_body and should_split_line(result, opening_bracket):
622 result.should_split_rhs = True
626 def dont_increase_indentation(split_func: Transformer) -> Transformer:
627 """Normalize prefix of the first leaf in every line returned by `split_func`.
629 This is a decorator over relevant split functions.
633 def split_wrapper(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]:
634 for line in split_func(line, features):
635 normalize_prefix(line.leaves[0], inside_brackets=True)
641 @dont_increase_indentation
642 def delimiter_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]:
643 """Split according to delimiters of the highest priority.
645 If the appropriate Features are given, the split will add trailing commas
646 also in function signatures and calls that contain `*` and `**`.
649 last_leaf = line.leaves[-1]
651 raise CannotSplit("Line empty") from None
653 bt = line.bracket_tracker
655 delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)})
657 raise CannotSplit("No delimiters found") from None
659 if delimiter_priority == DOT_PRIORITY:
660 if bt.delimiter_count_with_priority(delimiter_priority) == 1:
661 raise CannotSplit("Splitting a single attribute from its owner looks wrong")
664 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
666 lowest_depth = sys.maxsize
667 trailing_comma_safe = True
669 def append_to_line(leaf: Leaf) -> Iterator[Line]:
670 """Append `leaf` to current line or to new line if appending impossible."""
671 nonlocal current_line
673 current_line.append_safe(leaf, preformatted=True)
678 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
680 current_line.append(leaf)
682 for leaf in line.leaves:
683 yield from append_to_line(leaf)
685 for comment_after in line.comments_after(leaf):
686 yield from append_to_line(comment_after)
688 lowest_depth = min(lowest_depth, leaf.bracket_depth)
689 if leaf.bracket_depth == lowest_depth:
690 if is_vararg(leaf, within={syms.typedargslist}):
691 trailing_comma_safe = (
692 trailing_comma_safe and Feature.TRAILING_COMMA_IN_DEF in features
694 elif is_vararg(leaf, within={syms.arglist, syms.argument}):
695 trailing_comma_safe = (
696 trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features
699 leaf_priority = bt.delimiters.get(id(leaf))
700 if leaf_priority == delimiter_priority:
704 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
709 and delimiter_priority == COMMA_PRIORITY
710 and current_line.leaves[-1].type != token.COMMA
711 and current_line.leaves[-1].type != STANDALONE_COMMENT
713 new_comma = Leaf(token.COMMA, ",")
714 current_line.append(new_comma)
718 @dont_increase_indentation
719 def standalone_comment_split(
720 line: Line, features: Collection[Feature] = ()
722 """Split standalone comments from the rest of the line."""
723 if not line.contains_standalone_comments(0):
724 raise CannotSplit("Line does not have any standalone comments")
727 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
730 def append_to_line(leaf: Leaf) -> Iterator[Line]:
731 """Append `leaf` to current line or to new line if appending impossible."""
732 nonlocal current_line
734 current_line.append_safe(leaf, preformatted=True)
739 line.mode, depth=line.depth, inside_brackets=line.inside_brackets
741 current_line.append(leaf)
743 for leaf in line.leaves:
744 yield from append_to_line(leaf)
746 for comment_after in line.comments_after(leaf):
747 yield from append_to_line(comment_after)
753 def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
754 """Leave existing extra newlines if not `inside_brackets`. Remove everything
757 Note: don't use backslashes for formatting or you'll lose your voting rights.
759 if not inside_brackets:
760 spl = leaf.prefix.split("#")
761 if "\\" not in spl[0]:
762 nl_count = spl[-1].count("\n")
765 leaf.prefix = "\n" * nl_count
771 def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None:
772 """Make existing optional parentheses invisible or create new ones.
774 `parens_after` is a set of string leaf values immediately after which parens
777 Standardizes on visible parentheses for single-element tuples, and keeps
778 existing visible parentheses for other tuples and generator expressions.
780 for pc in list_comments(node.prefix, is_endmarker=False):
781 if pc.value in FMT_OFF:
782 # This `node` has a prefix with `# fmt: off`, don't mess with parens.
785 for index, child in enumerate(list(node.children)):
786 # Fixes a bug where invisible parens are not properly stripped from
787 # assignment statements that contain type annotations.
788 if isinstance(child, Node) and child.type == syms.annassign:
789 normalize_invisible_parens(child, parens_after=parens_after)
791 # Add parentheses around long tuple unpacking in assignments.
794 and isinstance(child, Node)
795 and child.type == syms.testlist_star_expr
800 if child.type == syms.atom:
801 if maybe_make_parens_invisible_in_atom(child, parent=node):
802 wrap_in_parentheses(node, child, visible=False)
803 elif is_one_tuple(child):
804 wrap_in_parentheses(node, child, visible=True)
805 elif node.type == syms.import_from:
806 # "import from" nodes store parentheses directly as part of
808 if child.type == token.LPAR:
809 # make parentheses invisible
810 child.value = "" # type: ignore
811 node.children[-1].value = "" # type: ignore
812 elif child.type != token.STAR:
813 # insert invisible parentheses
814 node.insert_child(index, Leaf(token.LPAR, ""))
815 node.append_child(Leaf(token.RPAR, ""))
818 elif not (isinstance(child, Leaf) and is_multiline_string(child)):
819 wrap_in_parentheses(node, child, visible=False)
821 check_lpar = isinstance(child, Leaf) and child.value in parens_after
824 def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool:
825 """If it's safe, make the parens in the atom `node` invisible, recursively.
826 Additionally, remove repeated, adjacent invisible parens from the atom `node`
827 as they are redundant.
829 Returns whether the node should itself be wrapped in invisible parentheses.
834 node.type != syms.atom
835 or is_empty_tuple(node)
836 or is_one_tuple(node)
837 or (is_yield(node) and parent.type != syms.expr_stmt)
838 or max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
842 if is_walrus_assignment(node):
848 # these ones aren't useful to end users, but they do please fuzzers
854 first = node.children[0]
855 last = node.children[-1]
856 if first.type == token.LPAR and last.type == token.RPAR:
857 middle = node.children[1]
858 # make parentheses invisible
859 first.value = "" # type: ignore
860 last.value = "" # type: ignore
861 maybe_make_parens_invisible_in_atom(middle, parent=parent)
863 if is_atom_with_invisible_parens(middle):
864 # Strip the invisible parens from `middle` by replacing
865 # it with the child in-between the invisible parens
866 middle.replace(middle.children[1])
873 def should_split_line(line: Line, opening_bracket: Leaf) -> bool:
874 """Should `line` be immediately split with `delimiter_split()` after RHS?"""
876 if not (opening_bracket.parent and opening_bracket.value in "[{("):
879 # We're essentially checking if the body is delimited by commas and there's more
880 # than one of them (we're excluding the trailing comma and if the delimiter priority
881 # is still commas, that means there's more).
883 trailing_comma = False
885 last_leaf = line.leaves[-1]
886 if last_leaf.type == token.COMMA:
887 trailing_comma = True
888 exclude.add(id(last_leaf))
889 max_priority = line.bracket_tracker.max_delimiter_priority(exclude=exclude)
890 except (IndexError, ValueError):
893 return max_priority == COMMA_PRIORITY and (
894 (line.mode.magic_trailing_comma and trailing_comma)
895 # always explode imports
896 or opening_bracket.parent.type in {syms.atom, syms.import_from}
900 def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[LeafID]]:
901 """Generate sets of closing bracket IDs that should be omitted in a RHS.
903 Brackets can be omitted if the entire trailer up to and including
904 a preceding closing bracket fits in one line.
906 Yielded sets are cumulative (contain results of previous yields, too). First
907 set is empty, unless the line should explode, in which case bracket pairs until
908 the one that needs to explode are omitted.
911 omit: Set[LeafID] = set()
912 if not line.magic_trailing_comma:
915 length = 4 * line.depth
916 opening_bracket: Optional[Leaf] = None
917 closing_bracket: Optional[Leaf] = None
918 inner_brackets: Set[LeafID] = set()
919 for index, leaf, leaf_length in line.enumerate_with_length(reversed=True):
920 length += leaf_length
921 if length > line_length:
924 has_inline_comment = leaf_length > len(leaf.value) + len(leaf.prefix)
925 if leaf.type == STANDALONE_COMMENT or has_inline_comment:
929 if leaf is opening_bracket:
930 opening_bracket = None
931 elif leaf.type in CLOSING_BRACKETS:
932 prev = line.leaves[index - 1] if index > 0 else None
935 and prev.type == token.COMMA
936 and not is_one_tuple_between(
937 leaf.opening_bracket, leaf, line.leaves
940 # Never omit bracket pairs with trailing commas.
941 # We need to explode on those.
944 inner_brackets.add(id(leaf))
945 elif leaf.type in CLOSING_BRACKETS:
946 prev = line.leaves[index - 1] if index > 0 else None
947 if prev and prev.type in OPENING_BRACKETS:
948 # Empty brackets would fail a split so treat them as "inner"
949 # brackets (e.g. only add them to the `omit` set if another
950 # pair of brackets was good enough.
951 inner_brackets.add(id(leaf))
955 omit.add(id(closing_bracket))
956 omit.update(inner_brackets)
957 inner_brackets.clear()
962 and prev.type == token.COMMA
963 and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves)
965 # Never omit bracket pairs with trailing commas.
966 # We need to explode on those.
970 opening_bracket = leaf.opening_bracket
971 closing_bracket = leaf
976 transform: Transformer,
978 features: Collection[Feature],
983 line_str = line_to_string(line)
984 result: List[Line] = []
985 for transformed_line in transform(line, features):
986 if str(transformed_line).strip("\n") == line_str:
987 raise CannotTransform("Line transformer returned an unchanged result")
989 result.extend(transform_line(transformed_line, mode=mode, features=features))
992 transform.__class__.__name__ != "rhs"
993 or not line.bracket_tracker.invisible
994 or any(bracket.value for bracket in line.bracket_tracker.invisible)
995 or line.contains_multiline_strings()
996 or result[0].contains_uncollapsable_type_comments()
997 or result[0].contains_unsplittable_type_ignore()
998 or is_line_short_enough(result[0], line_length=mode.line_length)
999 # If any leaves have no parents (which _can_ occur since
1000 # `transform(line)` potentially destroys the line's underlying node
1001 # structure), then we can't proceed. Doing so would cause the below
1002 # call to `append_leaves()` to fail.
1003 or any(leaf.parent is None for leaf in line.leaves)
1007 line_copy = line.clone()
1008 append_leaves(line_copy, line, line.leaves)
1009 features_fop = set(features) | {Feature.FORCE_OPTIONAL_PARENTHESES}
1010 second_opinion = run_transformer(
1011 line_copy, transform, mode, features_fop, line_str=line_str
1014 is_line_short_enough(ln, line_length=mode.line_length) for ln in second_opinion
1016 result = second_opinion