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, cast
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, is_arith_like, ensure_visible
11 from black.nodes import (
15 is_one_sequence_between,
17 from black.nodes import is_name_token, is_lpar_token, is_rpar_token
18 from black.nodes import is_walrus_assignment, is_yield, is_vararg, is_multiline_string
19 from black.nodes import is_stub_suite, is_stub_body, is_atom_with_invisible_parens
20 from black.nodes import wrap_in_parentheses
21 from black.brackets import max_delimiter_priority_in_atom
22 from black.brackets import DOT_PRIORITY, COMMA_PRIORITY
23 from black.lines import Line, line_to_string, is_line_short_enough
24 from black.lines import can_omit_invisible_parens, can_be_split, append_leaves
25 from black.comments import generate_comments, list_comments, FMT_OFF
26 from black.numerics import normalize_numeric_literal
27 from black.strings import get_string_prefix, fix_docstring
28 from black.strings import normalize_string_prefix, normalize_string_quotes
29 from black.trans import Transformer, CannotTransform, StringMerger, StringSplitter
30 from black.trans import StringParenWrapper, StringParenStripper, hug_power_op
31 from black.mode import Mode, Feature, Preview
33 from blib2to3.pytree import Node, Leaf
34 from blib2to3.pgen2 import token
39 LN = Union[Leaf, Node]
42 class CannotSplit(CannotTransform):
43 """A readable split that fits the allotted line length is impossible."""
46 # This isn't a dataclass because @dataclass + Generic breaks mypyc.
47 # See also https://github.com/mypyc/mypyc/issues/827.
48 class LineGenerator(Visitor[Line]):
49 """Generates reformatted Line objects. Empty lines are not emitted.
51 Note: destroys the tree it's visiting by mutating prefixes of its leaves
52 in ways that will no longer stringify to valid Python code on the tree.
55 def __init__(self, mode: Mode) -> None:
57 self.current_line: Line
60 def line(self, indent: int = 0) -> Iterator[Line]:
63 If the line is empty, only emit if it makes sense.
64 If the line is too long, split it first and then generate.
66 If any lines were generated, set up a new current_line.
68 if not self.current_line:
69 self.current_line.depth += indent
70 return # Line is empty, don't emit. Creating a new one unnecessary.
72 complete_line = self.current_line
73 self.current_line = Line(mode=self.mode, depth=complete_line.depth + indent)
76 def visit_default(self, node: LN) -> Iterator[Line]:
77 """Default `visit_*()` implementation. Recurses to children of `node`."""
78 if isinstance(node, Leaf):
79 any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
80 for comment in generate_comments(node, preview=self.mode.preview):
82 # any comment within brackets is subject to splitting
83 self.current_line.append(comment)
84 elif comment.type == token.COMMENT:
85 # regular trailing comment
86 self.current_line.append(comment)
87 yield from self.line()
90 # regular standalone comment
91 yield from self.line()
93 self.current_line.append(comment)
94 yield from self.line()
96 normalize_prefix(node, inside_brackets=any_open_brackets)
97 if self.mode.string_normalization and node.type == token.STRING:
98 node.value = normalize_string_prefix(node.value)
99 node.value = normalize_string_quotes(node.value)
100 if node.type == token.NUMBER:
101 normalize_numeric_literal(node)
102 if node.type not in WHITESPACE:
103 self.current_line.append(node)
104 yield from super().visit_default(node)
106 def visit_INDENT(self, node: Leaf) -> Iterator[Line]:
107 """Increase indentation level, maybe yield a line."""
108 # In blib2to3 INDENT never holds comments.
109 yield from self.line(+1)
110 yield from self.visit_default(node)
112 def visit_DEDENT(self, node: Leaf) -> Iterator[Line]:
113 """Decrease indentation level, maybe yield a line."""
114 # The current line might still wait for trailing comments. At DEDENT time
115 # there won't be any (they would be prefixes on the preceding NEWLINE).
116 # Emit the line then.
117 yield from self.line()
119 # While DEDENT has no value, its prefix may contain standalone comments
120 # that belong to the current indentation level. Get 'em.
121 yield from self.visit_default(node)
123 # Finally, emit the dedent.
124 yield from self.line(-1)
127 self, node: Node, keywords: Set[str], parens: Set[str]
129 """Visit a statement.
131 This implementation is shared for `if`, `while`, `for`, `try`, `except`,
132 `def`, `with`, `class`, `assert`, and assignments.
134 The relevant Python language `keywords` for a given statement will be
135 NAME leaves within it. This methods puts those on a separate line.
137 `parens` holds a set of string leaf values immediately after which
138 invisible parens should be put.
140 normalize_invisible_parens(node, parens_after=parens, preview=self.mode.preview)
141 for child in node.children:
142 if is_name_token(child) and child.value in keywords:
143 yield from self.line()
145 yield from self.visit(child)
147 def visit_funcdef(self, node: Node) -> Iterator[Line]:
148 """Visit function definition."""
149 if Preview.annotation_parens not in self.mode:
150 yield from self.visit_stmt(node, keywords={"def"}, parens=set())
152 yield from self.line()
154 # Remove redundant brackets around return type annotation.
155 is_return_annotation = False
156 for child in node.children:
157 if child.type == token.RARROW:
158 is_return_annotation = True
159 elif is_return_annotation:
160 if child.type == syms.atom and child.children[0].type == token.LPAR:
161 if maybe_make_parens_invisible_in_atom(
164 remove_brackets_around_comma=False,
166 wrap_in_parentheses(node, child, visible=False)
168 wrap_in_parentheses(node, child, visible=False)
169 is_return_annotation = False
171 for child in node.children:
172 yield from self.visit(child)
174 def visit_match_case(self, node: Node) -> Iterator[Line]:
175 """Visit either a match or case statement."""
176 normalize_invisible_parens(node, parens_after=set(), preview=self.mode.preview)
178 yield from self.line()
179 for child in node.children:
180 yield from self.visit(child)
182 def visit_suite(self, node: Node) -> Iterator[Line]:
184 if self.mode.is_pyi and is_stub_suite(node):
185 yield from self.visit(node.children[2])
187 yield from self.visit_default(node)
189 def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
190 """Visit a statement without nested statements."""
191 prev_type: Optional[int] = None
192 for child in node.children:
193 if (prev_type is None or prev_type == token.SEMI) and is_arith_like(child):
194 wrap_in_parentheses(node, child, visible=False)
195 prev_type = child.type
197 is_suite_like = node.parent and node.parent.type in STATEMENT
199 if self.mode.is_pyi and is_stub_body(node):
200 yield from self.visit_default(node)
202 yield from self.line(+1)
203 yield from self.visit_default(node)
204 yield from self.line(-1)
210 or not is_stub_suite(node.parent)
212 yield from self.line()
213 yield from self.visit_default(node)
215 def visit_async_stmt(self, node: Node) -> Iterator[Line]:
216 """Visit `async def`, `async for`, `async with`."""
217 yield from self.line()
219 children = iter(node.children)
220 for child in children:
221 yield from self.visit(child)
223 if child.type == token.ASYNC or child.type == STANDALONE_COMMENT:
224 # STANDALONE_COMMENT happens when `# fmt: skip` is applied on the async
228 internal_stmt = next(children)
229 for child in internal_stmt.children:
230 yield from self.visit(child)
232 def visit_decorators(self, node: Node) -> Iterator[Line]:
233 """Visit decorators."""
234 for child in node.children:
235 yield from self.line()
236 yield from self.visit(child)
238 def visit_power(self, node: Node) -> Iterator[Line]:
239 for idx, leaf in enumerate(node.children[:-1]):
240 next_leaf = node.children[idx + 1]
242 if not isinstance(leaf, Leaf):
245 value = leaf.value.lower()
247 leaf.type == token.NUMBER
248 and next_leaf.type == syms.trailer
249 # Ensure that we are in an attribute trailer
250 and next_leaf.children[0].type == token.DOT
251 # It shouldn't wrap hexadecimal, binary and octal literals
252 and not value.startswith(("0x", "0b", "0o"))
253 # It shouldn't wrap complex literals
256 wrap_in_parentheses(node, leaf)
258 if Preview.remove_redundant_parens in self.mode:
259 remove_await_parens(node)
261 yield from self.visit_default(node)
263 def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]:
264 """Remove a semicolon and put the other statement on a separate line."""
265 yield from self.line()
267 def visit_ENDMARKER(self, leaf: Leaf) -> Iterator[Line]:
268 """End of file. Process outstanding comments and end with a newline."""
269 yield from self.visit_default(leaf)
270 yield from self.line()
272 def visit_STANDALONE_COMMENT(self, leaf: Leaf) -> Iterator[Line]:
273 if not self.current_line.bracket_tracker.any_open_brackets():
274 yield from self.line()
275 yield from self.visit_default(leaf)
277 def visit_factor(self, node: Node) -> Iterator[Line]:
278 """Force parentheses between a unary op and a binary power:
282 _operator, operand = node.children
284 operand.type == syms.power
285 and len(operand.children) == 3
286 and operand.children[1].type == token.DOUBLESTAR
288 lpar = Leaf(token.LPAR, "(")
289 rpar = Leaf(token.RPAR, ")")
290 index = operand.remove() or 0
291 node.insert_child(index, Node(syms.atom, [lpar, operand, rpar]))
292 yield from self.visit_default(node)
294 def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
295 if is_docstring(leaf) and "\\\n" not in leaf.value:
296 # We're ignoring docstrings with backslash newline escapes because changing
297 # indentation of those changes the AST representation of the code.
298 if Preview.normalize_docstring_quotes_and_prefixes_properly in self.mode:
299 # There was a bug where --skip-string-normalization wouldn't stop us
300 # from normalizing docstring prefixes. To maintain stability, we can
301 # only address this buggy behaviour while the preview style is enabled.
302 if self.mode.string_normalization:
303 docstring = normalize_string_prefix(leaf.value)
304 # visit_default() does handle string normalization for us, but
305 # since this method acts differently depending on quote style (ex.
306 # see padding logic below), there's a possibility for unstable
307 # formatting as visit_default() is called *after*. To avoid a
308 # situation where this function formats a docstring differently on
309 # the second pass, normalize it early.
310 docstring = normalize_string_quotes(docstring)
312 docstring = leaf.value
314 # ... otherwise, we'll keep the buggy behaviour >.<
315 docstring = normalize_string_prefix(leaf.value)
316 prefix = get_string_prefix(docstring)
317 docstring = docstring[len(prefix) :] # Remove the prefix
318 quote_char = docstring[0]
319 # A natural way to remove the outer quotes is to do:
320 # docstring = docstring.strip(quote_char)
321 # but that breaks on """""x""" (which is '""x').
322 # So we actually need to remove the first character and the next two
323 # characters but only if they are the same as the first.
324 quote_len = 1 if docstring[1] != quote_char else 3
325 docstring = docstring[quote_len:-quote_len]
326 docstring_started_empty = not docstring
327 indent = " " * 4 * self.current_line.depth
329 if is_multiline_string(leaf):
330 docstring = fix_docstring(docstring, indent)
332 docstring = docstring.strip()
335 # Add some padding if the docstring starts / ends with a quote mark.
336 if docstring[0] == quote_char:
337 docstring = " " + docstring
338 if docstring[-1] == quote_char:
340 if docstring[-1] == "\\":
341 backslash_count = len(docstring) - len(docstring.rstrip("\\"))
342 if backslash_count % 2:
343 # Odd number of tailing backslashes, add some padding to
344 # avoid escaping the closing string quote.
346 elif not docstring_started_empty:
349 # We could enforce triple quotes at this point.
350 quote = quote_char * quote_len
352 # It's invalid to put closing single-character quotes on a new line.
353 if Preview.long_docstring_quotes_on_newline in self.mode and quote_len == 3:
354 # We need to find the length of the last line of the docstring
355 # to find if we can add the closing quotes to the line without
356 # exceeding the maximum line length.
357 # If docstring is one line, then we need to add the length
358 # of the indent, prefix, and starting quotes. Ending quotes are
360 lines = docstring.splitlines()
361 last_line_length = len(lines[-1]) if docstring else 0
364 last_line_length += len(indent) + len(prefix) + quote_len
366 # If adding closing quotes would cause the last line to exceed
367 # the maximum line length then put a line break before the
369 if last_line_length + quote_len > self.mode.line_length:
370 leaf.value = prefix + quote + docstring + "\n" + indent + quote
372 leaf.value = prefix + quote + docstring + quote
374 leaf.value = prefix + quote + docstring + quote
376 yield from self.visit_default(leaf)
378 def __post_init__(self) -> None:
379 """You are in a twisty little maze of passages."""
380 self.current_line = Line(mode=self.mode)
384 self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
385 self.visit_if_stmt = partial(
386 v, keywords={"if", "else", "elif"}, parens={"if", "elif"}
388 self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"})
389 self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"})
390 self.visit_try_stmt = partial(
391 v, keywords={"try", "except", "else", "finally"}, parens=Ø
393 if self.mode.preview:
394 self.visit_except_clause = partial(
395 v, keywords={"except"}, parens={"except"}
397 self.visit_with_stmt = partial(v, keywords={"with"}, parens={"with"})
399 self.visit_except_clause = partial(v, keywords={"except"}, parens=Ø)
400 self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø)
401 self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
402 self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS)
403 self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
404 self.visit_import_from = partial(v, keywords=Ø, parens={"import"})
405 self.visit_del_stmt = partial(v, keywords=Ø, parens={"del"})
406 self.visit_async_funcdef = self.visit_async_stmt
407 self.visit_decorated = self.visit_decorators
410 self.visit_match_stmt = self.visit_match_case
411 self.visit_case_block = self.visit_match_case
415 line: Line, mode: Mode, features: Collection[Feature] = ()
417 """Transform a `line`, potentially splitting it into many lines.
419 They should fit in the allotted `line_length` but might not be able to.
421 `features` are syntactical features that may be used in the output.
427 line_str = line_to_string(line)
429 ll = mode.line_length
430 sn = mode.string_normalization
431 string_merge = StringMerger(ll, sn)
432 string_paren_strip = StringParenStripper(ll, sn)
433 string_split = StringSplitter(ll, sn)
434 string_paren_wrap = StringParenWrapper(ll, sn)
436 transformers: List[Transformer]
438 not line.contains_uncollapsable_type_comments()
439 and not line.should_split_rhs
440 and not line.magic_trailing_comma
442 is_line_short_enough(line, line_length=mode.line_length, line_str=line_str)
443 or line.contains_unsplittable_type_ignore()
445 and not (line.inside_brackets and line.contains_standalone_comments())
447 # Only apply basic string preprocessing, since lines shouldn't be split here.
448 if Preview.string_processing in mode:
449 transformers = [string_merge, string_paren_strip]
453 transformers = [left_hand_split]
457 self: object, line: Line, features: Collection[Feature]
459 """Wraps calls to `right_hand_split`.
461 The calls increasingly `omit` right-hand trailers (bracket pairs with
462 content), meaning the trailers get glued together to split on another
463 bracket pair instead.
465 for omit in generate_trailers_to_omit(line, mode.line_length):
467 right_hand_split(line, mode.line_length, features, omit=omit)
469 # Note: this check is only able to figure out if the first line of the
470 # *current* transformation fits in the line length. This is true only
471 # for simple cases. All others require running more transforms via
472 # `transform_line()`. This check doesn't know if those would succeed.
473 if is_line_short_enough(lines[0], line_length=mode.line_length):
477 # All splits failed, best effort split with no omits.
478 # This mostly happens to multiline strings that are by definition
479 # reported as not fitting a single line, as well as lines that contain
480 # trailing commas (those have to be exploded).
481 yield from right_hand_split(
482 line, line_length=mode.line_length, features=features
485 # HACK: nested functions (like _rhs) compiled by mypyc don't retain their
486 # __name__ attribute which is needed in `run_transformer` further down.
487 # Unfortunately a nested class breaks mypyc too. So a class must be created
488 # via type ... https://github.com/mypyc/mypyc/issues/884
489 rhs = type("rhs", (), {"__call__": _rhs})()
491 if Preview.string_processing in mode:
492 if line.inside_brackets:
498 standalone_comment_split,
511 if line.inside_brackets:
512 transformers = [delimiter_split, standalone_comment_split, rhs]
515 # It's always safe to attempt hugging of power operations and pretty much every line
517 transformers.append(hug_power_op)
519 for transform in transformers:
520 # We are accumulating lines in `result` because we might want to abort
521 # mission and return the original line in the end, or attempt a different
524 result = run_transformer(line, transform, mode, features, line_str=line_str)
525 except CannotTransform:
535 def left_hand_split(line: Line, _features: Collection[Feature] = ()) -> Iterator[Line]:
536 """Split line into many lines, starting with the first matching bracket pair.
538 Note: this usually looks weird, only use this for function definitions.
539 Prefer RHS otherwise. This is why this function is not symmetrical with
540 :func:`right_hand_split` which also handles optional parentheses.
542 tail_leaves: List[Leaf] = []
543 body_leaves: List[Leaf] = []
544 head_leaves: List[Leaf] = []
545 current_leaves = head_leaves
546 matching_bracket: Optional[Leaf] = None
547 for leaf in line.leaves:
549 current_leaves is body_leaves
550 and leaf.type in CLOSING_BRACKETS
551 and leaf.opening_bracket is matching_bracket
552 and isinstance(matching_bracket, Leaf)
555 ensure_visible(matching_bracket)
556 current_leaves = tail_leaves if body_leaves else head_leaves
557 current_leaves.append(leaf)
558 if current_leaves is head_leaves:
559 if leaf.type in OPENING_BRACKETS:
560 matching_bracket = leaf
561 current_leaves = body_leaves
562 if not matching_bracket:
563 raise CannotSplit("No brackets found")
565 head = bracket_split_build_line(head_leaves, line, matching_bracket)
566 body = bracket_split_build_line(body_leaves, line, matching_bracket, is_body=True)
567 tail = bracket_split_build_line(tail_leaves, line, matching_bracket)
568 bracket_split_succeeded_or_raise(head, body, tail)
569 for result in (head, body, tail):
574 def right_hand_split(
577 features: Collection[Feature] = (),
578 omit: Collection[LeafID] = (),
580 """Split line into many lines, starting with the last matching bracket pair.
582 If the split was by optional parentheses, attempt splitting without them, too.
583 `omit` is a collection of closing bracket IDs that shouldn't be considered for
586 Note: running this function modifies `bracket_depth` on the leaves of `line`.
588 tail_leaves: List[Leaf] = []
589 body_leaves: List[Leaf] = []
590 head_leaves: List[Leaf] = []
591 current_leaves = tail_leaves
592 opening_bracket: Optional[Leaf] = None
593 closing_bracket: Optional[Leaf] = None
594 for leaf in reversed(line.leaves):
595 if current_leaves is body_leaves:
596 if leaf is opening_bracket:
597 current_leaves = head_leaves if body_leaves else tail_leaves
598 current_leaves.append(leaf)
599 if current_leaves is tail_leaves:
600 if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit:
601 opening_bracket = leaf.opening_bracket
602 closing_bracket = leaf
603 current_leaves = body_leaves
604 if not (opening_bracket and closing_bracket and head_leaves):
605 # If there is no opening or closing_bracket that means the split failed and
606 # all content is in the tail. Otherwise, if `head_leaves` are empty, it means
607 # the matching `opening_bracket` wasn't available on `line` anymore.
608 raise CannotSplit("No brackets found")
610 tail_leaves.reverse()
611 body_leaves.reverse()
612 head_leaves.reverse()
613 head = bracket_split_build_line(head_leaves, line, opening_bracket)
614 body = bracket_split_build_line(body_leaves, line, opening_bracket, is_body=True)
615 tail = bracket_split_build_line(tail_leaves, line, opening_bracket)
616 bracket_split_succeeded_or_raise(head, body, tail)
618 Feature.FORCE_OPTIONAL_PARENTHESES not in features
619 # the opening bracket is an optional paren
620 and opening_bracket.type == token.LPAR
621 and not opening_bracket.value
622 # the closing bracket is an optional paren
623 and closing_bracket.type == token.RPAR
624 and not closing_bracket.value
625 # it's not an import (optional parens are the only thing we can split on
626 # in this case; attempting a split without them is a waste of time)
627 and not line.is_import
628 # there are no standalone comments in the body
629 and not body.contains_standalone_comments(0)
630 # and we can actually remove the parens
631 and can_omit_invisible_parens(body, line_length)
633 omit = {id(closing_bracket), *omit}
635 yield from right_hand_split(line, line_length, features=features, omit=omit)
638 except CannotSplit as e:
641 or is_line_short_enough(body, line_length=line_length)
644 "Splitting failed, body is still too long and can't be split."
647 elif head.contains_multiline_strings() or tail.contains_multiline_strings():
649 "The current optional pair of parentheses is bound to fail to"
650 " satisfy the splitting algorithm because the head or the tail"
651 " contains multiline strings which by definition never fit one"
655 ensure_visible(opening_bracket)
656 ensure_visible(closing_bracket)
657 for result in (head, body, tail):
662 def bracket_split_succeeded_or_raise(head: Line, body: Line, tail: Line) -> None:
663 """Raise :exc:`CannotSplit` if the last left- or right-hand split failed.
665 Do nothing otherwise.
667 A left- or right-hand split is based on a pair of brackets. Content before
668 (and including) the opening bracket is left on one line, content inside the
669 brackets is put on a separate line, and finally content starting with and
670 following the closing bracket is put on a separate line.
672 Those are called `head`, `body`, and `tail`, respectively. If the split
673 produced the same line (all content in `head`) or ended up with an empty `body`
674 and the `tail` is just the closing bracket, then it's considered failed.
676 tail_len = len(str(tail).strip())
679 raise CannotSplit("Splitting brackets produced the same line")
683 f"Splitting brackets on an empty body to save {tail_len} characters is"
688 def bracket_split_build_line(
689 leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False
691 """Return a new line with given `leaves` and respective comments from `original`.
693 If `is_body` is True, the result line is one-indented inside brackets and as such
694 has its first leaf's prefix normalized and a trailing comma added when expected.
696 result = Line(mode=original.mode, depth=original.depth)
698 result.inside_brackets = True
701 # Since body is a new indent level, remove spurious leading whitespace.
702 normalize_prefix(leaves[0], inside_brackets=True)
703 # Ensure a trailing comma for imports and standalone function arguments, but
704 # be careful not to add one after any comments or within type annotations.
707 and opening_bracket.value == "("
708 and not any(leaf.type == token.COMMA for leaf in leaves)
709 # In particular, don't add one within a parenthesized return annotation.
710 # Unfortunately the indicator we're in a return annotation (RARROW) may
711 # be defined directly in the parent node, the parent of the parent ...
712 # and so on depending on how complex the return annotation is.
713 # This isn't perfect and there's some false negatives but they are in
714 # contexts were a comma is actually fine.
716 node.prev_sibling.type == RARROW
719 getattr(leaves[0].parent, "parent", None),
721 if isinstance(node, Node) and isinstance(node.prev_sibling, Leaf)
725 if original.is_import or no_commas:
726 for i in range(len(leaves) - 1, -1, -1):
727 if leaves[i].type == STANDALONE_COMMENT:
730 if leaves[i].type != token.COMMA:
731 new_comma = Leaf(token.COMMA, ",")
732 leaves.insert(i + 1, new_comma)
737 result.append(leaf, preformatted=True)
738 for comment_after in original.comments_after(leaf):
739 result.append(comment_after, preformatted=True)
740 if is_body and should_split_line(result, opening_bracket):
741 result.should_split_rhs = True
745 def dont_increase_indentation(split_func: Transformer) -> Transformer:
746 """Normalize prefix of the first leaf in every line returned by `split_func`.
748 This is a decorator over relevant split functions.
752 def split_wrapper(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]:
753 for split_line in split_func(line, features):
754 normalize_prefix(split_line.leaves[0], inside_brackets=True)
760 @dont_increase_indentation
761 def delimiter_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]:
762 """Split according to delimiters of the highest priority.
764 If the appropriate Features are given, the split will add trailing commas
765 also in function signatures and calls that contain `*` and `**`.
768 last_leaf = line.leaves[-1]
770 raise CannotSplit("Line empty") from None
772 bt = line.bracket_tracker
774 delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)})
776 raise CannotSplit("No delimiters found") from None
778 if delimiter_priority == DOT_PRIORITY:
779 if bt.delimiter_count_with_priority(delimiter_priority) == 1:
780 raise CannotSplit("Splitting a single attribute from its owner looks wrong")
783 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
785 lowest_depth = sys.maxsize
786 trailing_comma_safe = True
788 def append_to_line(leaf: Leaf) -> Iterator[Line]:
789 """Append `leaf` to current line or to new line if appending impossible."""
790 nonlocal current_line
792 current_line.append_safe(leaf, preformatted=True)
797 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
799 current_line.append(leaf)
801 for leaf in line.leaves:
802 yield from append_to_line(leaf)
804 for comment_after in line.comments_after(leaf):
805 yield from append_to_line(comment_after)
807 lowest_depth = min(lowest_depth, leaf.bracket_depth)
808 if leaf.bracket_depth == lowest_depth:
809 if is_vararg(leaf, within={syms.typedargslist}):
810 trailing_comma_safe = (
811 trailing_comma_safe and Feature.TRAILING_COMMA_IN_DEF in features
813 elif is_vararg(leaf, within={syms.arglist, syms.argument}):
814 trailing_comma_safe = (
815 trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features
818 leaf_priority = bt.delimiters.get(id(leaf))
819 if leaf_priority == delimiter_priority:
823 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
828 and delimiter_priority == COMMA_PRIORITY
829 and current_line.leaves[-1].type != token.COMMA
830 and current_line.leaves[-1].type != STANDALONE_COMMENT
832 new_comma = Leaf(token.COMMA, ",")
833 current_line.append(new_comma)
837 @dont_increase_indentation
838 def standalone_comment_split(
839 line: Line, features: Collection[Feature] = ()
841 """Split standalone comments from the rest of the line."""
842 if not line.contains_standalone_comments(0):
843 raise CannotSplit("Line does not have any standalone comments")
846 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
849 def append_to_line(leaf: Leaf) -> Iterator[Line]:
850 """Append `leaf` to current line or to new line if appending impossible."""
851 nonlocal current_line
853 current_line.append_safe(leaf, preformatted=True)
858 line.mode, depth=line.depth, inside_brackets=line.inside_brackets
860 current_line.append(leaf)
862 for leaf in line.leaves:
863 yield from append_to_line(leaf)
865 for comment_after in line.comments_after(leaf):
866 yield from append_to_line(comment_after)
872 def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
873 """Leave existing extra newlines if not `inside_brackets`. Remove everything
876 Note: don't use backslashes for formatting or you'll lose your voting rights.
878 if not inside_brackets:
879 spl = leaf.prefix.split("#")
880 if "\\" not in spl[0]:
881 nl_count = spl[-1].count("\n")
884 leaf.prefix = "\n" * nl_count
890 def normalize_invisible_parens(
891 node: Node, parens_after: Set[str], *, preview: bool
893 """Make existing optional parentheses invisible or create new ones.
895 `parens_after` is a set of string leaf values immediately after which parens
898 Standardizes on visible parentheses for single-element tuples, and keeps
899 existing visible parentheses for other tuples and generator expressions.
901 for pc in list_comments(node.prefix, is_endmarker=False, preview=preview):
902 if pc.value in FMT_OFF:
903 # This `node` has a prefix with `# fmt: off`, don't mess with parens.
906 for index, child in enumerate(list(node.children)):
907 # Fixes a bug where invisible parens are not properly stripped from
908 # assignment statements that contain type annotations.
909 if isinstance(child, Node) and child.type == syms.annassign:
910 normalize_invisible_parens(
911 child, parens_after=parens_after, preview=preview
914 # Add parentheses around long tuple unpacking in assignments.
917 and isinstance(child, Node)
918 and child.type == syms.testlist_star_expr
925 and child.type == syms.atom
926 and node.type == syms.for_stmt
927 and isinstance(child.prev_sibling, Leaf)
928 and child.prev_sibling.type == token.NAME
929 and child.prev_sibling.value == "for"
931 if maybe_make_parens_invisible_in_atom(
934 remove_brackets_around_comma=True,
936 wrap_in_parentheses(node, child, visible=False)
937 elif preview and isinstance(child, Node) and node.type == syms.with_stmt:
938 remove_with_parens(child, node)
939 elif child.type == syms.atom:
940 if maybe_make_parens_invisible_in_atom(
944 wrap_in_parentheses(node, child, visible=False)
945 elif is_one_tuple(child):
946 wrap_in_parentheses(node, child, visible=True)
947 elif node.type == syms.import_from:
948 # "import from" nodes store parentheses directly as part of
950 if is_lpar_token(child):
951 assert is_rpar_token(node.children[-1])
952 # make parentheses invisible
954 node.children[-1].value = ""
955 elif child.type != token.STAR:
956 # insert invisible parentheses
957 node.insert_child(index, Leaf(token.LPAR, ""))
958 node.append_child(Leaf(token.RPAR, ""))
962 and child.type == token.STAR
963 and node.type == syms.except_clause
965 # In except* (PEP 654), the star is actually part of
966 # of the keyword. So we need to skip the insertion of
967 # invisible parentheses to work more precisely.
970 elif not (isinstance(child, Leaf) and is_multiline_string(child)):
971 wrap_in_parentheses(node, child, visible=False)
973 comma_check = child.type == token.COMMA if preview else False
975 check_lpar = isinstance(child, Leaf) and (
976 child.value in parens_after or comma_check
980 def remove_await_parens(node: Node) -> None:
981 if node.children[0].type == token.AWAIT and len(node.children) > 1:
983 node.children[1].type == syms.atom
984 and node.children[1].children[0].type == token.LPAR
986 if maybe_make_parens_invisible_in_atom(
989 remove_brackets_around_comma=True,
991 wrap_in_parentheses(node, node.children[1], visible=False)
993 # Since await is an expression we shouldn't remove
994 # brackets in cases where this would change
995 # the AST due to operator precedence.
996 # Therefore we only aim to remove brackets around
997 # power nodes that aren't also await expressions themselves.
998 # https://peps.python.org/pep-0492/#updated-operator-precedence-table
999 # N.B. We've still removed any redundant nested brackets though :)
1000 opening_bracket = cast(Leaf, node.children[1].children[0])
1001 closing_bracket = cast(Leaf, node.children[1].children[-1])
1002 bracket_contents = cast(Node, node.children[1].children[1])
1003 if bracket_contents.type != syms.power:
1004 ensure_visible(opening_bracket)
1005 ensure_visible(closing_bracket)
1007 bracket_contents.type == syms.power
1008 and bracket_contents.children[0].type == token.AWAIT
1010 ensure_visible(opening_bracket)
1011 ensure_visible(closing_bracket)
1012 # If we are in a nested await then recurse down.
1013 remove_await_parens(bracket_contents)
1016 def remove_with_parens(node: Node, parent: Node) -> None:
1017 """Recursively hide optional parens in `with` statements."""
1018 # Removing all unnecessary parentheses in with statements in one pass is a tad
1019 # complex as different variations of bracketed statements result in pretty
1020 # different parse trees:
1022 # with (open("file")) as f: # this is an asexpr_test
1025 # with (open("file") as f): # this is an atom containing an
1028 # with (open("file")) as f, (open("file")) as f: # this is asexpr_test, COMMA,
1031 # with (open("file") as f, open("file") as f): # an atom containing a
1032 # ... # testlist_gexp which then
1033 # # contains multiple asexpr_test(s)
1034 if node.type == syms.atom:
1035 if maybe_make_parens_invisible_in_atom(
1038 remove_brackets_around_comma=True,
1040 wrap_in_parentheses(parent, node, visible=False)
1041 if isinstance(node.children[1], Node):
1042 remove_with_parens(node.children[1], node)
1043 elif node.type == syms.testlist_gexp:
1044 for child in node.children:
1045 if isinstance(child, Node):
1046 remove_with_parens(child, node)
1047 elif node.type == syms.asexpr_test and not any(
1048 leaf.type == token.COLONEQUAL for leaf in node.leaves()
1050 if maybe_make_parens_invisible_in_atom(
1053 remove_brackets_around_comma=True,
1055 wrap_in_parentheses(node, node.children[0], visible=False)
1058 def maybe_make_parens_invisible_in_atom(
1061 remove_brackets_around_comma: bool = False,
1063 """If it's safe, make the parens in the atom `node` invisible, recursively.
1064 Additionally, remove repeated, adjacent invisible parens from the atom `node`
1065 as they are redundant.
1067 Returns whether the node should itself be wrapped in invisible parentheses.
1070 node.type != syms.atom
1071 or is_empty_tuple(node)
1072 or is_one_tuple(node)
1073 or (is_yield(node) and parent.type != syms.expr_stmt)
1075 # This condition tries to prevent removing non-optional brackets
1076 # around a tuple, however, can be a bit overzealous so we provide
1077 # and option to skip this check for `for` and `with` statements.
1078 not remove_brackets_around_comma
1079 and max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
1084 if is_walrus_assignment(node):
1090 # these ones aren't useful to end users, but they do please fuzzers
1096 first = node.children[0]
1097 last = node.children[-1]
1098 if is_lpar_token(first) and is_rpar_token(last):
1099 middle = node.children[1]
1100 # make parentheses invisible
1103 maybe_make_parens_invisible_in_atom(
1106 remove_brackets_around_comma=remove_brackets_around_comma,
1109 if is_atom_with_invisible_parens(middle):
1110 # Strip the invisible parens from `middle` by replacing
1111 # it with the child in-between the invisible parens
1112 middle.replace(middle.children[1])
1119 def should_split_line(line: Line, opening_bracket: Leaf) -> bool:
1120 """Should `line` be immediately split with `delimiter_split()` after RHS?"""
1122 if not (opening_bracket.parent and opening_bracket.value in "[{("):
1125 # We're essentially checking if the body is delimited by commas and there's more
1126 # than one of them (we're excluding the trailing comma and if the delimiter priority
1127 # is still commas, that means there's more).
1129 trailing_comma = False
1131 last_leaf = line.leaves[-1]
1132 if last_leaf.type == token.COMMA:
1133 trailing_comma = True
1134 exclude.add(id(last_leaf))
1135 max_priority = line.bracket_tracker.max_delimiter_priority(exclude=exclude)
1136 except (IndexError, ValueError):
1139 return max_priority == COMMA_PRIORITY and (
1140 (line.mode.magic_trailing_comma and trailing_comma)
1141 # always explode imports
1142 or opening_bracket.parent.type in {syms.atom, syms.import_from}
1146 def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[LeafID]]:
1147 """Generate sets of closing bracket IDs that should be omitted in a RHS.
1149 Brackets can be omitted if the entire trailer up to and including
1150 a preceding closing bracket fits in one line.
1152 Yielded sets are cumulative (contain results of previous yields, too). First
1153 set is empty, unless the line should explode, in which case bracket pairs until
1154 the one that needs to explode are omitted.
1157 omit: Set[LeafID] = set()
1158 if not line.magic_trailing_comma:
1161 length = 4 * line.depth
1162 opening_bracket: Optional[Leaf] = None
1163 closing_bracket: Optional[Leaf] = None
1164 inner_brackets: Set[LeafID] = set()
1165 for index, leaf, leaf_length in line.enumerate_with_length(reversed=True):
1166 length += leaf_length
1167 if length > line_length:
1170 has_inline_comment = leaf_length > len(leaf.value) + len(leaf.prefix)
1171 if leaf.type == STANDALONE_COMMENT or has_inline_comment:
1175 if leaf is opening_bracket:
1176 opening_bracket = None
1177 elif leaf.type in CLOSING_BRACKETS:
1178 prev = line.leaves[index - 1] if index > 0 else None
1181 and prev.type == token.COMMA
1182 and leaf.opening_bracket is not None
1183 and not is_one_sequence_between(
1184 leaf.opening_bracket, leaf, line.leaves
1187 # Never omit bracket pairs with trailing commas.
1188 # We need to explode on those.
1191 inner_brackets.add(id(leaf))
1192 elif leaf.type in CLOSING_BRACKETS:
1193 prev = line.leaves[index - 1] if index > 0 else None
1194 if prev and prev.type in OPENING_BRACKETS:
1195 # Empty brackets would fail a split so treat them as "inner"
1196 # brackets (e.g. only add them to the `omit` set if another
1197 # pair of brackets was good enough.
1198 inner_brackets.add(id(leaf))
1202 omit.add(id(closing_bracket))
1203 omit.update(inner_brackets)
1204 inner_brackets.clear()
1209 and prev.type == token.COMMA
1210 and leaf.opening_bracket is not None
1211 and not is_one_sequence_between(leaf.opening_bracket, leaf, line.leaves)
1213 # Never omit bracket pairs with trailing commas.
1214 # We need to explode on those.
1218 opening_bracket = leaf.opening_bracket
1219 closing_bracket = leaf
1222 def run_transformer(
1224 transform: Transformer,
1226 features: Collection[Feature],
1231 line_str = line_to_string(line)
1232 result: List[Line] = []
1233 for transformed_line in transform(line, features):
1234 if str(transformed_line).strip("\n") == line_str:
1235 raise CannotTransform("Line transformer returned an unchanged result")
1237 result.extend(transform_line(transformed_line, mode=mode, features=features))
1240 transform.__class__.__name__ != "rhs"
1241 or not line.bracket_tracker.invisible
1242 or any(bracket.value for bracket in line.bracket_tracker.invisible)
1243 or line.contains_multiline_strings()
1244 or result[0].contains_uncollapsable_type_comments()
1245 or result[0].contains_unsplittable_type_ignore()
1246 or is_line_short_enough(result[0], line_length=mode.line_length)
1247 # If any leaves have no parents (which _can_ occur since
1248 # `transform(line)` potentially destroys the line's underlying node
1249 # structure), then we can't proceed. Doing so would cause the below
1250 # call to `append_leaves()` to fail.
1251 or any(leaf.parent is None for leaf in line.leaves)
1255 line_copy = line.clone()
1256 append_leaves(line_copy, line, line.leaves)
1257 features_fop = set(features) | {Feature.FORCE_OPTIONAL_PARENTHESES}
1258 second_opinion = run_transformer(
1259 line_copy, transform, mode, features_fop, line_str=line_str
1262 is_line_short_enough(ln, line_length=mode.line_length) for ln in second_opinion
1264 result = second_opinion