]> git.madduck.net Git - etc/vim.git/blob - src/black/linegen.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Add isort to linting toolchain
[etc/vim.git] / src / black / linegen.py
1 """
2 Generating lines of code.
3 """
4 from functools import partial, wraps
5 import sys
6 from typing import Collection, Iterator, List, Optional, Set, Union, cast
7
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 (
12     is_docstring,
13     is_empty_tuple,
14     is_one_tuple,
15     is_one_sequence_between,
16 )
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
32
33 from blib2to3.pytree import Node, Leaf
34 from blib2to3.pgen2 import token
35
36
37 # types
38 LeafID = int
39 LN = Union[Leaf, Node]
40
41
42 class CannotSplit(CannotTransform):
43     """A readable split that fits the allotted line length is impossible."""
44
45
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.
50
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.
53     """
54
55     def __init__(self, mode: Mode) -> None:
56         self.mode = mode
57         self.current_line: Line
58         self.__post_init__()
59
60     def line(self, indent: int = 0) -> Iterator[Line]:
61         """Generate a line.
62
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.
65
66         If any lines were generated, set up a new current_line.
67         """
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.
71
72         complete_line = self.current_line
73         self.current_line = Line(mode=self.mode, depth=complete_line.depth + indent)
74         yield complete_line
75
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):
81                 if any_open_brackets:
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()
88
89                 else:
90                     # regular standalone comment
91                     yield from self.line()
92
93                     self.current_line.append(comment)
94                     yield from self.line()
95
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)
105
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)
111
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()
118
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)
122
123         # Finally, emit the dedent.
124         yield from self.line(-1)
125
126     def visit_stmt(
127         self, node: Node, keywords: Set[str], parens: Set[str]
128     ) -> Iterator[Line]:
129         """Visit a statement.
130
131         This implementation is shared for `if`, `while`, `for`, `try`, `except`,
132         `def`, `with`, `class`, `assert`, and assignments.
133
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.
136
137         `parens` holds a set of string leaf values immediately after which
138         invisible parens should be put.
139         """
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()
144
145             yield from self.visit(child)
146
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())
151         else:
152             yield from self.line()
153
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(
162                             child,
163                             parent=node,
164                             remove_brackets_around_comma=False,
165                         ):
166                             wrap_in_parentheses(node, child, visible=False)
167                     else:
168                         wrap_in_parentheses(node, child, visible=False)
169                     is_return_annotation = False
170
171             for child in node.children:
172                 yield from self.visit(child)
173
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)
177
178         yield from self.line()
179         for child in node.children:
180             yield from self.visit(child)
181
182     def visit_suite(self, node: Node) -> Iterator[Line]:
183         """Visit a suite."""
184         if self.mode.is_pyi and is_stub_suite(node):
185             yield from self.visit(node.children[2])
186         else:
187             yield from self.visit_default(node)
188
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
196
197         is_suite_like = node.parent and node.parent.type in STATEMENT
198         if is_suite_like:
199             if self.mode.is_pyi and is_stub_body(node):
200                 yield from self.visit_default(node)
201             else:
202                 yield from self.line(+1)
203                 yield from self.visit_default(node)
204                 yield from self.line(-1)
205
206         else:
207             if (
208                 not self.mode.is_pyi
209                 or not node.parent
210                 or not is_stub_suite(node.parent)
211             ):
212                 yield from self.line()
213             yield from self.visit_default(node)
214
215     def visit_async_stmt(self, node: Node) -> Iterator[Line]:
216         """Visit `async def`, `async for`, `async with`."""
217         yield from self.line()
218
219         children = iter(node.children)
220         for child in children:
221             yield from self.visit(child)
222
223             if child.type == token.ASYNC or child.type == STANDALONE_COMMENT:
224                 # STANDALONE_COMMENT happens when `# fmt: skip` is applied on the async
225                 # line.
226                 break
227
228         internal_stmt = next(children)
229         for child in internal_stmt.children:
230             yield from self.visit(child)
231
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)
237
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]
241
242             if not isinstance(leaf, Leaf):
243                 continue
244
245             value = leaf.value.lower()
246             if (
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
254                 and "j" not in value
255             ):
256                 wrap_in_parentheses(node, leaf)
257
258         if Preview.remove_redundant_parens in self.mode:
259             remove_await_parens(node)
260
261         yield from self.visit_default(node)
262
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()
266
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()
271
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)
276
277     def visit_factor(self, node: Node) -> Iterator[Line]:
278         """Force parentheses between a unary op and a binary power:
279
280         -2 ** 8 -> -(2 ** 8)
281         """
282         _operator, operand = node.children
283         if (
284             operand.type == syms.power
285             and len(operand.children) == 3
286             and operand.children[1].type == token.DOUBLESTAR
287         ):
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)
293
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)
311                 else:
312                     docstring = leaf.value
313             else:
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
328
329             if is_multiline_string(leaf):
330                 docstring = fix_docstring(docstring, indent)
331             else:
332                 docstring = docstring.strip()
333
334             if docstring:
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:
339                     docstring += " "
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.
345                         docstring += " "
346             elif not docstring_started_empty:
347                 docstring = " "
348
349             # We could enforce triple quotes at this point.
350             quote = quote_char * quote_len
351
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
359                 # handled later.
360                 lines = docstring.splitlines()
361                 last_line_length = len(lines[-1]) if docstring else 0
362
363                 if len(lines) == 1:
364                     last_line_length += len(indent) + len(prefix) + quote_len
365
366                 # If adding closing quotes would cause the last line to exceed
367                 # the maximum line length then put a line break before the
368                 # closing quotes
369                 if last_line_length + quote_len > self.mode.line_length:
370                     leaf.value = prefix + quote + docstring + "\n" + indent + quote
371                 else:
372                     leaf.value = prefix + quote + docstring + quote
373             else:
374                 leaf.value = prefix + quote + docstring + quote
375
376         yield from self.visit_default(leaf)
377
378     def __post_init__(self) -> None:
379         """You are in a twisty little maze of passages."""
380         self.current_line = Line(mode=self.mode)
381
382         v = self.visit_stmt
383         Ø: Set[str] = set()
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"}
387         )
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=Ø
392         )
393         if self.mode.preview:
394             self.visit_except_clause = partial(
395                 v, keywords={"except"}, parens={"except"}
396             )
397             self.visit_with_stmt = partial(v, keywords={"with"}, parens={"with"})
398         else:
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
408
409         # PEP 634
410         self.visit_match_stmt = self.visit_match_case
411         self.visit_case_block = self.visit_match_case
412
413
414 def transform_line(
415     line: Line, mode: Mode, features: Collection[Feature] = ()
416 ) -> Iterator[Line]:
417     """Transform a `line`, potentially splitting it into many lines.
418
419     They should fit in the allotted `line_length` but might not be able to.
420
421     `features` are syntactical features that may be used in the output.
422     """
423     if line.is_comment:
424         yield line
425         return
426
427     line_str = line_to_string(line)
428
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)
435
436     transformers: List[Transformer]
437     if (
438         not line.contains_uncollapsable_type_comments()
439         and not line.should_split_rhs
440         and not line.magic_trailing_comma
441         and (
442             is_line_short_enough(line, line_length=mode.line_length, line_str=line_str)
443             or line.contains_unsplittable_type_ignore()
444         )
445         and not (line.inside_brackets and line.contains_standalone_comments())
446     ):
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]
450         else:
451             transformers = []
452     elif line.is_def:
453         transformers = [left_hand_split]
454     else:
455
456         def _rhs(
457             self: object, line: Line, features: Collection[Feature]
458         ) -> Iterator[Line]:
459             """Wraps calls to `right_hand_split`.
460
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.
464             """
465             for omit in generate_trailers_to_omit(line, mode.line_length):
466                 lines = list(
467                     right_hand_split(line, mode.line_length, features, omit=omit)
468                 )
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):
474                     yield from lines
475                     return
476
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
483             )
484
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})()
490
491         if Preview.string_processing in mode:
492             if line.inside_brackets:
493                 transformers = [
494                     string_merge,
495                     string_paren_strip,
496                     string_split,
497                     delimiter_split,
498                     standalone_comment_split,
499                     string_paren_wrap,
500                     rhs,
501                 ]
502             else:
503                 transformers = [
504                     string_merge,
505                     string_paren_strip,
506                     string_split,
507                     string_paren_wrap,
508                     rhs,
509                 ]
510         else:
511             if line.inside_brackets:
512                 transformers = [delimiter_split, standalone_comment_split, rhs]
513             else:
514                 transformers = [rhs]
515     # It's always safe to attempt hugging of power operations and pretty much every line
516     # could match.
517     transformers.append(hug_power_op)
518
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
522         # split altogether.
523         try:
524             result = run_transformer(line, transform, mode, features, line_str=line_str)
525         except CannotTransform:
526             continue
527         else:
528             yield from result
529             break
530
531     else:
532         yield line
533
534
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.
537
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.
541     """
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:
548         if (
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)
553         ):
554             ensure_visible(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")
564
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):
570         if result:
571             yield result
572
573
574 def right_hand_split(
575     line: Line,
576     line_length: int,
577     features: Collection[Feature] = (),
578     omit: Collection[LeafID] = (),
579 ) -> Iterator[Line]:
580     """Split line into many lines, starting with the last matching bracket pair.
581
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
584     this split.
585
586     Note: running this function modifies `bracket_depth` on the leaves of `line`.
587     """
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")
609
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)
617     if (
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)
632     ):
633         omit = {id(closing_bracket), *omit}
634         try:
635             yield from right_hand_split(line, line_length, features=features, omit=omit)
636             return
637
638         except CannotSplit as e:
639             if not (
640                 can_be_split(body)
641                 or is_line_short_enough(body, line_length=line_length)
642             ):
643                 raise CannotSplit(
644                     "Splitting failed, body is still too long and can't be split."
645                 ) from e
646
647             elif head.contains_multiline_strings() or tail.contains_multiline_strings():
648                 raise CannotSplit(
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"
652                     " line."
653                 ) from e
654
655     ensure_visible(opening_bracket)
656     ensure_visible(closing_bracket)
657     for result in (head, body, tail):
658         if result:
659             yield result
660
661
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.
664
665     Do nothing otherwise.
666
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.
671
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.
675     """
676     tail_len = len(str(tail).strip())
677     if not body:
678         if tail_len == 0:
679             raise CannotSplit("Splitting brackets produced the same line")
680
681         elif tail_len < 3:
682             raise CannotSplit(
683                 f"Splitting brackets on an empty body to save {tail_len} characters is"
684                 " not worth it"
685             )
686
687
688 def bracket_split_build_line(
689     leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False
690 ) -> Line:
691     """Return a new line with given `leaves` and respective comments from `original`.
692
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.
695     """
696     result = Line(mode=original.mode, depth=original.depth)
697     if is_body:
698         result.inside_brackets = True
699         result.depth += 1
700         if leaves:
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.
705             no_commas = (
706                 original.is_def
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.
715                 and not any(
716                     node.prev_sibling.type == RARROW
717                     for node in (
718                         leaves[0].parent,
719                         getattr(leaves[0].parent, "parent", None),
720                     )
721                     if isinstance(node, Node) and isinstance(node.prev_sibling, Leaf)
722                 )
723             )
724
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:
728                         continue
729
730                     if leaves[i].type != token.COMMA:
731                         new_comma = Leaf(token.COMMA, ",")
732                         leaves.insert(i + 1, new_comma)
733                     break
734
735     # Populate the line
736     for leaf in leaves:
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
742     return result
743
744
745 def dont_increase_indentation(split_func: Transformer) -> Transformer:
746     """Normalize prefix of the first leaf in every line returned by `split_func`.
747
748     This is a decorator over relevant split functions.
749     """
750
751     @wraps(split_func)
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)
755             yield split_line
756
757     return split_wrapper
758
759
760 @dont_increase_indentation
761 def delimiter_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]:
762     """Split according to delimiters of the highest priority.
763
764     If the appropriate Features are given, the split will add trailing commas
765     also in function signatures and calls that contain `*` and `**`.
766     """
767     try:
768         last_leaf = line.leaves[-1]
769     except IndexError:
770         raise CannotSplit("Line empty") from None
771
772     bt = line.bracket_tracker
773     try:
774         delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)})
775     except ValueError:
776         raise CannotSplit("No delimiters found") from None
777
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")
781
782     current_line = Line(
783         mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
784     )
785     lowest_depth = sys.maxsize
786     trailing_comma_safe = True
787
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
791         try:
792             current_line.append_safe(leaf, preformatted=True)
793         except ValueError:
794             yield current_line
795
796             current_line = Line(
797                 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
798             )
799             current_line.append(leaf)
800
801     for leaf in line.leaves:
802         yield from append_to_line(leaf)
803
804         for comment_after in line.comments_after(leaf):
805             yield from append_to_line(comment_after)
806
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
812                 )
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
816                 )
817
818         leaf_priority = bt.delimiters.get(id(leaf))
819         if leaf_priority == delimiter_priority:
820             yield current_line
821
822             current_line = Line(
823                 mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
824             )
825     if current_line:
826         if (
827             trailing_comma_safe
828             and delimiter_priority == COMMA_PRIORITY
829             and current_line.leaves[-1].type != token.COMMA
830             and current_line.leaves[-1].type != STANDALONE_COMMENT
831         ):
832             new_comma = Leaf(token.COMMA, ",")
833             current_line.append(new_comma)
834         yield current_line
835
836
837 @dont_increase_indentation
838 def standalone_comment_split(
839     line: Line, features: Collection[Feature] = ()
840 ) -> Iterator[Line]:
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")
844
845     current_line = Line(
846         mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets
847     )
848
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
852         try:
853             current_line.append_safe(leaf, preformatted=True)
854         except ValueError:
855             yield current_line
856
857             current_line = Line(
858                 line.mode, depth=line.depth, inside_brackets=line.inside_brackets
859             )
860             current_line.append(leaf)
861
862     for leaf in line.leaves:
863         yield from append_to_line(leaf)
864
865         for comment_after in line.comments_after(leaf):
866             yield from append_to_line(comment_after)
867
868     if current_line:
869         yield current_line
870
871
872 def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
873     """Leave existing extra newlines if not `inside_brackets`. Remove everything
874     else.
875
876     Note: don't use backslashes for formatting or you'll lose your voting rights.
877     """
878     if not inside_brackets:
879         spl = leaf.prefix.split("#")
880         if "\\" not in spl[0]:
881             nl_count = spl[-1].count("\n")
882             if len(spl) > 1:
883                 nl_count -= 1
884             leaf.prefix = "\n" * nl_count
885             return
886
887     leaf.prefix = ""
888
889
890 def normalize_invisible_parens(
891     node: Node, parens_after: Set[str], *, preview: bool
892 ) -> None:
893     """Make existing optional parentheses invisible or create new ones.
894
895     `parens_after` is a set of string leaf values immediately after which parens
896     should be put.
897
898     Standardizes on visible parentheses for single-element tuples, and keeps
899     existing visible parentheses for other tuples and generator expressions.
900     """
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.
904             return
905     check_lpar = False
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
912             )
913
914         # Add parentheses around long tuple unpacking in assignments.
915         if (
916             index == 0
917             and isinstance(child, Node)
918             and child.type == syms.testlist_star_expr
919         ):
920             check_lpar = True
921
922         if check_lpar:
923             if (
924                 preview
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"
930             ):
931                 if maybe_make_parens_invisible_in_atom(
932                     child,
933                     parent=node,
934                     remove_brackets_around_comma=True,
935                 ):
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(
941                     child,
942                     parent=node,
943                 ):
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
949                 # the statement
950                 if is_lpar_token(child):
951                     assert is_rpar_token(node.children[-1])
952                     # make parentheses invisible
953                     child.value = ""
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, ""))
959                 break
960             elif (
961                 index == 1
962                 and child.type == token.STAR
963                 and node.type == syms.except_clause
964             ):
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.
968                 continue
969
970             elif not (isinstance(child, Leaf) and is_multiline_string(child)):
971                 wrap_in_parentheses(node, child, visible=False)
972
973         comma_check = child.type == token.COMMA if preview else False
974
975         check_lpar = isinstance(child, Leaf) and (
976             child.value in parens_after or comma_check
977         )
978
979
980 def remove_await_parens(node: Node) -> None:
981     if node.children[0].type == token.AWAIT and len(node.children) > 1:
982         if (
983             node.children[1].type == syms.atom
984             and node.children[1].children[0].type == token.LPAR
985         ):
986             if maybe_make_parens_invisible_in_atom(
987                 node.children[1],
988                 parent=node,
989                 remove_brackets_around_comma=True,
990             ):
991                 wrap_in_parentheses(node, node.children[1], visible=False)
992
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)
1006             elif (
1007                 bracket_contents.type == syms.power
1008                 and bracket_contents.children[0].type == token.AWAIT
1009             ):
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)
1014
1015
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:
1021     #
1022     # with (open("file")) as f:                       # this is an asexpr_test
1023     #     ...
1024     #
1025     # with (open("file") as f):                       # this is an atom containing an
1026     #     ...                                         # asexpr_test
1027     #
1028     # with (open("file")) as f, (open("file")) as f:  # this is asexpr_test, COMMA,
1029     #     ...                                         # asexpr_test
1030     #
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(
1036             node,
1037             parent=parent,
1038             remove_brackets_around_comma=True,
1039         ):
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()
1049     ):
1050         if maybe_make_parens_invisible_in_atom(
1051             node.children[0],
1052             parent=node,
1053             remove_brackets_around_comma=True,
1054         ):
1055             wrap_in_parentheses(node, node.children[0], visible=False)
1056
1057
1058 def maybe_make_parens_invisible_in_atom(
1059     node: LN,
1060     parent: LN,
1061     remove_brackets_around_comma: bool = False,
1062 ) -> bool:
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.
1066
1067     Returns whether the node should itself be wrapped in invisible parentheses.
1068     """
1069     if (
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)
1074         or (
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
1080         )
1081     ):
1082         return False
1083
1084     if is_walrus_assignment(node):
1085         if parent.type in [
1086             syms.annassign,
1087             syms.expr_stmt,
1088             syms.assert_stmt,
1089             syms.return_stmt,
1090             # these ones aren't useful to end users, but they do please fuzzers
1091             syms.for_stmt,
1092             syms.del_stmt,
1093         ]:
1094             return False
1095
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
1101         first.value = ""
1102         last.value = ""
1103         maybe_make_parens_invisible_in_atom(
1104             middle,
1105             parent=parent,
1106             remove_brackets_around_comma=remove_brackets_around_comma,
1107         )
1108
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])
1113
1114         return False
1115
1116     return True
1117
1118
1119 def should_split_line(line: Line, opening_bracket: Leaf) -> bool:
1120     """Should `line` be immediately split with `delimiter_split()` after RHS?"""
1121
1122     if not (opening_bracket.parent and opening_bracket.value in "[{("):
1123         return False
1124
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).
1128     exclude = set()
1129     trailing_comma = False
1130     try:
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):
1137         return False
1138
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}
1143     )
1144
1145
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.
1148
1149     Brackets can be omitted if the entire trailer up to and including
1150     a preceding closing bracket fits in one line.
1151
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.
1155     """
1156
1157     omit: Set[LeafID] = set()
1158     if not line.magic_trailing_comma:
1159         yield omit
1160
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:
1168             break
1169
1170         has_inline_comment = leaf_length > len(leaf.value) + len(leaf.prefix)
1171         if leaf.type == STANDALONE_COMMENT or has_inline_comment:
1172             break
1173
1174         if opening_bracket:
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
1179                 if (
1180                     prev
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
1185                     )
1186                 ):
1187                     # Never omit bracket pairs with trailing commas.
1188                     # We need to explode on those.
1189                     break
1190
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))
1199                 continue
1200
1201             if closing_bracket:
1202                 omit.add(id(closing_bracket))
1203                 omit.update(inner_brackets)
1204                 inner_brackets.clear()
1205                 yield omit
1206
1207             if (
1208                 prev
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)
1212             ):
1213                 # Never omit bracket pairs with trailing commas.
1214                 # We need to explode on those.
1215                 break
1216
1217             if leaf.value:
1218                 opening_bracket = leaf.opening_bracket
1219                 closing_bracket = leaf
1220
1221
1222 def run_transformer(
1223     line: Line,
1224     transform: Transformer,
1225     mode: Mode,
1226     features: Collection[Feature],
1227     *,
1228     line_str: str = "",
1229 ) -> List[Line]:
1230     if not line_str:
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")
1236
1237         result.extend(transform_line(transformed_line, mode=mode, features=features))
1238
1239     if (
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)
1252     ):
1253         return result
1254
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
1260     )
1261     if all(
1262         is_line_short_enough(ln, line_length=mode.line_length) for ln in second_opinion
1263     ):
1264         result = second_opinion
1265     return result