]> git.madduck.net Git - etc/vim.git/blob - black.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:

Make cache work with non-default line lenghts (#163)
[etc/vim.git] / black.py
1 #!/usr/bin/env python3
2
3 import asyncio
4 import pickle
5 from asyncio.base_events import BaseEventLoop
6 from concurrent.futures import Executor, ProcessPoolExecutor
7 from enum import Enum
8 from functools import partial, wraps
9 import keyword
10 import logging
11 from multiprocessing import Manager
12 import os
13 from pathlib import Path
14 import re
15 import tokenize
16 import signal
17 import sys
18 from typing import (
19     Any,
20     Callable,
21     Collection,
22     Dict,
23     Generic,
24     Iterable,
25     Iterator,
26     List,
27     Optional,
28     Pattern,
29     Set,
30     Tuple,
31     Type,
32     TypeVar,
33     Union,
34 )
35
36 from appdirs import user_cache_dir
37 from attr import dataclass, Factory
38 import click
39
40 # lib2to3 fork
41 from blib2to3.pytree import Node, Leaf, type_repr
42 from blib2to3 import pygram, pytree
43 from blib2to3.pgen2 import driver, token
44 from blib2to3.pgen2.parse import ParseError
45
46 __version__ = "18.4a2"
47 DEFAULT_LINE_LENGTH = 88
48 # types
49 syms = pygram.python_symbols
50 FileContent = str
51 Encoding = str
52 Depth = int
53 NodeType = int
54 LeafID = int
55 Priority = int
56 Index = int
57 LN = Union[Leaf, Node]
58 SplitFunc = Callable[["Line", bool], Iterator["Line"]]
59 Timestamp = float
60 FileSize = int
61 CacheInfo = Tuple[Timestamp, FileSize]
62 Cache = Dict[Path, CacheInfo]
63 out = partial(click.secho, bold=True, err=True)
64 err = partial(click.secho, fg="red", err=True)
65
66
67 class NothingChanged(UserWarning):
68     """Raised by :func:`format_file` when reformatted code is the same as source."""
69
70
71 class CannotSplit(Exception):
72     """A readable split that fits the allotted line length is impossible.
73
74     Raised by :func:`left_hand_split`, :func:`right_hand_split`, and
75     :func:`delimiter_split`.
76     """
77
78
79 class FormatError(Exception):
80     """Base exception for `# fmt: on` and `# fmt: off` handling.
81
82     It holds the number of bytes of the prefix consumed before the format
83     control comment appeared.
84     """
85
86     def __init__(self, consumed: int) -> None:
87         super().__init__(consumed)
88         self.consumed = consumed
89
90     def trim_prefix(self, leaf: Leaf) -> None:
91         leaf.prefix = leaf.prefix[self.consumed:]
92
93     def leaf_from_consumed(self, leaf: Leaf) -> Leaf:
94         """Returns a new Leaf from the consumed part of the prefix."""
95         unformatted_prefix = leaf.prefix[:self.consumed]
96         return Leaf(token.NEWLINE, unformatted_prefix)
97
98
99 class FormatOn(FormatError):
100     """Found a comment like `# fmt: on` in the file."""
101
102
103 class FormatOff(FormatError):
104     """Found a comment like `# fmt: off` in the file."""
105
106
107 class WriteBack(Enum):
108     NO = 0
109     YES = 1
110     DIFF = 2
111
112
113 class Changed(Enum):
114     NO = 0
115     CACHED = 1
116     YES = 2
117
118
119 @click.command()
120 @click.option(
121     "-l",
122     "--line-length",
123     type=int,
124     default=DEFAULT_LINE_LENGTH,
125     help="How many character per line to allow.",
126     show_default=True,
127 )
128 @click.option(
129     "--check",
130     is_flag=True,
131     help=(
132         "Don't write the files back, just return the status.  Return code 0 "
133         "means nothing would change.  Return code 1 means some files would be "
134         "reformatted.  Return code 123 means there was an internal error."
135     ),
136 )
137 @click.option(
138     "--diff",
139     is_flag=True,
140     help="Don't write the files back, just output a diff for each file on stdout.",
141 )
142 @click.option(
143     "--fast/--safe",
144     is_flag=True,
145     help="If --fast given, skip temporary sanity checks. [default: --safe]",
146 )
147 @click.option(
148     "-q",
149     "--quiet",
150     is_flag=True,
151     help=(
152         "Don't emit non-error messages to stderr. Errors are still emitted, "
153         "silence those with 2>/dev/null."
154     ),
155 )
156 @click.version_option(version=__version__)
157 @click.argument(
158     "src",
159     nargs=-1,
160     type=click.Path(
161         exists=True, file_okay=True, dir_okay=True, readable=True, allow_dash=True
162     ),
163 )
164 @click.pass_context
165 def main(
166     ctx: click.Context,
167     line_length: int,
168     check: bool,
169     diff: bool,
170     fast: bool,
171     quiet: bool,
172     src: List[str],
173 ) -> None:
174     """The uncompromising code formatter."""
175     sources: List[Path] = []
176     for s in src:
177         p = Path(s)
178         if p.is_dir():
179             sources.extend(gen_python_files_in_dir(p))
180         elif p.is_file():
181             # if a file was explicitly given, we don't care about its extension
182             sources.append(p)
183         elif s == "-":
184             sources.append(Path("-"))
185         else:
186             err(f"invalid path: {s}")
187
188     if check and not diff:
189         write_back = WriteBack.NO
190     elif diff:
191         write_back = WriteBack.DIFF
192     else:
193         write_back = WriteBack.YES
194     report = Report(check=check, quiet=quiet)
195     if len(sources) == 0:
196         ctx.exit(0)
197         return
198
199     elif len(sources) == 1:
200         reformat_one(sources[0], line_length, fast, write_back, report)
201     else:
202         loop = asyncio.get_event_loop()
203         executor = ProcessPoolExecutor(max_workers=os.cpu_count())
204         try:
205             loop.run_until_complete(
206                 schedule_formatting(
207                     sources, line_length, fast, write_back, report, loop, executor
208                 )
209             )
210         finally:
211             shutdown(loop)
212         if not quiet:
213             out("All done! ✨ 🍰 ✨")
214             click.echo(str(report))
215     ctx.exit(report.return_code)
216
217
218 def reformat_one(
219     src: Path, line_length: int, fast: bool, write_back: WriteBack, report: "Report"
220 ) -> None:
221     """Reformat a single file under `src` without spawning child processes.
222
223     If `quiet` is True, non-error messages are not output. `line_length`,
224     `write_back`, and `fast` options are passed to :func:`format_file_in_place`.
225     """
226     try:
227         changed = Changed.NO
228         if not src.is_file() and str(src) == "-":
229             if format_stdin_to_stdout(
230                 line_length=line_length, fast=fast, write_back=write_back
231             ):
232                 changed = Changed.YES
233         else:
234             cache: Cache = {}
235             if write_back != WriteBack.DIFF:
236                 cache = read_cache(line_length)
237                 src = src.resolve()
238                 if src in cache and cache[src] == get_cache_info(src):
239                     changed = Changed.CACHED
240             if (
241                 changed is not Changed.CACHED
242                 and format_file_in_place(
243                     src, line_length=line_length, fast=fast, write_back=write_back
244                 )
245             ):
246                 changed = Changed.YES
247             if write_back != WriteBack.DIFF and changed is not Changed.NO:
248                 write_cache(cache, [src], line_length)
249         report.done(src, changed)
250     except Exception as exc:
251         report.failed(src, str(exc))
252
253
254 async def schedule_formatting(
255     sources: List[Path],
256     line_length: int,
257     fast: bool,
258     write_back: WriteBack,
259     report: "Report",
260     loop: BaseEventLoop,
261     executor: Executor,
262 ) -> None:
263     """Run formatting of `sources` in parallel using the provided `executor`.
264
265     (Use ProcessPoolExecutors for actual parallelism.)
266
267     `line_length`, `write_back`, and `fast` options are passed to
268     :func:`format_file_in_place`.
269     """
270     cache: Cache = {}
271     if write_back != WriteBack.DIFF:
272         cache = read_cache(line_length)
273         sources, cached = filter_cached(cache, sources)
274         for src in cached:
275             report.done(src, Changed.CACHED)
276     cancelled = []
277     formatted = []
278     if sources:
279         lock = None
280         if write_back == WriteBack.DIFF:
281             # For diff output, we need locks to ensure we don't interleave output
282             # from different processes.
283             manager = Manager()
284             lock = manager.Lock()
285         tasks = {
286             src: loop.run_in_executor(
287                 executor, format_file_in_place, src, line_length, fast, write_back, lock
288             )
289             for src in sources
290         }
291         _task_values = list(tasks.values())
292         try:
293             loop.add_signal_handler(signal.SIGINT, cancel, _task_values)
294             loop.add_signal_handler(signal.SIGTERM, cancel, _task_values)
295         except NotImplementedError:
296             # There are no good alternatives for these on Windows
297             pass
298         await asyncio.wait(_task_values)
299         for src, task in tasks.items():
300             if not task.done():
301                 report.failed(src, "timed out, cancelling")
302                 task.cancel()
303                 cancelled.append(task)
304             elif task.cancelled():
305                 cancelled.append(task)
306             elif task.exception():
307                 report.failed(src, str(task.exception()))
308             else:
309                 formatted.append(src)
310                 report.done(src, Changed.YES if task.result() else Changed.NO)
311
312     if cancelled:
313         await asyncio.gather(*cancelled, loop=loop, return_exceptions=True)
314     if write_back != WriteBack.DIFF and formatted:
315         write_cache(cache, formatted, line_length)
316
317
318 def format_file_in_place(
319     src: Path,
320     line_length: int,
321     fast: bool,
322     write_back: WriteBack = WriteBack.NO,
323     lock: Any = None,  # multiprocessing.Manager().Lock() is some crazy proxy
324 ) -> bool:
325     """Format file under `src` path. Return True if changed.
326
327     If `write_back` is True, write reformatted code back to stdout.
328     `line_length` and `fast` options are passed to :func:`format_file_contents`.
329     """
330
331     with tokenize.open(src) as src_buffer:
332         src_contents = src_buffer.read()
333     try:
334         dst_contents = format_file_contents(
335             src_contents, line_length=line_length, fast=fast
336         )
337     except NothingChanged:
338         return False
339
340     if write_back == write_back.YES:
341         with open(src, "w", encoding=src_buffer.encoding) as f:
342             f.write(dst_contents)
343     elif write_back == write_back.DIFF:
344         src_name = f"{src}  (original)"
345         dst_name = f"{src}  (formatted)"
346         diff_contents = diff(src_contents, dst_contents, src_name, dst_name)
347         if lock:
348             lock.acquire()
349         try:
350             sys.stdout.write(diff_contents)
351         finally:
352             if lock:
353                 lock.release()
354     return True
355
356
357 def format_stdin_to_stdout(
358     line_length: int, fast: bool, write_back: WriteBack = WriteBack.NO
359 ) -> bool:
360     """Format file on stdin. Return True if changed.
361
362     If `write_back` is True, write reformatted code back to stdout.
363     `line_length` and `fast` arguments are passed to :func:`format_file_contents`.
364     """
365     src = sys.stdin.read()
366     dst = src
367     try:
368         dst = format_file_contents(src, line_length=line_length, fast=fast)
369         return True
370
371     except NothingChanged:
372         return False
373
374     finally:
375         if write_back == WriteBack.YES:
376             sys.stdout.write(dst)
377         elif write_back == WriteBack.DIFF:
378             src_name = "<stdin>  (original)"
379             dst_name = "<stdin>  (formatted)"
380             sys.stdout.write(diff(src, dst, src_name, dst_name))
381
382
383 def format_file_contents(
384     src_contents: str, line_length: int, fast: bool
385 ) -> FileContent:
386     """Reformat contents a file and return new contents.
387
388     If `fast` is False, additionally confirm that the reformatted code is
389     valid by calling :func:`assert_equivalent` and :func:`assert_stable` on it.
390     `line_length` is passed to :func:`format_str`.
391     """
392     if src_contents.strip() == "":
393         raise NothingChanged
394
395     dst_contents = format_str(src_contents, line_length=line_length)
396     if src_contents == dst_contents:
397         raise NothingChanged
398
399     if not fast:
400         assert_equivalent(src_contents, dst_contents)
401         assert_stable(src_contents, dst_contents, line_length=line_length)
402     return dst_contents
403
404
405 def format_str(src_contents: str, line_length: int) -> FileContent:
406     """Reformat a string and return new contents.
407
408     `line_length` determines how many characters per line are allowed.
409     """
410     src_node = lib2to3_parse(src_contents)
411     dst_contents = ""
412     lines = LineGenerator()
413     elt = EmptyLineTracker()
414     py36 = is_python36(src_node)
415     empty_line = Line()
416     after = 0
417     for current_line in lines.visit(src_node):
418         for _ in range(after):
419             dst_contents += str(empty_line)
420         before, after = elt.maybe_empty_lines(current_line)
421         for _ in range(before):
422             dst_contents += str(empty_line)
423         for line in split_line(current_line, line_length=line_length, py36=py36):
424             dst_contents += str(line)
425     return dst_contents
426
427
428 GRAMMARS = [
429     pygram.python_grammar_no_print_statement_no_exec_statement,
430     pygram.python_grammar_no_print_statement,
431     pygram.python_grammar,
432 ]
433
434
435 def lib2to3_parse(src_txt: str) -> Node:
436     """Given a string with source, return the lib2to3 Node."""
437     grammar = pygram.python_grammar_no_print_statement
438     if src_txt[-1] != "\n":
439         nl = "\r\n" if "\r\n" in src_txt[:1024] else "\n"
440         src_txt += nl
441     for grammar in GRAMMARS:
442         drv = driver.Driver(grammar, pytree.convert)
443         try:
444             result = drv.parse_string(src_txt, True)
445             break
446
447         except ParseError as pe:
448             lineno, column = pe.context[1]
449             lines = src_txt.splitlines()
450             try:
451                 faulty_line = lines[lineno - 1]
452             except IndexError:
453                 faulty_line = "<line number missing in source>"
454             exc = ValueError(f"Cannot parse: {lineno}:{column}: {faulty_line}")
455     else:
456         raise exc from None
457
458     if isinstance(result, Leaf):
459         result = Node(syms.file_input, [result])
460     return result
461
462
463 def lib2to3_unparse(node: Node) -> str:
464     """Given a lib2to3 node, return its string representation."""
465     code = str(node)
466     return code
467
468
469 T = TypeVar("T")
470
471
472 class Visitor(Generic[T]):
473     """Basic lib2to3 visitor that yields things of type `T` on `visit()`."""
474
475     def visit(self, node: LN) -> Iterator[T]:
476         """Main method to visit `node` and its children.
477
478         It tries to find a `visit_*()` method for the given `node.type`, like
479         `visit_simple_stmt` for Node objects or `visit_INDENT` for Leaf objects.
480         If no dedicated `visit_*()` method is found, chooses `visit_default()`
481         instead.
482
483         Then yields objects of type `T` from the selected visitor.
484         """
485         if node.type < 256:
486             name = token.tok_name[node.type]
487         else:
488             name = type_repr(node.type)
489         yield from getattr(self, f"visit_{name}", self.visit_default)(node)
490
491     def visit_default(self, node: LN) -> Iterator[T]:
492         """Default `visit_*()` implementation. Recurses to children of `node`."""
493         if isinstance(node, Node):
494             for child in node.children:
495                 yield from self.visit(child)
496
497
498 @dataclass
499 class DebugVisitor(Visitor[T]):
500     tree_depth: int = 0
501
502     def visit_default(self, node: LN) -> Iterator[T]:
503         indent = " " * (2 * self.tree_depth)
504         if isinstance(node, Node):
505             _type = type_repr(node.type)
506             out(f"{indent}{_type}", fg="yellow")
507             self.tree_depth += 1
508             for child in node.children:
509                 yield from self.visit(child)
510
511             self.tree_depth -= 1
512             out(f"{indent}/{_type}", fg="yellow", bold=False)
513         else:
514             _type = token.tok_name.get(node.type, str(node.type))
515             out(f"{indent}{_type}", fg="blue", nl=False)
516             if node.prefix:
517                 # We don't have to handle prefixes for `Node` objects since
518                 # that delegates to the first child anyway.
519                 out(f" {node.prefix!r}", fg="green", bold=False, nl=False)
520             out(f" {node.value!r}", fg="blue", bold=False)
521
522     @classmethod
523     def show(cls, code: str) -> None:
524         """Pretty-print the lib2to3 AST of a given string of `code`.
525
526         Convenience method for debugging.
527         """
528         v: DebugVisitor[None] = DebugVisitor()
529         list(v.visit(lib2to3_parse(code)))
530
531
532 KEYWORDS = set(keyword.kwlist)
533 WHITESPACE = {token.DEDENT, token.INDENT, token.NEWLINE}
534 FLOW_CONTROL = {"return", "raise", "break", "continue"}
535 STATEMENT = {
536     syms.if_stmt,
537     syms.while_stmt,
538     syms.for_stmt,
539     syms.try_stmt,
540     syms.except_clause,
541     syms.with_stmt,
542     syms.funcdef,
543     syms.classdef,
544 }
545 STANDALONE_COMMENT = 153
546 LOGIC_OPERATORS = {"and", "or"}
547 COMPARATORS = {
548     token.LESS,
549     token.GREATER,
550     token.EQEQUAL,
551     token.NOTEQUAL,
552     token.LESSEQUAL,
553     token.GREATEREQUAL,
554 }
555 MATH_OPERATORS = {
556     token.PLUS,
557     token.MINUS,
558     token.STAR,
559     token.SLASH,
560     token.VBAR,
561     token.AMPER,
562     token.PERCENT,
563     token.CIRCUMFLEX,
564     token.TILDE,
565     token.LEFTSHIFT,
566     token.RIGHTSHIFT,
567     token.DOUBLESTAR,
568     token.DOUBLESLASH,
569 }
570 STARS = {token.STAR, token.DOUBLESTAR}
571 VARARGS_PARENTS = {
572     syms.arglist,
573     syms.argument,  # double star in arglist
574     syms.trailer,  # single argument to call
575     syms.typedargslist,
576     syms.varargslist,  # lambdas
577 }
578 UNPACKING_PARENTS = {
579     syms.atom,  # single element of a list or set literal
580     syms.dictsetmaker,
581     syms.listmaker,
582     syms.testlist_gexp,
583 }
584 COMPREHENSION_PRIORITY = 20
585 COMMA_PRIORITY = 10
586 LOGIC_PRIORITY = 5
587 STRING_PRIORITY = 4
588 COMPARATOR_PRIORITY = 3
589 MATH_PRIORITY = 1
590
591
592 @dataclass
593 class BracketTracker:
594     """Keeps track of brackets on a line."""
595
596     depth: int = 0
597     bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = Factory(dict)
598     delimiters: Dict[LeafID, Priority] = Factory(dict)
599     previous: Optional[Leaf] = None
600     _for_loop_variable: bool = False
601     _lambda_arguments: bool = False
602
603     def mark(self, leaf: Leaf) -> None:
604         """Mark `leaf` with bracket-related metadata. Keep track of delimiters.
605
606         All leaves receive an int `bracket_depth` field that stores how deep
607         within brackets a given leaf is. 0 means there are no enclosing brackets
608         that started on this line.
609
610         If a leaf is itself a closing bracket, it receives an `opening_bracket`
611         field that it forms a pair with. This is a one-directional link to
612         avoid reference cycles.
613
614         If a leaf is a delimiter (a token on which Black can split the line if
615         needed) and it's on depth 0, its `id()` is stored in the tracker's
616         `delimiters` field.
617         """
618         if leaf.type == token.COMMENT:
619             return
620
621         self.maybe_decrement_after_for_loop_variable(leaf)
622         self.maybe_decrement_after_lambda_arguments(leaf)
623         if leaf.type in CLOSING_BRACKETS:
624             self.depth -= 1
625             opening_bracket = self.bracket_match.pop((self.depth, leaf.type))
626             leaf.opening_bracket = opening_bracket
627         leaf.bracket_depth = self.depth
628         if self.depth == 0:
629             delim = is_split_before_delimiter(leaf, self.previous)
630             if delim and self.previous is not None:
631                 self.delimiters[id(self.previous)] = delim
632             else:
633                 delim = is_split_after_delimiter(leaf, self.previous)
634                 if delim:
635                     self.delimiters[id(leaf)] = delim
636         if leaf.type in OPENING_BRACKETS:
637             self.bracket_match[self.depth, BRACKET[leaf.type]] = leaf
638             self.depth += 1
639         self.previous = leaf
640         self.maybe_increment_lambda_arguments(leaf)
641         self.maybe_increment_for_loop_variable(leaf)
642
643     def any_open_brackets(self) -> bool:
644         """Return True if there is an yet unmatched open bracket on the line."""
645         return bool(self.bracket_match)
646
647     def max_delimiter_priority(self, exclude: Iterable[LeafID] = ()) -> int:
648         """Return the highest priority of a delimiter found on the line.
649
650         Values are consistent with what `is_split_*_delimiter()` return.
651         Raises ValueError on no delimiters.
652         """
653         return max(v for k, v in self.delimiters.items() if k not in exclude)
654
655     def maybe_increment_for_loop_variable(self, leaf: Leaf) -> bool:
656         """In a for loop, or comprehension, the variables are often unpacks.
657
658         To avoid splitting on the comma in this situation, increase the depth of
659         tokens between `for` and `in`.
660         """
661         if leaf.type == token.NAME and leaf.value == "for":
662             self.depth += 1
663             self._for_loop_variable = True
664             return True
665
666         return False
667
668     def maybe_decrement_after_for_loop_variable(self, leaf: Leaf) -> bool:
669         """See `maybe_increment_for_loop_variable` above for explanation."""
670         if self._for_loop_variable and leaf.type == token.NAME and leaf.value == "in":
671             self.depth -= 1
672             self._for_loop_variable = False
673             return True
674
675         return False
676
677     def maybe_increment_lambda_arguments(self, leaf: Leaf) -> bool:
678         """In a lambda expression, there might be more than one argument.
679
680         To avoid splitting on the comma in this situation, increase the depth of
681         tokens between `lambda` and `:`.
682         """
683         if leaf.type == token.NAME and leaf.value == "lambda":
684             self.depth += 1
685             self._lambda_arguments = True
686             return True
687
688         return False
689
690     def maybe_decrement_after_lambda_arguments(self, leaf: Leaf) -> bool:
691         """See `maybe_increment_lambda_arguments` above for explanation."""
692         if self._lambda_arguments and leaf.type == token.COLON:
693             self.depth -= 1
694             self._lambda_arguments = False
695             return True
696
697         return False
698
699
700 @dataclass
701 class Line:
702     """Holds leaves and comments. Can be printed with `str(line)`."""
703
704     depth: int = 0
705     leaves: List[Leaf] = Factory(list)
706     comments: List[Tuple[Index, Leaf]] = Factory(list)
707     bracket_tracker: BracketTracker = Factory(BracketTracker)
708     inside_brackets: bool = False
709
710     def append(self, leaf: Leaf, preformatted: bool = False) -> None:
711         """Add a new `leaf` to the end of the line.
712
713         Unless `preformatted` is True, the `leaf` will receive a new consistent
714         whitespace prefix and metadata applied by :class:`BracketTracker`.
715         Trailing commas are maybe removed, unpacked for loop variables are
716         demoted from being delimiters.
717
718         Inline comments are put aside.
719         """
720         has_value = leaf.type in BRACKETS or bool(leaf.value.strip())
721         if not has_value:
722             return
723
724         if self.leaves and not preformatted:
725             # Note: at this point leaf.prefix should be empty except for
726             # imports, for which we only preserve newlines.
727             leaf.prefix += whitespace(leaf)
728         if self.inside_brackets or not preformatted:
729             self.bracket_tracker.mark(leaf)
730             self.maybe_remove_trailing_comma(leaf)
731
732         if not self.append_comment(leaf):
733             self.leaves.append(leaf)
734
735     def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
736         """Like :func:`append()` but disallow invalid standalone comment structure.
737
738         Raises ValueError when any `leaf` is appended after a standalone comment
739         or when a standalone comment is not the first leaf on the line.
740         """
741         if self.bracket_tracker.depth == 0:
742             if self.is_comment:
743                 raise ValueError("cannot append to standalone comments")
744
745             if self.leaves and leaf.type == STANDALONE_COMMENT:
746                 raise ValueError(
747                     "cannot append standalone comments to a populated line"
748                 )
749
750         self.append(leaf, preformatted=preformatted)
751
752     @property
753     def is_comment(self) -> bool:
754         """Is this line a standalone comment?"""
755         return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
756
757     @property
758     def is_decorator(self) -> bool:
759         """Is this line a decorator?"""
760         return bool(self) and self.leaves[0].type == token.AT
761
762     @property
763     def is_import(self) -> bool:
764         """Is this an import line?"""
765         return bool(self) and is_import(self.leaves[0])
766
767     @property
768     def is_class(self) -> bool:
769         """Is this line a class definition?"""
770         return (
771             bool(self)
772             and self.leaves[0].type == token.NAME
773             and self.leaves[0].value == "class"
774         )
775
776     @property
777     def is_def(self) -> bool:
778         """Is this a function definition? (Also returns True for async defs.)"""
779         try:
780             first_leaf = self.leaves[0]
781         except IndexError:
782             return False
783
784         try:
785             second_leaf: Optional[Leaf] = self.leaves[1]
786         except IndexError:
787             second_leaf = None
788         return (
789             (first_leaf.type == token.NAME and first_leaf.value == "def")
790             or (
791                 first_leaf.type == token.ASYNC
792                 and second_leaf is not None
793                 and second_leaf.type == token.NAME
794                 and second_leaf.value == "def"
795             )
796         )
797
798     @property
799     def is_flow_control(self) -> bool:
800         """Is this line a flow control statement?
801
802         Those are `return`, `raise`, `break`, and `continue`.
803         """
804         return (
805             bool(self)
806             and self.leaves[0].type == token.NAME
807             and self.leaves[0].value in FLOW_CONTROL
808         )
809
810     @property
811     def is_yield(self) -> bool:
812         """Is this line a yield statement?"""
813         return (
814             bool(self)
815             and self.leaves[0].type == token.NAME
816             and self.leaves[0].value == "yield"
817         )
818
819     def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
820         """If so, needs to be split before emitting."""
821         for leaf in self.leaves:
822             if leaf.type == STANDALONE_COMMENT:
823                 if leaf.bracket_depth <= depth_limit:
824                     return True
825
826         return False
827
828     def maybe_remove_trailing_comma(self, closing: Leaf) -> bool:
829         """Remove trailing comma if there is one and it's safe."""
830         if not (
831             self.leaves
832             and self.leaves[-1].type == token.COMMA
833             and closing.type in CLOSING_BRACKETS
834         ):
835             return False
836
837         if closing.type == token.RBRACE:
838             self.remove_trailing_comma()
839             return True
840
841         if closing.type == token.RSQB:
842             comma = self.leaves[-1]
843             if comma.parent and comma.parent.type == syms.listmaker:
844                 self.remove_trailing_comma()
845                 return True
846
847         # For parens let's check if it's safe to remove the comma.  If the
848         # trailing one is the only one, we might mistakenly change a tuple
849         # into a different type by removing the comma.
850         depth = closing.bracket_depth + 1
851         commas = 0
852         opening = closing.opening_bracket
853         for _opening_index, leaf in enumerate(self.leaves):
854             if leaf is opening:
855                 break
856
857         else:
858             return False
859
860         for leaf in self.leaves[_opening_index + 1:]:
861             if leaf is closing:
862                 break
863
864             bracket_depth = leaf.bracket_depth
865             if bracket_depth == depth and leaf.type == token.COMMA:
866                 commas += 1
867                 if leaf.parent and leaf.parent.type == syms.arglist:
868                     commas += 1
869                     break
870
871         if commas > 1:
872             self.remove_trailing_comma()
873             return True
874
875         return False
876
877     def append_comment(self, comment: Leaf) -> bool:
878         """Add an inline or standalone comment to the line."""
879         if (
880             comment.type == STANDALONE_COMMENT
881             and self.bracket_tracker.any_open_brackets()
882         ):
883             comment.prefix = ""
884             return False
885
886         if comment.type != token.COMMENT:
887             return False
888
889         after = len(self.leaves) - 1
890         if after == -1:
891             comment.type = STANDALONE_COMMENT
892             comment.prefix = ""
893             return False
894
895         else:
896             self.comments.append((after, comment))
897             return True
898
899     def comments_after(self, leaf: Leaf) -> Iterator[Leaf]:
900         """Generate comments that should appear directly after `leaf`."""
901         for _leaf_index, _leaf in enumerate(self.leaves):
902             if leaf is _leaf:
903                 break
904
905         else:
906             return
907
908         for index, comment_after in self.comments:
909             if _leaf_index == index:
910                 yield comment_after
911
912     def remove_trailing_comma(self) -> None:
913         """Remove the trailing comma and moves the comments attached to it."""
914         comma_index = len(self.leaves) - 1
915         for i in range(len(self.comments)):
916             comment_index, comment = self.comments[i]
917             if comment_index == comma_index:
918                 self.comments[i] = (comma_index - 1, comment)
919         self.leaves.pop()
920
921     def __str__(self) -> str:
922         """Render the line."""
923         if not self:
924             return "\n"
925
926         indent = "    " * self.depth
927         leaves = iter(self.leaves)
928         first = next(leaves)
929         res = f"{first.prefix}{indent}{first.value}"
930         for leaf in leaves:
931             res += str(leaf)
932         for _, comment in self.comments:
933             res += str(comment)
934         return res + "\n"
935
936     def __bool__(self) -> bool:
937         """Return True if the line has leaves or comments."""
938         return bool(self.leaves or self.comments)
939
940
941 class UnformattedLines(Line):
942     """Just like :class:`Line` but stores lines which aren't reformatted."""
943
944     def append(self, leaf: Leaf, preformatted: bool = True) -> None:
945         """Just add a new `leaf` to the end of the lines.
946
947         The `preformatted` argument is ignored.
948
949         Keeps track of indentation `depth`, which is useful when the user
950         says `# fmt: on`. Otherwise, doesn't do anything with the `leaf`.
951         """
952         try:
953             list(generate_comments(leaf))
954         except FormatOn as f_on:
955             self.leaves.append(f_on.leaf_from_consumed(leaf))
956             raise
957
958         self.leaves.append(leaf)
959         if leaf.type == token.INDENT:
960             self.depth += 1
961         elif leaf.type == token.DEDENT:
962             self.depth -= 1
963
964     def __str__(self) -> str:
965         """Render unformatted lines from leaves which were added with `append()`.
966
967         `depth` is not used for indentation in this case.
968         """
969         if not self:
970             return "\n"
971
972         res = ""
973         for leaf in self.leaves:
974             res += str(leaf)
975         return res
976
977     def append_comment(self, comment: Leaf) -> bool:
978         """Not implemented in this class. Raises `NotImplementedError`."""
979         raise NotImplementedError("Unformatted lines don't store comments separately.")
980
981     def maybe_remove_trailing_comma(self, closing: Leaf) -> bool:
982         """Does nothing and returns False."""
983         return False
984
985     def maybe_increment_for_loop_variable(self, leaf: Leaf) -> bool:
986         """Does nothing and returns False."""
987         return False
988
989
990 @dataclass
991 class EmptyLineTracker:
992     """Provides a stateful method that returns the number of potential extra
993     empty lines needed before and after the currently processed line.
994
995     Note: this tracker works on lines that haven't been split yet.  It assumes
996     the prefix of the first leaf consists of optional newlines.  Those newlines
997     are consumed by `maybe_empty_lines()` and included in the computation.
998     """
999     previous_line: Optional[Line] = None
1000     previous_after: int = 0
1001     previous_defs: List[int] = Factory(list)
1002
1003     def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
1004         """Return the number of extra empty lines before and after the `current_line`.
1005
1006         This is for separating `def`, `async def` and `class` with extra empty
1007         lines (two on module-level), as well as providing an extra empty line
1008         after flow control keywords to make them more prominent.
1009         """
1010         if isinstance(current_line, UnformattedLines):
1011             return 0, 0
1012
1013         before, after = self._maybe_empty_lines(current_line)
1014         before -= self.previous_after
1015         self.previous_after = after
1016         self.previous_line = current_line
1017         return before, after
1018
1019     def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
1020         max_allowed = 1
1021         if current_line.depth == 0:
1022             max_allowed = 2
1023         if current_line.leaves:
1024             # Consume the first leaf's extra newlines.
1025             first_leaf = current_line.leaves[0]
1026             before = first_leaf.prefix.count("\n")
1027             before = min(before, max_allowed)
1028             first_leaf.prefix = ""
1029         else:
1030             before = 0
1031         depth = current_line.depth
1032         while self.previous_defs and self.previous_defs[-1] >= depth:
1033             self.previous_defs.pop()
1034             before = 1 if depth else 2
1035         is_decorator = current_line.is_decorator
1036         if is_decorator or current_line.is_def or current_line.is_class:
1037             if not is_decorator:
1038                 self.previous_defs.append(depth)
1039             if self.previous_line is None:
1040                 # Don't insert empty lines before the first line in the file.
1041                 return 0, 0
1042
1043             if self.previous_line.is_decorator:
1044                 return 0, 0
1045
1046             if (
1047                 self.previous_line.is_comment
1048                 and self.previous_line.depth == current_line.depth
1049                 and before == 0
1050             ):
1051                 return 0, 0
1052
1053             newlines = 2
1054             if current_line.depth:
1055                 newlines -= 1
1056             return newlines, 0
1057
1058         if current_line.is_flow_control:
1059             return before, 1
1060
1061         if (
1062             self.previous_line
1063             and self.previous_line.is_import
1064             and not current_line.is_import
1065             and depth == self.previous_line.depth
1066         ):
1067             return (before or 1), 0
1068
1069         if (
1070             self.previous_line
1071             and self.previous_line.is_yield
1072             and (not current_line.is_yield or depth != self.previous_line.depth)
1073         ):
1074             return (before or 1), 0
1075
1076         return before, 0
1077
1078
1079 @dataclass
1080 class LineGenerator(Visitor[Line]):
1081     """Generates reformatted Line objects.  Empty lines are not emitted.
1082
1083     Note: destroys the tree it's visiting by mutating prefixes of its leaves
1084     in ways that will no longer stringify to valid Python code on the tree.
1085     """
1086     current_line: Line = Factory(Line)
1087
1088     def line(self, indent: int = 0, type: Type[Line] = Line) -> Iterator[Line]:
1089         """Generate a line.
1090
1091         If the line is empty, only emit if it makes sense.
1092         If the line is too long, split it first and then generate.
1093
1094         If any lines were generated, set up a new current_line.
1095         """
1096         if not self.current_line:
1097             if self.current_line.__class__ == type:
1098                 self.current_line.depth += indent
1099             else:
1100                 self.current_line = type(depth=self.current_line.depth + indent)
1101             return  # Line is empty, don't emit. Creating a new one unnecessary.
1102
1103         complete_line = self.current_line
1104         self.current_line = type(depth=complete_line.depth + indent)
1105         yield complete_line
1106
1107     def visit(self, node: LN) -> Iterator[Line]:
1108         """Main method to visit `node` and its children.
1109
1110         Yields :class:`Line` objects.
1111         """
1112         if isinstance(self.current_line, UnformattedLines):
1113             # File contained `# fmt: off`
1114             yield from self.visit_unformatted(node)
1115
1116         else:
1117             yield from super().visit(node)
1118
1119     def visit_default(self, node: LN) -> Iterator[Line]:
1120         """Default `visit_*()` implementation. Recurses to children of `node`."""
1121         if isinstance(node, Leaf):
1122             any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
1123             try:
1124                 for comment in generate_comments(node):
1125                     if any_open_brackets:
1126                         # any comment within brackets is subject to splitting
1127                         self.current_line.append(comment)
1128                     elif comment.type == token.COMMENT:
1129                         # regular trailing comment
1130                         self.current_line.append(comment)
1131                         yield from self.line()
1132
1133                     else:
1134                         # regular standalone comment
1135                         yield from self.line()
1136
1137                         self.current_line.append(comment)
1138                         yield from self.line()
1139
1140             except FormatOff as f_off:
1141                 f_off.trim_prefix(node)
1142                 yield from self.line(type=UnformattedLines)
1143                 yield from self.visit(node)
1144
1145             except FormatOn as f_on:
1146                 # This only happens here if somebody says "fmt: on" multiple
1147                 # times in a row.
1148                 f_on.trim_prefix(node)
1149                 yield from self.visit_default(node)
1150
1151             else:
1152                 normalize_prefix(node, inside_brackets=any_open_brackets)
1153                 if node.type == token.STRING:
1154                     normalize_string_quotes(node)
1155                 if node.type not in WHITESPACE:
1156                     self.current_line.append(node)
1157         yield from super().visit_default(node)
1158
1159     def visit_INDENT(self, node: Node) -> Iterator[Line]:
1160         """Increase indentation level, maybe yield a line."""
1161         # In blib2to3 INDENT never holds comments.
1162         yield from self.line(+1)
1163         yield from self.visit_default(node)
1164
1165     def visit_DEDENT(self, node: Node) -> Iterator[Line]:
1166         """Decrease indentation level, maybe yield a line."""
1167         # The current line might still wait for trailing comments.  At DEDENT time
1168         # there won't be any (they would be prefixes on the preceding NEWLINE).
1169         # Emit the line then.
1170         yield from self.line()
1171
1172         # While DEDENT has no value, its prefix may contain standalone comments
1173         # that belong to the current indentation level.  Get 'em.
1174         yield from self.visit_default(node)
1175
1176         # Finally, emit the dedent.
1177         yield from self.line(-1)
1178
1179     def visit_stmt(
1180         self, node: Node, keywords: Set[str], parens: Set[str]
1181     ) -> Iterator[Line]:
1182         """Visit a statement.
1183
1184         This implementation is shared for `if`, `while`, `for`, `try`, `except`,
1185         `def`, `with`, `class`, and `assert`.
1186
1187         The relevant Python language `keywords` for a given statement will be
1188         NAME leaves within it. This methods puts those on a separate line.
1189
1190         `parens` holds pairs of nodes where invisible parentheses should be put.
1191         Keys hold nodes after which opening parentheses should be put, values
1192         hold nodes before which closing parentheses should be put.
1193         """
1194         normalize_invisible_parens(node, parens_after=parens)
1195         for child in node.children:
1196             if child.type == token.NAME and child.value in keywords:  # type: ignore
1197                 yield from self.line()
1198
1199             yield from self.visit(child)
1200
1201     def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
1202         """Visit a statement without nested statements."""
1203         is_suite_like = node.parent and node.parent.type in STATEMENT
1204         if is_suite_like:
1205             yield from self.line(+1)
1206             yield from self.visit_default(node)
1207             yield from self.line(-1)
1208
1209         else:
1210             yield from self.line()
1211             yield from self.visit_default(node)
1212
1213     def visit_async_stmt(self, node: Node) -> Iterator[Line]:
1214         """Visit `async def`, `async for`, `async with`."""
1215         yield from self.line()
1216
1217         children = iter(node.children)
1218         for child in children:
1219             yield from self.visit(child)
1220
1221             if child.type == token.ASYNC:
1222                 break
1223
1224         internal_stmt = next(children)
1225         for child in internal_stmt.children:
1226             yield from self.visit(child)
1227
1228     def visit_decorators(self, node: Node) -> Iterator[Line]:
1229         """Visit decorators."""
1230         for child in node.children:
1231             yield from self.line()
1232             yield from self.visit(child)
1233
1234     def visit_import_from(self, node: Node) -> Iterator[Line]:
1235         """Visit import_from and maybe put invisible parentheses.
1236
1237         This is separate from `visit_stmt` because import statements don't
1238         support arbitrary atoms and thus handling of parentheses is custom.
1239         """
1240         check_lpar = False
1241         for index, child in enumerate(node.children):
1242             if check_lpar:
1243                 if child.type == token.LPAR:
1244                     # make parentheses invisible
1245                     child.value = ""  # type: ignore
1246                     node.children[-1].value = ""  # type: ignore
1247                 else:
1248                     # insert invisible parentheses
1249                     node.insert_child(index, Leaf(token.LPAR, ""))
1250                     node.append_child(Leaf(token.RPAR, ""))
1251                 break
1252
1253             check_lpar = (
1254                 child.type == token.NAME and child.value == "import"  # type: ignore
1255             )
1256
1257         for child in node.children:
1258             yield from self.visit(child)
1259
1260     def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]:
1261         """Remove a semicolon and put the other statement on a separate line."""
1262         yield from self.line()
1263
1264     def visit_ENDMARKER(self, leaf: Leaf) -> Iterator[Line]:
1265         """End of file. Process outstanding comments and end with a newline."""
1266         yield from self.visit_default(leaf)
1267         yield from self.line()
1268
1269     def visit_unformatted(self, node: LN) -> Iterator[Line]:
1270         """Used when file contained a `# fmt: off`."""
1271         if isinstance(node, Node):
1272             for child in node.children:
1273                 yield from self.visit(child)
1274
1275         else:
1276             try:
1277                 self.current_line.append(node)
1278             except FormatOn as f_on:
1279                 f_on.trim_prefix(node)
1280                 yield from self.line()
1281                 yield from self.visit(node)
1282
1283             if node.type == token.ENDMARKER:
1284                 # somebody decided not to put a final `# fmt: on`
1285                 yield from self.line()
1286
1287     def __attrs_post_init__(self) -> None:
1288         """You are in a twisty little maze of passages."""
1289         v = self.visit_stmt
1290         Ø: Set[str] = set()
1291         self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
1292         self.visit_if_stmt = partial(v, keywords={"if", "else", "elif"}, parens={"if"})
1293         self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"})
1294         self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"})
1295         self.visit_try_stmt = partial(
1296             v, keywords={"try", "except", "else", "finally"}, parens=Ø
1297         )
1298         self.visit_except_clause = partial(v, keywords={"except"}, parens=Ø)
1299         self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø)
1300         self.visit_funcdef = partial(v, keywords={"def"}, parens=Ø)
1301         self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
1302         self.visit_async_funcdef = self.visit_async_stmt
1303         self.visit_decorated = self.visit_decorators
1304
1305
1306 IMPLICIT_TUPLE = {syms.testlist, syms.testlist_star_expr, syms.exprlist}
1307 BRACKET = {token.LPAR: token.RPAR, token.LSQB: token.RSQB, token.LBRACE: token.RBRACE}
1308 OPENING_BRACKETS = set(BRACKET.keys())
1309 CLOSING_BRACKETS = set(BRACKET.values())
1310 BRACKETS = OPENING_BRACKETS | CLOSING_BRACKETS
1311 ALWAYS_NO_SPACE = CLOSING_BRACKETS | {token.COMMA, STANDALONE_COMMENT}
1312
1313
1314 def whitespace(leaf: Leaf) -> str:  # noqa C901
1315     """Return whitespace prefix if needed for the given `leaf`."""
1316     NO = ""
1317     SPACE = " "
1318     DOUBLESPACE = "  "
1319     t = leaf.type
1320     p = leaf.parent
1321     v = leaf.value
1322     if t in ALWAYS_NO_SPACE:
1323         return NO
1324
1325     if t == token.COMMENT:
1326         return DOUBLESPACE
1327
1328     assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
1329     if t == token.COLON and p.type not in {syms.subscript, syms.subscriptlist}:
1330         return NO
1331
1332     prev = leaf.prev_sibling
1333     if not prev:
1334         prevp = preceding_leaf(p)
1335         if not prevp or prevp.type in OPENING_BRACKETS:
1336             return NO
1337
1338         if t == token.COLON:
1339             return SPACE if prevp.type == token.COMMA else NO
1340
1341         if prevp.type == token.EQUAL:
1342             if prevp.parent:
1343                 if prevp.parent.type in {
1344                     syms.arglist, syms.argument, syms.parameters, syms.varargslist
1345                 }:
1346                     return NO
1347
1348                 elif prevp.parent.type == syms.typedargslist:
1349                     # A bit hacky: if the equal sign has whitespace, it means we
1350                     # previously found it's a typed argument.  So, we're using
1351                     # that, too.
1352                     return prevp.prefix
1353
1354         elif prevp.type in STARS:
1355             if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS):
1356                 return NO
1357
1358         elif prevp.type == token.COLON:
1359             if prevp.parent and prevp.parent.type in {syms.subscript, syms.sliceop}:
1360                 return NO
1361
1362         elif (
1363             prevp.parent
1364             and prevp.parent.type == syms.factor
1365             and prevp.type in MATH_OPERATORS
1366         ):
1367             return NO
1368
1369         elif (
1370             prevp.type == token.RIGHTSHIFT
1371             and prevp.parent
1372             and prevp.parent.type == syms.shift_expr
1373             and prevp.prev_sibling
1374             and prevp.prev_sibling.type == token.NAME
1375             and prevp.prev_sibling.value == "print"  # type: ignore
1376         ):
1377             # Python 2 print chevron
1378             return NO
1379
1380     elif prev.type in OPENING_BRACKETS:
1381         return NO
1382
1383     if p.type in {syms.parameters, syms.arglist}:
1384         # untyped function signatures or calls
1385         if not prev or prev.type != token.COMMA:
1386             return NO
1387
1388     elif p.type == syms.varargslist:
1389         # lambdas
1390         if prev and prev.type != token.COMMA:
1391             return NO
1392
1393     elif p.type == syms.typedargslist:
1394         # typed function signatures
1395         if not prev:
1396             return NO
1397
1398         if t == token.EQUAL:
1399             if prev.type != syms.tname:
1400                 return NO
1401
1402         elif prev.type == token.EQUAL:
1403             # A bit hacky: if the equal sign has whitespace, it means we
1404             # previously found it's a typed argument.  So, we're using that, too.
1405             return prev.prefix
1406
1407         elif prev.type != token.COMMA:
1408             return NO
1409
1410     elif p.type == syms.tname:
1411         # type names
1412         if not prev:
1413             prevp = preceding_leaf(p)
1414             if not prevp or prevp.type != token.COMMA:
1415                 return NO
1416
1417     elif p.type == syms.trailer:
1418         # attributes and calls
1419         if t == token.LPAR or t == token.RPAR:
1420             return NO
1421
1422         if not prev:
1423             if t == token.DOT:
1424                 prevp = preceding_leaf(p)
1425                 if not prevp or prevp.type != token.NUMBER:
1426                     return NO
1427
1428             elif t == token.LSQB:
1429                 return NO
1430
1431         elif prev.type != token.COMMA:
1432             return NO
1433
1434     elif p.type == syms.argument:
1435         # single argument
1436         if t == token.EQUAL:
1437             return NO
1438
1439         if not prev:
1440             prevp = preceding_leaf(p)
1441             if not prevp or prevp.type == token.LPAR:
1442                 return NO
1443
1444         elif prev.type in {token.EQUAL} | STARS:
1445             return NO
1446
1447     elif p.type == syms.decorator:
1448         # decorators
1449         return NO
1450
1451     elif p.type == syms.dotted_name:
1452         if prev:
1453             return NO
1454
1455         prevp = preceding_leaf(p)
1456         if not prevp or prevp.type == token.AT or prevp.type == token.DOT:
1457             return NO
1458
1459     elif p.type == syms.classdef:
1460         if t == token.LPAR:
1461             return NO
1462
1463         if prev and prev.type == token.LPAR:
1464             return NO
1465
1466     elif p.type == syms.subscript:
1467         # indexing
1468         if not prev:
1469             assert p.parent is not None, "subscripts are always parented"
1470             if p.parent.type == syms.subscriptlist:
1471                 return SPACE
1472
1473             return NO
1474
1475         else:
1476             return NO
1477
1478     elif p.type == syms.atom:
1479         if prev and t == token.DOT:
1480             # dots, but not the first one.
1481             return NO
1482
1483     elif p.type == syms.dictsetmaker:
1484         # dict unpacking
1485         if prev and prev.type == token.DOUBLESTAR:
1486             return NO
1487
1488     elif p.type in {syms.factor, syms.star_expr}:
1489         # unary ops
1490         if not prev:
1491             prevp = preceding_leaf(p)
1492             if not prevp or prevp.type in OPENING_BRACKETS:
1493                 return NO
1494
1495             prevp_parent = prevp.parent
1496             assert prevp_parent is not None
1497             if (
1498                 prevp.type == token.COLON
1499                 and prevp_parent.type in {syms.subscript, syms.sliceop}
1500             ):
1501                 return NO
1502
1503             elif prevp.type == token.EQUAL and prevp_parent.type == syms.argument:
1504                 return NO
1505
1506         elif t == token.NAME or t == token.NUMBER:
1507             return NO
1508
1509     elif p.type == syms.import_from:
1510         if t == token.DOT:
1511             if prev and prev.type == token.DOT:
1512                 return NO
1513
1514         elif t == token.NAME:
1515             if v == "import":
1516                 return SPACE
1517
1518             if prev and prev.type == token.DOT:
1519                 return NO
1520
1521     elif p.type == syms.sliceop:
1522         return NO
1523
1524     return SPACE
1525
1526
1527 def preceding_leaf(node: Optional[LN]) -> Optional[Leaf]:
1528     """Return the first leaf that precedes `node`, if any."""
1529     while node:
1530         res = node.prev_sibling
1531         if res:
1532             if isinstance(res, Leaf):
1533                 return res
1534
1535             try:
1536                 return list(res.leaves())[-1]
1537
1538             except IndexError:
1539                 return None
1540
1541         node = node.parent
1542     return None
1543
1544
1545 def is_split_after_delimiter(leaf: Leaf, previous: Leaf = None) -> int:
1546     """Return the priority of the `leaf` delimiter, given a line break after it.
1547
1548     The delimiter priorities returned here are from those delimiters that would
1549     cause a line break after themselves.
1550
1551     Higher numbers are higher priority.
1552     """
1553     if leaf.type == token.COMMA:
1554         return COMMA_PRIORITY
1555
1556     return 0
1557
1558
1559 def is_split_before_delimiter(leaf: Leaf, previous: Leaf = None) -> int:
1560     """Return the priority of the `leaf` delimiter, given a line before after it.
1561
1562     The delimiter priorities returned here are from those delimiters that would
1563     cause a line break before themselves.
1564
1565     Higher numbers are higher priority.
1566     """
1567     if is_vararg(leaf, within=VARARGS_PARENTS | UNPACKING_PARENTS):
1568         # * and ** might also be MATH_OPERATORS but in this case they are not.
1569         # Don't treat them as a delimiter.
1570         return 0
1571
1572     if (
1573         leaf.type in MATH_OPERATORS
1574         and leaf.parent
1575         and leaf.parent.type not in {syms.factor, syms.star_expr}
1576     ):
1577         return MATH_PRIORITY
1578
1579     if leaf.type in COMPARATORS:
1580         return COMPARATOR_PRIORITY
1581
1582     if (
1583         leaf.type == token.STRING
1584         and previous is not None
1585         and previous.type == token.STRING
1586     ):
1587         return STRING_PRIORITY
1588
1589     if (
1590         leaf.type == token.NAME
1591         and leaf.value == "for"
1592         and leaf.parent
1593         and leaf.parent.type in {syms.comp_for, syms.old_comp_for}
1594     ):
1595         return COMPREHENSION_PRIORITY
1596
1597     if (
1598         leaf.type == token.NAME
1599         and leaf.value == "if"
1600         and leaf.parent
1601         and leaf.parent.type in {syms.comp_if, syms.old_comp_if}
1602     ):
1603         return COMPREHENSION_PRIORITY
1604
1605     if leaf.type == token.NAME and leaf.value in LOGIC_OPERATORS and leaf.parent:
1606         return LOGIC_PRIORITY
1607
1608     return 0
1609
1610
1611 def generate_comments(leaf: Leaf) -> Iterator[Leaf]:
1612     """Clean the prefix of the `leaf` and generate comments from it, if any.
1613
1614     Comments in lib2to3 are shoved into the whitespace prefix.  This happens
1615     in `pgen2/driver.py:Driver.parse_tokens()`.  This was a brilliant implementation
1616     move because it does away with modifying the grammar to include all the
1617     possible places in which comments can be placed.
1618
1619     The sad consequence for us though is that comments don't "belong" anywhere.
1620     This is why this function generates simple parentless Leaf objects for
1621     comments.  We simply don't know what the correct parent should be.
1622
1623     No matter though, we can live without this.  We really only need to
1624     differentiate between inline and standalone comments.  The latter don't
1625     share the line with any code.
1626
1627     Inline comments are emitted as regular token.COMMENT leaves.  Standalone
1628     are emitted with a fake STANDALONE_COMMENT token identifier.
1629     """
1630     p = leaf.prefix
1631     if not p:
1632         return
1633
1634     if "#" not in p:
1635         return
1636
1637     consumed = 0
1638     nlines = 0
1639     for index, line in enumerate(p.split("\n")):
1640         consumed += len(line) + 1  # adding the length of the split '\n'
1641         line = line.lstrip()
1642         if not line:
1643             nlines += 1
1644         if not line.startswith("#"):
1645             continue
1646
1647         if index == 0 and leaf.type != token.ENDMARKER:
1648             comment_type = token.COMMENT  # simple trailing comment
1649         else:
1650             comment_type = STANDALONE_COMMENT
1651         comment = make_comment(line)
1652         yield Leaf(comment_type, comment, prefix="\n" * nlines)
1653
1654         if comment in {"# fmt: on", "# yapf: enable"}:
1655             raise FormatOn(consumed)
1656
1657         if comment in {"# fmt: off", "# yapf: disable"}:
1658             if comment_type == STANDALONE_COMMENT:
1659                 raise FormatOff(consumed)
1660
1661             prev = preceding_leaf(leaf)
1662             if not prev or prev.type in WHITESPACE:  # standalone comment in disguise
1663                 raise FormatOff(consumed)
1664
1665         nlines = 0
1666
1667
1668 def make_comment(content: str) -> str:
1669     """Return a consistently formatted comment from the given `content` string.
1670
1671     All comments (except for "##", "#!", "#:") should have a single space between
1672     the hash sign and the content.
1673
1674     If `content` didn't start with a hash sign, one is provided.
1675     """
1676     content = content.rstrip()
1677     if not content:
1678         return "#"
1679
1680     if content[0] == "#":
1681         content = content[1:]
1682     if content and content[0] not in " !:#":
1683         content = " " + content
1684     return "#" + content
1685
1686
1687 def split_line(
1688     line: Line, line_length: int, inner: bool = False, py36: bool = False
1689 ) -> Iterator[Line]:
1690     """Split a `line` into potentially many lines.
1691
1692     They should fit in the allotted `line_length` but might not be able to.
1693     `inner` signifies that there were a pair of brackets somewhere around the
1694     current `line`, possibly transitively. This means we can fallback to splitting
1695     by delimiters if the LHS/RHS don't yield any results.
1696
1697     If `py36` is True, splitting may generate syntax that is only compatible
1698     with Python 3.6 and later.
1699     """
1700     if isinstance(line, UnformattedLines) or line.is_comment:
1701         yield line
1702         return
1703
1704     line_str = str(line).strip("\n")
1705     if (
1706         len(line_str) <= line_length
1707         and "\n" not in line_str  # multiline strings
1708         and not line.contains_standalone_comments()
1709     ):
1710         yield line
1711         return
1712
1713     split_funcs: List[SplitFunc]
1714     if line.is_def:
1715         split_funcs = [left_hand_split]
1716     elif line.inside_brackets:
1717         split_funcs = [delimiter_split, standalone_comment_split, right_hand_split]
1718     else:
1719         split_funcs = [right_hand_split]
1720     for split_func in split_funcs:
1721         # We are accumulating lines in `result` because we might want to abort
1722         # mission and return the original line in the end, or attempt a different
1723         # split altogether.
1724         result: List[Line] = []
1725         try:
1726             for l in split_func(line, py36):
1727                 if str(l).strip("\n") == line_str:
1728                     raise CannotSplit("Split function returned an unchanged result")
1729
1730                 result.extend(
1731                     split_line(l, line_length=line_length, inner=True, py36=py36)
1732                 )
1733         except CannotSplit as cs:
1734             continue
1735
1736         else:
1737             yield from result
1738             break
1739
1740     else:
1741         yield line
1742
1743
1744 def left_hand_split(line: Line, py36: bool = False) -> Iterator[Line]:
1745     """Split line into many lines, starting with the first matching bracket pair.
1746
1747     Note: this usually looks weird, only use this for function definitions.
1748     Prefer RHS otherwise.
1749     """
1750     head = Line(depth=line.depth)
1751     body = Line(depth=line.depth + 1, inside_brackets=True)
1752     tail = Line(depth=line.depth)
1753     tail_leaves: List[Leaf] = []
1754     body_leaves: List[Leaf] = []
1755     head_leaves: List[Leaf] = []
1756     current_leaves = head_leaves
1757     matching_bracket = None
1758     for leaf in line.leaves:
1759         if (
1760             current_leaves is body_leaves
1761             and leaf.type in CLOSING_BRACKETS
1762             and leaf.opening_bracket is matching_bracket
1763         ):
1764             current_leaves = tail_leaves if body_leaves else head_leaves
1765         current_leaves.append(leaf)
1766         if current_leaves is head_leaves:
1767             if leaf.type in OPENING_BRACKETS:
1768                 matching_bracket = leaf
1769                 current_leaves = body_leaves
1770     # Since body is a new indent level, remove spurious leading whitespace.
1771     if body_leaves:
1772         normalize_prefix(body_leaves[0], inside_brackets=True)
1773     # Build the new lines.
1774     for result, leaves in (head, head_leaves), (body, body_leaves), (tail, tail_leaves):
1775         for leaf in leaves:
1776             result.append(leaf, preformatted=True)
1777             for comment_after in line.comments_after(leaf):
1778                 result.append(comment_after, preformatted=True)
1779     bracket_split_succeeded_or_raise(head, body, tail)
1780     for result in (head, body, tail):
1781         if result:
1782             yield result
1783
1784
1785 def right_hand_split(
1786     line: Line, py36: bool = False, omit: Collection[LeafID] = ()
1787 ) -> Iterator[Line]:
1788     """Split line into many lines, starting with the last matching bracket pair."""
1789     head = Line(depth=line.depth)
1790     body = Line(depth=line.depth + 1, inside_brackets=True)
1791     tail = Line(depth=line.depth)
1792     tail_leaves: List[Leaf] = []
1793     body_leaves: List[Leaf] = []
1794     head_leaves: List[Leaf] = []
1795     current_leaves = tail_leaves
1796     opening_bracket = None
1797     closing_bracket = None
1798     for leaf in reversed(line.leaves):
1799         if current_leaves is body_leaves:
1800             if leaf is opening_bracket:
1801                 current_leaves = head_leaves if body_leaves else tail_leaves
1802         current_leaves.append(leaf)
1803         if current_leaves is tail_leaves:
1804             if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit:
1805                 opening_bracket = leaf.opening_bracket
1806                 closing_bracket = leaf
1807                 current_leaves = body_leaves
1808     tail_leaves.reverse()
1809     body_leaves.reverse()
1810     head_leaves.reverse()
1811     # Since body is a new indent level, remove spurious leading whitespace.
1812     if body_leaves:
1813         normalize_prefix(body_leaves[0], inside_brackets=True)
1814     elif not head_leaves:
1815         # No `head` and no `body` means the split failed. `tail` has all content.
1816         raise CannotSplit("No brackets found")
1817
1818     # Build the new lines.
1819     for result, leaves in (head, head_leaves), (body, body_leaves), (tail, tail_leaves):
1820         for leaf in leaves:
1821             result.append(leaf, preformatted=True)
1822             for comment_after in line.comments_after(leaf):
1823                 result.append(comment_after, preformatted=True)
1824     bracket_split_succeeded_or_raise(head, body, tail)
1825     assert opening_bracket and closing_bracket
1826     if (
1827         opening_bracket.type == token.LPAR
1828         and not opening_bracket.value
1829         and closing_bracket.type == token.RPAR
1830         and not closing_bracket.value
1831     ):
1832         # These parens were optional. If there aren't any delimiters or standalone
1833         # comments in the body, they were unnecessary and another split without
1834         # them should be attempted.
1835         if not (
1836             body.bracket_tracker.delimiters or line.contains_standalone_comments(0)
1837         ):
1838             omit = {id(closing_bracket), *omit}
1839             yield from right_hand_split(line, py36=py36, omit=omit)
1840             return
1841
1842     ensure_visible(opening_bracket)
1843     ensure_visible(closing_bracket)
1844     for result in (head, body, tail):
1845         if result:
1846             yield result
1847
1848
1849 def bracket_split_succeeded_or_raise(head: Line, body: Line, tail: Line) -> None:
1850     """Raise :exc:`CannotSplit` if the last left- or right-hand split failed.
1851
1852     Do nothing otherwise.
1853
1854     A left- or right-hand split is based on a pair of brackets. Content before
1855     (and including) the opening bracket is left on one line, content inside the
1856     brackets is put on a separate line, and finally content starting with and
1857     following the closing bracket is put on a separate line.
1858
1859     Those are called `head`, `body`, and `tail`, respectively. If the split
1860     produced the same line (all content in `head`) or ended up with an empty `body`
1861     and the `tail` is just the closing bracket, then it's considered failed.
1862     """
1863     tail_len = len(str(tail).strip())
1864     if not body:
1865         if tail_len == 0:
1866             raise CannotSplit("Splitting brackets produced the same line")
1867
1868         elif tail_len < 3:
1869             raise CannotSplit(
1870                 f"Splitting brackets on an empty body to save "
1871                 f"{tail_len} characters is not worth it"
1872             )
1873
1874
1875 def dont_increase_indentation(split_func: SplitFunc) -> SplitFunc:
1876     """Normalize prefix of the first leaf in every line returned by `split_func`.
1877
1878     This is a decorator over relevant split functions.
1879     """
1880
1881     @wraps(split_func)
1882     def split_wrapper(line: Line, py36: bool = False) -> Iterator[Line]:
1883         for l in split_func(line, py36):
1884             normalize_prefix(l.leaves[0], inside_brackets=True)
1885             yield l
1886
1887     return split_wrapper
1888
1889
1890 @dont_increase_indentation
1891 def delimiter_split(line: Line, py36: bool = False) -> Iterator[Line]:
1892     """Split according to delimiters of the highest priority.
1893
1894     If `py36` is True, the split will add trailing commas also in function
1895     signatures that contain `*` and `**`.
1896     """
1897     try:
1898         last_leaf = line.leaves[-1]
1899     except IndexError:
1900         raise CannotSplit("Line empty")
1901
1902     delimiters = line.bracket_tracker.delimiters
1903     try:
1904         delimiter_priority = line.bracket_tracker.max_delimiter_priority(
1905             exclude={id(last_leaf)}
1906         )
1907     except ValueError:
1908         raise CannotSplit("No delimiters found")
1909
1910     current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
1911     lowest_depth = sys.maxsize
1912     trailing_comma_safe = True
1913
1914     def append_to_line(leaf: Leaf) -> Iterator[Line]:
1915         """Append `leaf` to current line or to new line if appending impossible."""
1916         nonlocal current_line
1917         try:
1918             current_line.append_safe(leaf, preformatted=True)
1919         except ValueError as ve:
1920             yield current_line
1921
1922             current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
1923             current_line.append(leaf)
1924
1925     for leaf in line.leaves:
1926         yield from append_to_line(leaf)
1927
1928         for comment_after in line.comments_after(leaf):
1929             yield from append_to_line(comment_after)
1930
1931         lowest_depth = min(lowest_depth, leaf.bracket_depth)
1932         if (
1933             leaf.bracket_depth == lowest_depth
1934             and is_vararg(leaf, within=VARARGS_PARENTS)
1935         ):
1936             trailing_comma_safe = trailing_comma_safe and py36
1937         leaf_priority = delimiters.get(id(leaf))
1938         if leaf_priority == delimiter_priority:
1939             yield current_line
1940
1941             current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
1942     if current_line:
1943         if (
1944             trailing_comma_safe
1945             and delimiter_priority == COMMA_PRIORITY
1946             and current_line.leaves[-1].type != token.COMMA
1947             and current_line.leaves[-1].type != STANDALONE_COMMENT
1948         ):
1949             current_line.append(Leaf(token.COMMA, ","))
1950         yield current_line
1951
1952
1953 @dont_increase_indentation
1954 def standalone_comment_split(line: Line, py36: bool = False) -> Iterator[Line]:
1955     """Split standalone comments from the rest of the line."""
1956     if not line.contains_standalone_comments(0):
1957         raise CannotSplit("Line does not have any standalone comments")
1958
1959     current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
1960
1961     def append_to_line(leaf: Leaf) -> Iterator[Line]:
1962         """Append `leaf` to current line or to new line if appending impossible."""
1963         nonlocal current_line
1964         try:
1965             current_line.append_safe(leaf, preformatted=True)
1966         except ValueError as ve:
1967             yield current_line
1968
1969             current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
1970             current_line.append(leaf)
1971
1972     for leaf in line.leaves:
1973         yield from append_to_line(leaf)
1974
1975         for comment_after in line.comments_after(leaf):
1976             yield from append_to_line(comment_after)
1977
1978     if current_line:
1979         yield current_line
1980
1981
1982 def is_import(leaf: Leaf) -> bool:
1983     """Return True if the given leaf starts an import statement."""
1984     p = leaf.parent
1985     t = leaf.type
1986     v = leaf.value
1987     return bool(
1988         t == token.NAME
1989         and (
1990             (v == "import" and p and p.type == syms.import_name)
1991             or (v == "from" and p and p.type == syms.import_from)
1992         )
1993     )
1994
1995
1996 def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
1997     """Leave existing extra newlines if not `inside_brackets`. Remove everything
1998     else.
1999
2000     Note: don't use backslashes for formatting or you'll lose your voting rights.
2001     """
2002     if not inside_brackets:
2003         spl = leaf.prefix.split("#")
2004         if "\\" not in spl[0]:
2005             nl_count = spl[-1].count("\n")
2006             if len(spl) > 1:
2007                 nl_count -= 1
2008             leaf.prefix = "\n" * nl_count
2009             return
2010
2011     leaf.prefix = ""
2012
2013
2014 def normalize_string_quotes(leaf: Leaf) -> None:
2015     """Prefer double quotes but only if it doesn't cause more escaping.
2016
2017     Adds or removes backslashes as appropriate. Doesn't parse and fix
2018     strings nested in f-strings (yet).
2019
2020     Note: Mutates its argument.
2021     """
2022     value = leaf.value.lstrip("furbFURB")
2023     if value[:3] == '"""':
2024         return
2025
2026     elif value[:3] == "'''":
2027         orig_quote = "'''"
2028         new_quote = '"""'
2029     elif value[0] == '"':
2030         orig_quote = '"'
2031         new_quote = "'"
2032     else:
2033         orig_quote = "'"
2034         new_quote = '"'
2035     first_quote_pos = leaf.value.find(orig_quote)
2036     if first_quote_pos == -1:
2037         return  # There's an internal error
2038
2039     prefix = leaf.value[:first_quote_pos]
2040     unescaped_new_quote = re.compile(rf"(([^\\]|^)(\\\\)*){new_quote}")
2041     escaped_new_quote = re.compile(rf"([^\\]|^)\\(\\\\)*{new_quote}")
2042     escaped_orig_quote = re.compile(rf"([^\\]|^)\\(\\\\)*{orig_quote}")
2043     body = leaf.value[first_quote_pos + len(orig_quote):-len(orig_quote)]
2044     if "r" in prefix.casefold():
2045         if unescaped_new_quote.search(body):
2046             # There's at least one unescaped new_quote in this raw string
2047             # so converting is impossible
2048             return
2049
2050         # Do not introduce or remove backslashes in raw strings
2051         new_body = body
2052     else:
2053         # remove unnecessary quotes
2054         new_body = sub_twice(escaped_new_quote, rf"\1\2{new_quote}", body)
2055         if body != new_body:
2056             # Consider the string without unnecessary quotes as the original
2057             body = new_body
2058             leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
2059         new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
2060         new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
2061     if new_quote == '"""' and new_body[-1] == '"':
2062         # edge case:
2063         new_body = new_body[:-1] + '\\"'
2064     orig_escape_count = body.count("\\")
2065     new_escape_count = new_body.count("\\")
2066     if new_escape_count > orig_escape_count:
2067         return  # Do not introduce more escaping
2068
2069     if new_escape_count == orig_escape_count and orig_quote == '"':
2070         return  # Prefer double quotes
2071
2072     leaf.value = f"{prefix}{new_quote}{new_body}{new_quote}"
2073
2074
2075 def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None:
2076     """Make existing optional parentheses invisible or create new ones.
2077
2078     Standardizes on visible parentheses for single-element tuples, and keeps
2079     existing visible parentheses for other tuples and generator expressions.
2080     """
2081     check_lpar = False
2082     for child in list(node.children):
2083         if check_lpar:
2084             if child.type == syms.atom:
2085                 if not (
2086                     is_empty_tuple(child)
2087                     or is_one_tuple(child)
2088                     or max_delimiter_priority_in_atom(child) >= COMMA_PRIORITY
2089                 ):
2090                     first = child.children[0]
2091                     last = child.children[-1]
2092                     if first.type == token.LPAR and last.type == token.RPAR:
2093                         # make parentheses invisible
2094                         first.value = ""  # type: ignore
2095                         last.value = ""  # type: ignore
2096             elif is_one_tuple(child):
2097                 # wrap child in visible parentheses
2098                 lpar = Leaf(token.LPAR, "(")
2099                 rpar = Leaf(token.RPAR, ")")
2100                 index = child.remove() or 0
2101                 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2102             else:
2103                 # wrap child in invisible parentheses
2104                 lpar = Leaf(token.LPAR, "")
2105                 rpar = Leaf(token.RPAR, "")
2106                 index = child.remove() or 0
2107                 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2108
2109         check_lpar = isinstance(child, Leaf) and child.value in parens_after
2110
2111
2112 def is_empty_tuple(node: LN) -> bool:
2113     """Return True if `node` holds an empty tuple."""
2114     return (
2115         node.type == syms.atom
2116         and len(node.children) == 2
2117         and node.children[0].type == token.LPAR
2118         and node.children[1].type == token.RPAR
2119     )
2120
2121
2122 def is_one_tuple(node: LN) -> bool:
2123     """Return True if `node` holds a tuple with one element, with or without parens."""
2124     if node.type == syms.atom:
2125         if len(node.children) != 3:
2126             return False
2127
2128         lpar, gexp, rpar = node.children
2129         if not (
2130             lpar.type == token.LPAR
2131             and gexp.type == syms.testlist_gexp
2132             and rpar.type == token.RPAR
2133         ):
2134             return False
2135
2136         return len(gexp.children) == 2 and gexp.children[1].type == token.COMMA
2137
2138     return (
2139         node.type in IMPLICIT_TUPLE
2140         and len(node.children) == 2
2141         and node.children[1].type == token.COMMA
2142     )
2143
2144
2145 def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool:
2146     """Return True if `leaf` is a star or double star in a vararg or kwarg.
2147
2148     If `within` includes VARARGS_PARENTS, this applies to function signatures.
2149     If `within` includes COLLECTION_LIBERALS_PARENTS, it applies to right
2150     hand-side extended iterable unpacking (PEP 3132) and additional unpacking
2151     generalizations (PEP 448).
2152     """
2153     if leaf.type not in STARS or not leaf.parent:
2154         return False
2155
2156     p = leaf.parent
2157     if p.type == syms.star_expr:
2158         # Star expressions are also used as assignment targets in extended
2159         # iterable unpacking (PEP 3132).  See what its parent is instead.
2160         if not p.parent:
2161             return False
2162
2163         p = p.parent
2164
2165     return p.type in within
2166
2167
2168 def max_delimiter_priority_in_atom(node: LN) -> int:
2169     """Return maximum delimiter priority inside `node`.
2170
2171     This is specific to atoms with contents contained in a pair of parentheses.
2172     If `node` isn't an atom or there are no enclosing parentheses, returns 0.
2173     """
2174     if node.type != syms.atom:
2175         return 0
2176
2177     first = node.children[0]
2178     last = node.children[-1]
2179     if not (first.type == token.LPAR and last.type == token.RPAR):
2180         return 0
2181
2182     bt = BracketTracker()
2183     for c in node.children[1:-1]:
2184         if isinstance(c, Leaf):
2185             bt.mark(c)
2186         else:
2187             for leaf in c.leaves():
2188                 bt.mark(leaf)
2189     try:
2190         return bt.max_delimiter_priority()
2191
2192     except ValueError:
2193         return 0
2194
2195
2196 def ensure_visible(leaf: Leaf) -> None:
2197     """Make sure parentheses are visible.
2198
2199     They could be invisible as part of some statements (see
2200     :func:`normalize_invible_parens` and :func:`visit_import_from`).
2201     """
2202     if leaf.type == token.LPAR:
2203         leaf.value = "("
2204     elif leaf.type == token.RPAR:
2205         leaf.value = ")"
2206
2207
2208 def is_python36(node: Node) -> bool:
2209     """Return True if the current file is using Python 3.6+ features.
2210
2211     Currently looking for:
2212     - f-strings; and
2213     - trailing commas after * or ** in function signatures.
2214     """
2215     for n in node.pre_order():
2216         if n.type == token.STRING:
2217             value_head = n.value[:2]  # type: ignore
2218             if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
2219                 return True
2220
2221         elif (
2222             n.type == syms.typedargslist
2223             and n.children
2224             and n.children[-1].type == token.COMMA
2225         ):
2226             for ch in n.children:
2227                 if ch.type in STARS:
2228                     return True
2229
2230     return False
2231
2232
2233 PYTHON_EXTENSIONS = {".py"}
2234 BLACKLISTED_DIRECTORIES = {
2235     "build", "buck-out", "dist", "_build", ".git", ".hg", ".mypy_cache", ".tox", ".venv"
2236 }
2237
2238
2239 def gen_python_files_in_dir(path: Path) -> Iterator[Path]:
2240     """Generate all files under `path` which aren't under BLACKLISTED_DIRECTORIES
2241     and have one of the PYTHON_EXTENSIONS.
2242     """
2243     for child in path.iterdir():
2244         if child.is_dir():
2245             if child.name in BLACKLISTED_DIRECTORIES:
2246                 continue
2247
2248             yield from gen_python_files_in_dir(child)
2249
2250         elif child.suffix in PYTHON_EXTENSIONS:
2251             yield child
2252
2253
2254 @dataclass
2255 class Report:
2256     """Provides a reformatting counter. Can be rendered with `str(report)`."""
2257     check: bool = False
2258     quiet: bool = False
2259     change_count: int = 0
2260     same_count: int = 0
2261     failure_count: int = 0
2262
2263     def done(self, src: Path, changed: Changed) -> None:
2264         """Increment the counter for successful reformatting. Write out a message."""
2265         if changed is Changed.YES:
2266             reformatted = "would reformat" if self.check else "reformatted"
2267             if not self.quiet:
2268                 out(f"{reformatted} {src}")
2269             self.change_count += 1
2270         else:
2271             if not self.quiet:
2272                 if changed is Changed.NO:
2273                     msg = f"{src} already well formatted, good job."
2274                 else:
2275                     msg = f"{src} wasn't modified on disk since last run."
2276                 out(msg, bold=False)
2277             self.same_count += 1
2278
2279     def failed(self, src: Path, message: str) -> None:
2280         """Increment the counter for failed reformatting. Write out a message."""
2281         err(f"error: cannot format {src}: {message}")
2282         self.failure_count += 1
2283
2284     @property
2285     def return_code(self) -> int:
2286         """Return the exit code that the app should use.
2287
2288         This considers the current state of changed files and failures:
2289         - if there were any failures, return 123;
2290         - if any files were changed and --check is being used, return 1;
2291         - otherwise return 0.
2292         """
2293         # According to http://tldp.org/LDP/abs/html/exitcodes.html starting with
2294         # 126 we have special returncodes reserved by the shell.
2295         if self.failure_count:
2296             return 123
2297
2298         elif self.change_count and self.check:
2299             return 1
2300
2301         return 0
2302
2303     def __str__(self) -> str:
2304         """Render a color report of the current state.
2305
2306         Use `click.unstyle` to remove colors.
2307         """
2308         if self.check:
2309             reformatted = "would be reformatted"
2310             unchanged = "would be left unchanged"
2311             failed = "would fail to reformat"
2312         else:
2313             reformatted = "reformatted"
2314             unchanged = "left unchanged"
2315             failed = "failed to reformat"
2316         report = []
2317         if self.change_count:
2318             s = "s" if self.change_count > 1 else ""
2319             report.append(
2320                 click.style(f"{self.change_count} file{s} {reformatted}", bold=True)
2321             )
2322         if self.same_count:
2323             s = "s" if self.same_count > 1 else ""
2324             report.append(f"{self.same_count} file{s} {unchanged}")
2325         if self.failure_count:
2326             s = "s" if self.failure_count > 1 else ""
2327             report.append(
2328                 click.style(f"{self.failure_count} file{s} {failed}", fg="red")
2329             )
2330         return ", ".join(report) + "."
2331
2332
2333 def assert_equivalent(src: str, dst: str) -> None:
2334     """Raise AssertionError if `src` and `dst` aren't equivalent."""
2335
2336     import ast
2337     import traceback
2338
2339     def _v(node: ast.AST, depth: int = 0) -> Iterator[str]:
2340         """Simple visitor generating strings to compare ASTs by content."""
2341         yield f"{'  ' * depth}{node.__class__.__name__}("
2342
2343         for field in sorted(node._fields):
2344             try:
2345                 value = getattr(node, field)
2346             except AttributeError:
2347                 continue
2348
2349             yield f"{'  ' * (depth+1)}{field}="
2350
2351             if isinstance(value, list):
2352                 for item in value:
2353                     if isinstance(item, ast.AST):
2354                         yield from _v(item, depth + 2)
2355
2356             elif isinstance(value, ast.AST):
2357                 yield from _v(value, depth + 2)
2358
2359             else:
2360                 yield f"{'  ' * (depth+2)}{value!r},  # {value.__class__.__name__}"
2361
2362         yield f"{'  ' * depth})  # /{node.__class__.__name__}"
2363
2364     try:
2365         src_ast = ast.parse(src)
2366     except Exception as exc:
2367         major, minor = sys.version_info[:2]
2368         raise AssertionError(
2369             f"cannot use --safe with this file; failed to parse source file "
2370             f"with Python {major}.{minor}'s builtin AST. Re-run with --fast "
2371             f"or stop using deprecated Python 2 syntax. AST error message: {exc}"
2372         )
2373
2374     try:
2375         dst_ast = ast.parse(dst)
2376     except Exception as exc:
2377         log = dump_to_file("".join(traceback.format_tb(exc.__traceback__)), dst)
2378         raise AssertionError(
2379             f"INTERNAL ERROR: Black produced invalid code: {exc}. "
2380             f"Please report a bug on https://github.com/ambv/black/issues.  "
2381             f"This invalid output might be helpful: {log}"
2382         ) from None
2383
2384     src_ast_str = "\n".join(_v(src_ast))
2385     dst_ast_str = "\n".join(_v(dst_ast))
2386     if src_ast_str != dst_ast_str:
2387         log = dump_to_file(diff(src_ast_str, dst_ast_str, "src", "dst"))
2388         raise AssertionError(
2389             f"INTERNAL ERROR: Black produced code that is not equivalent to "
2390             f"the source.  "
2391             f"Please report a bug on https://github.com/ambv/black/issues.  "
2392             f"This diff might be helpful: {log}"
2393         ) from None
2394
2395
2396 def assert_stable(src: str, dst: str, line_length: int) -> None:
2397     """Raise AssertionError if `dst` reformats differently the second time."""
2398     newdst = format_str(dst, line_length=line_length)
2399     if dst != newdst:
2400         log = dump_to_file(
2401             diff(src, dst, "source", "first pass"),
2402             diff(dst, newdst, "first pass", "second pass"),
2403         )
2404         raise AssertionError(
2405             f"INTERNAL ERROR: Black produced different code on the second pass "
2406             f"of the formatter.  "
2407             f"Please report a bug on https://github.com/ambv/black/issues.  "
2408             f"This diff might be helpful: {log}"
2409         ) from None
2410
2411
2412 def dump_to_file(*output: str) -> str:
2413     """Dump `output` to a temporary file. Return path to the file."""
2414     import tempfile
2415
2416     with tempfile.NamedTemporaryFile(
2417         mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8"
2418     ) as f:
2419         for lines in output:
2420             f.write(lines)
2421             if lines and lines[-1] != "\n":
2422                 f.write("\n")
2423     return f.name
2424
2425
2426 def diff(a: str, b: str, a_name: str, b_name: str) -> str:
2427     """Return a unified diff string between strings `a` and `b`."""
2428     import difflib
2429
2430     a_lines = [line + "\n" for line in a.split("\n")]
2431     b_lines = [line + "\n" for line in b.split("\n")]
2432     return "".join(
2433         difflib.unified_diff(a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5)
2434     )
2435
2436
2437 def cancel(tasks: List[asyncio.Task]) -> None:
2438     """asyncio signal handler that cancels all `tasks` and reports to stderr."""
2439     err("Aborted!")
2440     for task in tasks:
2441         task.cancel()
2442
2443
2444 def shutdown(loop: BaseEventLoop) -> None:
2445     """Cancel all pending tasks on `loop`, wait for them, and close the loop."""
2446     try:
2447         # This part is borrowed from asyncio/runners.py in Python 3.7b2.
2448         to_cancel = [task for task in asyncio.Task.all_tasks(loop) if not task.done()]
2449         if not to_cancel:
2450             return
2451
2452         for task in to_cancel:
2453             task.cancel()
2454         loop.run_until_complete(
2455             asyncio.gather(*to_cancel, loop=loop, return_exceptions=True)
2456         )
2457     finally:
2458         # `concurrent.futures.Future` objects cannot be cancelled once they
2459         # are already running. There might be some when the `shutdown()` happened.
2460         # Silence their logger's spew about the event loop being closed.
2461         cf_logger = logging.getLogger("concurrent.futures")
2462         cf_logger.setLevel(logging.CRITICAL)
2463         loop.close()
2464
2465
2466 def sub_twice(regex: Pattern[str], replacement: str, original: str) -> str:
2467     """Replace `regex` with `replacement` twice on `original`.
2468
2469     This is used by string normalization to perform replaces on
2470     overlapping matches.
2471     """
2472     return regex.sub(replacement, regex.sub(replacement, original))
2473
2474
2475 CACHE_DIR = Path(user_cache_dir("black", version=__version__))
2476
2477
2478 def get_cache_file(line_length: int) -> Path:
2479     return CACHE_DIR / f"cache.{line_length}.pickle"
2480
2481
2482 def read_cache(line_length: int) -> Cache:
2483     """Read the cache if it exists and is well formed.
2484
2485     If it is not well formed, the call to write_cache later should resolve the issue.
2486     """
2487     cache_file = get_cache_file(line_length)
2488     if not cache_file.exists():
2489         return {}
2490
2491     with cache_file.open("rb") as fobj:
2492         try:
2493             cache: Cache = pickle.load(fobj)
2494         except pickle.UnpicklingError:
2495             return {}
2496
2497     return cache
2498
2499
2500 def get_cache_info(path: Path) -> CacheInfo:
2501     """Return the information used to check if a file is already formatted or not."""
2502     stat = path.stat()
2503     return stat.st_mtime, stat.st_size
2504
2505
2506 def filter_cached(
2507     cache: Cache, sources: Iterable[Path]
2508 ) -> Tuple[List[Path], List[Path]]:
2509     """Split a list of paths into two.
2510
2511     The first list contains paths of files that modified on disk or are not in the
2512     cache. The other list contains paths to non-modified files.
2513     """
2514     todo, done = [], []
2515     for src in sources:
2516         src = src.resolve()
2517         if cache.get(src) != get_cache_info(src):
2518             todo.append(src)
2519         else:
2520             done.append(src)
2521     return todo, done
2522
2523
2524 def write_cache(cache: Cache, sources: List[Path], line_length: int) -> None:
2525     """Update the cache file."""
2526     cache_file = get_cache_file(line_length)
2527     try:
2528         if not CACHE_DIR.exists():
2529             CACHE_DIR.mkdir(parents=True)
2530         new_cache = {**cache, **{src.resolve(): get_cache_info(src) for src in sources}}
2531         with cache_file.open("wb") as fobj:
2532             pickle.dump(new_cache, fobj, protocol=pickle.HIGHEST_PROTOCOL)
2533     except OSError:
2534         pass
2535
2536
2537 if __name__ == "__main__":
2538     main()