]> 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:

write cache in --check mode (#453)
[etc/vim.git] / black.py
1 import asyncio
2 from asyncio.base_events import BaseEventLoop
3 from concurrent.futures import Executor, ProcessPoolExecutor
4 from datetime import datetime
5 from enum import Enum, Flag
6 from functools import lru_cache, partial, wraps
7 import io
8 import keyword
9 import logging
10 from multiprocessing import Manager
11 import os
12 from pathlib import Path
13 import pickle
14 import re
15 import signal
16 import sys
17 import tokenize
18 from typing import (
19     Any,
20     Callable,
21     Collection,
22     Dict,
23     Generator,
24     Generic,
25     Iterable,
26     Iterator,
27     List,
28     Optional,
29     Pattern,
30     Sequence,
31     Set,
32     Tuple,
33     TypeVar,
34     Union,
35     cast,
36 )
37
38 from appdirs import user_cache_dir
39 from attr import dataclass, Factory
40 import click
41 import toml
42
43 # lib2to3 fork
44 from blib2to3.pytree import Node, Leaf, type_repr
45 from blib2to3 import pygram, pytree
46 from blib2to3.pgen2 import driver, token
47 from blib2to3.pgen2.parse import ParseError
48
49
50 __version__ = "18.6b4"
51 DEFAULT_LINE_LENGTH = 88
52 DEFAULT_EXCLUDES = (
53     r"/(\.git|\.hg|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist)/"
54 )
55 DEFAULT_INCLUDES = r"\.pyi?$"
56 CACHE_DIR = Path(user_cache_dir("black", version=__version__))
57
58
59 # types
60 FileContent = str
61 Encoding = str
62 NewLine = str
63 Depth = int
64 NodeType = int
65 LeafID = int
66 Priority = int
67 Index = int
68 LN = Union[Leaf, Node]
69 SplitFunc = Callable[["Line", bool], Iterator["Line"]]
70 Timestamp = float
71 FileSize = int
72 CacheInfo = Tuple[Timestamp, FileSize]
73 Cache = Dict[Path, CacheInfo]
74 out = partial(click.secho, bold=True, err=True)
75 err = partial(click.secho, fg="red", err=True)
76
77 pygram.initialize(CACHE_DIR)
78 syms = pygram.python_symbols
79
80
81 class NothingChanged(UserWarning):
82     """Raised by :func:`format_file` when reformatted code is the same as source."""
83
84
85 class CannotSplit(Exception):
86     """A readable split that fits the allotted line length is impossible.
87
88     Raised by :func:`left_hand_split`, :func:`right_hand_split`, and
89     :func:`delimiter_split`.
90     """
91
92
93 class WriteBack(Enum):
94     NO = 0
95     YES = 1
96     DIFF = 2
97     CHECK = 3
98
99     @classmethod
100     def from_configuration(cls, *, check: bool, diff: bool) -> "WriteBack":
101         if check and not diff:
102             return cls.CHECK
103
104         return cls.DIFF if diff else cls.YES
105
106
107 class Changed(Enum):
108     NO = 0
109     CACHED = 1
110     YES = 2
111
112
113 class FileMode(Flag):
114     AUTO_DETECT = 0
115     PYTHON36 = 1
116     PYI = 2
117     NO_STRING_NORMALIZATION = 4
118
119     @classmethod
120     def from_configuration(
121         cls, *, py36: bool, pyi: bool, skip_string_normalization: bool
122     ) -> "FileMode":
123         mode = cls.AUTO_DETECT
124         if py36:
125             mode |= cls.PYTHON36
126         if pyi:
127             mode |= cls.PYI
128         if skip_string_normalization:
129             mode |= cls.NO_STRING_NORMALIZATION
130         return mode
131
132
133 def read_pyproject_toml(
134     ctx: click.Context, param: click.Parameter, value: Union[str, int, bool, None]
135 ) -> Optional[str]:
136     """Inject Black configuration from "pyproject.toml" into defaults in `ctx`.
137
138     Returns the path to a successfully found and read configuration file, None
139     otherwise.
140     """
141     assert not isinstance(value, (int, bool)), "Invalid parameter type passed"
142     if not value:
143         root = find_project_root(ctx.params.get("src", ()))
144         path = root / "pyproject.toml"
145         if path.is_file():
146             value = str(path)
147         else:
148             return None
149
150     try:
151         pyproject_toml = toml.load(value)
152         config = pyproject_toml.get("tool", {}).get("black", {})
153     except (toml.TomlDecodeError, OSError) as e:
154         raise click.BadOptionUsage(f"Error reading configuration file: {e}", ctx)
155
156     if not config:
157         return None
158
159     if ctx.default_map is None:
160         ctx.default_map = {}
161     ctx.default_map.update(  # type: ignore  # bad types in .pyi
162         {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
163     )
164     return value
165
166
167 @click.command(context_settings=dict(help_option_names=["-h", "--help"]))
168 @click.option(
169     "-l",
170     "--line-length",
171     type=int,
172     default=DEFAULT_LINE_LENGTH,
173     help="How many character per line to allow.",
174     show_default=True,
175 )
176 @click.option(
177     "--py36",
178     is_flag=True,
179     help=(
180         "Allow using Python 3.6-only syntax on all input files.  This will put "
181         "trailing commas in function signatures and calls also after *args and "
182         "**kwargs.  [default: per-file auto-detection]"
183     ),
184 )
185 @click.option(
186     "--pyi",
187     is_flag=True,
188     help=(
189         "Format all input files like typing stubs regardless of file extension "
190         "(useful when piping source on standard input)."
191     ),
192 )
193 @click.option(
194     "-S",
195     "--skip-string-normalization",
196     is_flag=True,
197     help="Don't normalize string quotes or prefixes.",
198 )
199 @click.option(
200     "--check",
201     is_flag=True,
202     help=(
203         "Don't write the files back, just return the status.  Return code 0 "
204         "means nothing would change.  Return code 1 means some files would be "
205         "reformatted.  Return code 123 means there was an internal error."
206     ),
207 )
208 @click.option(
209     "--diff",
210     is_flag=True,
211     help="Don't write the files back, just output a diff for each file on stdout.",
212 )
213 @click.option(
214     "--fast/--safe",
215     is_flag=True,
216     help="If --fast given, skip temporary sanity checks. [default: --safe]",
217 )
218 @click.option(
219     "--include",
220     type=str,
221     default=DEFAULT_INCLUDES,
222     help=(
223         "A regular expression that matches files and directories that should be "
224         "included on recursive searches.  An empty value means all files are "
225         "included regardless of the name.  Use forward slashes for directories on "
226         "all platforms (Windows, too).  Exclusions are calculated first, inclusions "
227         "later."
228     ),
229     show_default=True,
230 )
231 @click.option(
232     "--exclude",
233     type=str,
234     default=DEFAULT_EXCLUDES,
235     help=(
236         "A regular expression that matches files and directories that should be "
237         "excluded on recursive searches.  An empty value means no paths are excluded. "
238         "Use forward slashes for directories on all platforms (Windows, too).  "
239         "Exclusions are calculated first, inclusions later."
240     ),
241     show_default=True,
242 )
243 @click.option(
244     "-q",
245     "--quiet",
246     is_flag=True,
247     help=(
248         "Don't emit non-error messages to stderr. Errors are still emitted, "
249         "silence those with 2>/dev/null."
250     ),
251 )
252 @click.option(
253     "-v",
254     "--verbose",
255     is_flag=True,
256     help=(
257         "Also emit messages to stderr about files that were not changed or were "
258         "ignored due to --exclude=."
259     ),
260 )
261 @click.version_option(version=__version__)
262 @click.argument(
263     "src",
264     nargs=-1,
265     type=click.Path(
266         exists=True, file_okay=True, dir_okay=True, readable=True, allow_dash=True
267     ),
268     is_eager=True,
269 )
270 @click.option(
271     "--config",
272     type=click.Path(
273         exists=False, file_okay=True, dir_okay=False, readable=True, allow_dash=False
274     ),
275     is_eager=True,
276     callback=read_pyproject_toml,
277     help="Read configuration from PATH.",
278 )
279 @click.pass_context
280 def main(
281     ctx: click.Context,
282     line_length: int,
283     check: bool,
284     diff: bool,
285     fast: bool,
286     pyi: bool,
287     py36: bool,
288     skip_string_normalization: bool,
289     quiet: bool,
290     verbose: bool,
291     include: str,
292     exclude: str,
293     src: Tuple[str],
294     config: Optional[str],
295 ) -> None:
296     """The uncompromising code formatter."""
297     write_back = WriteBack.from_configuration(check=check, diff=diff)
298     mode = FileMode.from_configuration(
299         py36=py36, pyi=pyi, skip_string_normalization=skip_string_normalization
300     )
301     if config and verbose:
302         out(f"Using configuration from {config}.", bold=False, fg="blue")
303     try:
304         include_regex = re_compile_maybe_verbose(include)
305     except re.error:
306         err(f"Invalid regular expression for include given: {include!r}")
307         ctx.exit(2)
308     try:
309         exclude_regex = re_compile_maybe_verbose(exclude)
310     except re.error:
311         err(f"Invalid regular expression for exclude given: {exclude!r}")
312         ctx.exit(2)
313     report = Report(check=check, quiet=quiet, verbose=verbose)
314     root = find_project_root(src)
315     sources: Set[Path] = set()
316     for s in src:
317         p = Path(s)
318         if p.is_dir():
319             sources.update(
320                 gen_python_files_in_dir(p, root, include_regex, exclude_regex, report)
321             )
322         elif p.is_file() or s == "-":
323             # if a file was explicitly given, we don't care about its extension
324             sources.add(p)
325         else:
326             err(f"invalid path: {s}")
327     if len(sources) == 0:
328         if verbose or not quiet:
329             out("No paths given. Nothing to do 😴")
330         ctx.exit(0)
331
332     if len(sources) == 1:
333         reformat_one(
334             src=sources.pop(),
335             line_length=line_length,
336             fast=fast,
337             write_back=write_back,
338             mode=mode,
339             report=report,
340         )
341     else:
342         loop = asyncio.get_event_loop()
343         executor = ProcessPoolExecutor(max_workers=os.cpu_count())
344         try:
345             loop.run_until_complete(
346                 schedule_formatting(
347                     sources=sources,
348                     line_length=line_length,
349                     fast=fast,
350                     write_back=write_back,
351                     mode=mode,
352                     report=report,
353                     loop=loop,
354                     executor=executor,
355                 )
356             )
357         finally:
358             shutdown(loop)
359     if verbose or not quiet:
360         bang = "💥 💔 💥" if report.return_code else "✨ 🍰 ✨"
361         out(f"All done! {bang}")
362         click.secho(str(report), err=True)
363     ctx.exit(report.return_code)
364
365
366 def reformat_one(
367     src: Path,
368     line_length: int,
369     fast: bool,
370     write_back: WriteBack,
371     mode: FileMode,
372     report: "Report",
373 ) -> None:
374     """Reformat a single file under `src` without spawning child processes.
375
376     If `quiet` is True, non-error messages are not output. `line_length`,
377     `write_back`, `fast` and `pyi` options are passed to
378     :func:`format_file_in_place` or :func:`format_stdin_to_stdout`.
379     """
380     try:
381         changed = Changed.NO
382         if not src.is_file() and str(src) == "-":
383             if format_stdin_to_stdout(
384                 line_length=line_length, fast=fast, write_back=write_back, mode=mode
385             ):
386                 changed = Changed.YES
387         else:
388             cache: Cache = {}
389             if write_back != WriteBack.DIFF:
390                 cache = read_cache(line_length, mode)
391                 res_src = src.resolve()
392                 if res_src in cache and cache[res_src] == get_cache_info(res_src):
393                     changed = Changed.CACHED
394             if changed is not Changed.CACHED and format_file_in_place(
395                 src,
396                 line_length=line_length,
397                 fast=fast,
398                 write_back=write_back,
399                 mode=mode,
400             ):
401                 changed = Changed.YES
402             if write_back is WriteBack.YES:
403                 should_write = changed is not Changed.CACHED
404             elif write_back is WriteBack.CHECK:
405                 should_write = changed is Changed.NO
406             else:
407                 should_write = False
408
409             if should_write:
410                 write_cache(cache, [src], line_length, mode)
411         report.done(src, changed)
412     except Exception as exc:
413         report.failed(src, str(exc))
414
415
416 async def schedule_formatting(
417     sources: Set[Path],
418     line_length: int,
419     fast: bool,
420     write_back: WriteBack,
421     mode: FileMode,
422     report: "Report",
423     loop: BaseEventLoop,
424     executor: Executor,
425 ) -> None:
426     """Run formatting of `sources` in parallel using the provided `executor`.
427
428     (Use ProcessPoolExecutors for actual parallelism.)
429
430     `line_length`, `write_back`, `fast`, and `pyi` options are passed to
431     :func:`format_file_in_place`.
432     """
433     cache: Cache = {}
434     if write_back != WriteBack.DIFF:
435         cache = read_cache(line_length, mode)
436         sources, cached = filter_cached(cache, sources)
437         for src in sorted(cached):
438             report.done(src, Changed.CACHED)
439     cancelled = []
440     formatted = []
441     if sources:
442         lock = None
443         if write_back == WriteBack.DIFF:
444             # For diff output, we need locks to ensure we don't interleave output
445             # from different processes.
446             manager = Manager()
447             lock = manager.Lock()
448         tasks = {
449             loop.run_in_executor(
450                 executor,
451                 format_file_in_place,
452                 src,
453                 line_length,
454                 fast,
455                 write_back,
456                 mode,
457                 lock,
458             ): src
459             for src in sorted(sources)
460         }
461         pending: Iterable[asyncio.Task] = tasks.keys()
462         try:
463             loop.add_signal_handler(signal.SIGINT, cancel, pending)
464             loop.add_signal_handler(signal.SIGTERM, cancel, pending)
465         except NotImplementedError:
466             # There are no good alternatives for these on Windows
467             pass
468         while pending:
469             done, _ = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
470             for task in done:
471                 src = tasks.pop(task)
472                 if task.cancelled():
473                     cancelled.append(task)
474                 elif task.exception():
475                     report.failed(src, str(task.exception()))
476                 else:
477                     changed = Changed.YES if task.result() else Changed.NO
478                     # In normal mode, write all files to the cache.
479                     if write_back is WriteBack.YES:
480                         formatted.append(src)
481                     # In check mode, write only unchanged files to the cache.
482                     elif write_back is WriteBack.CHECK and changed is Changed.NO:
483                         formatted.append(src)
484                     report.done(src, changed)
485     if cancelled:
486         await asyncio.gather(*cancelled, loop=loop, return_exceptions=True)
487     if write_back in (WriteBack.YES, WriteBack.CHECK) and formatted:
488         write_cache(cache, formatted, line_length, mode)
489
490
491 def format_file_in_place(
492     src: Path,
493     line_length: int,
494     fast: bool,
495     write_back: WriteBack = WriteBack.NO,
496     mode: FileMode = FileMode.AUTO_DETECT,
497     lock: Any = None,  # multiprocessing.Manager().Lock() is some crazy proxy
498 ) -> bool:
499     """Format file under `src` path. Return True if changed.
500
501     If `write_back` is DIFF, write a diff to stdout. If it is YES, write reformatted
502     code to the file.
503     `line_length` and `fast` options are passed to :func:`format_file_contents`.
504     """
505     if src.suffix == ".pyi":
506         mode |= FileMode.PYI
507
508     then = datetime.utcfromtimestamp(src.stat().st_mtime)
509     with open(src, "rb") as buf:
510         src_contents, encoding, newline = decode_bytes(buf.read())
511     try:
512         dst_contents = format_file_contents(
513             src_contents, line_length=line_length, fast=fast, mode=mode
514         )
515     except NothingChanged:
516         return False
517
518     if write_back == write_back.YES:
519         with open(src, "w", encoding=encoding, newline=newline) as f:
520             f.write(dst_contents)
521     elif write_back == write_back.DIFF:
522         now = datetime.utcnow()
523         src_name = f"{src}\t{then} +0000"
524         dst_name = f"{src}\t{now} +0000"
525         diff_contents = diff(src_contents, dst_contents, src_name, dst_name)
526         if lock:
527             lock.acquire()
528         try:
529             f = io.TextIOWrapper(
530                 sys.stdout.buffer,
531                 encoding=encoding,
532                 newline=newline,
533                 write_through=True,
534             )
535             f.write(diff_contents)
536             f.detach()
537         finally:
538             if lock:
539                 lock.release()
540     return True
541
542
543 def format_stdin_to_stdout(
544     line_length: int,
545     fast: bool,
546     write_back: WriteBack = WriteBack.NO,
547     mode: FileMode = FileMode.AUTO_DETECT,
548 ) -> bool:
549     """Format file on stdin. Return True if changed.
550
551     If `write_back` is YES, write reformatted code back to stdout. If it is DIFF,
552     write a diff to stdout.
553     `line_length`, `fast`, `is_pyi`, and `force_py36` arguments are passed to
554     :func:`format_file_contents`.
555     """
556     then = datetime.utcnow()
557     src, encoding, newline = decode_bytes(sys.stdin.buffer.read())
558     dst = src
559     try:
560         dst = format_file_contents(src, line_length=line_length, fast=fast, mode=mode)
561         return True
562
563     except NothingChanged:
564         return False
565
566     finally:
567         f = io.TextIOWrapper(
568             sys.stdout.buffer, encoding=encoding, newline=newline, write_through=True
569         )
570         if write_back == WriteBack.YES:
571             f.write(dst)
572         elif write_back == WriteBack.DIFF:
573             now = datetime.utcnow()
574             src_name = f"STDIN\t{then} +0000"
575             dst_name = f"STDOUT\t{now} +0000"
576             f.write(diff(src, dst, src_name, dst_name))
577         f.detach()
578
579
580 def format_file_contents(
581     src_contents: str,
582     *,
583     line_length: int,
584     fast: bool,
585     mode: FileMode = FileMode.AUTO_DETECT,
586 ) -> FileContent:
587     """Reformat contents a file and return new contents.
588
589     If `fast` is False, additionally confirm that the reformatted code is
590     valid by calling :func:`assert_equivalent` and :func:`assert_stable` on it.
591     `line_length` is passed to :func:`format_str`.
592     """
593     if src_contents.strip() == "":
594         raise NothingChanged
595
596     dst_contents = format_str(src_contents, line_length=line_length, mode=mode)
597     if src_contents == dst_contents:
598         raise NothingChanged
599
600     if not fast:
601         assert_equivalent(src_contents, dst_contents)
602         assert_stable(src_contents, dst_contents, line_length=line_length, mode=mode)
603     return dst_contents
604
605
606 def format_str(
607     src_contents: str, line_length: int, *, mode: FileMode = FileMode.AUTO_DETECT
608 ) -> FileContent:
609     """Reformat a string and return new contents.
610
611     `line_length` determines how many characters per line are allowed.
612     """
613     src_node = lib2to3_parse(src_contents)
614     dst_contents = ""
615     future_imports = get_future_imports(src_node)
616     is_pyi = bool(mode & FileMode.PYI)
617     py36 = bool(mode & FileMode.PYTHON36) or is_python36(src_node)
618     normalize_strings = not bool(mode & FileMode.NO_STRING_NORMALIZATION)
619     normalize_fmt_off(src_node)
620     lines = LineGenerator(
621         remove_u_prefix=py36 or "unicode_literals" in future_imports,
622         is_pyi=is_pyi,
623         normalize_strings=normalize_strings,
624         allow_underscores=py36,
625     )
626     elt = EmptyLineTracker(is_pyi=is_pyi)
627     empty_line = Line()
628     after = 0
629     for current_line in lines.visit(src_node):
630         for _ in range(after):
631             dst_contents += str(empty_line)
632         before, after = elt.maybe_empty_lines(current_line)
633         for _ in range(before):
634             dst_contents += str(empty_line)
635         for line in split_line(current_line, line_length=line_length, py36=py36):
636             dst_contents += str(line)
637     return dst_contents
638
639
640 def decode_bytes(src: bytes) -> Tuple[FileContent, Encoding, NewLine]:
641     """Return a tuple of (decoded_contents, encoding, newline).
642
643     `newline` is either CRLF or LF but `decoded_contents` is decoded with
644     universal newlines (i.e. only contains LF).
645     """
646     srcbuf = io.BytesIO(src)
647     encoding, lines = tokenize.detect_encoding(srcbuf.readline)
648     if not lines:
649         return "", encoding, "\n"
650
651     newline = "\r\n" if b"\r\n" == lines[0][-2:] else "\n"
652     srcbuf.seek(0)
653     with io.TextIOWrapper(srcbuf, encoding) as tiow:
654         return tiow.read(), encoding, newline
655
656
657 GRAMMARS = [
658     pygram.python_grammar_no_print_statement_no_exec_statement,
659     pygram.python_grammar_no_print_statement,
660     pygram.python_grammar,
661 ]
662
663
664 def lib2to3_parse(src_txt: str) -> Node:
665     """Given a string with source, return the lib2to3 Node."""
666     grammar = pygram.python_grammar_no_print_statement
667     if src_txt[-1:] != "\n":
668         src_txt += "\n"
669     for grammar in GRAMMARS:
670         drv = driver.Driver(grammar, pytree.convert)
671         try:
672             result = drv.parse_string(src_txt, True)
673             break
674
675         except ParseError as pe:
676             lineno, column = pe.context[1]
677             lines = src_txt.splitlines()
678             try:
679                 faulty_line = lines[lineno - 1]
680             except IndexError:
681                 faulty_line = "<line number missing in source>"
682             exc = ValueError(f"Cannot parse: {lineno}:{column}: {faulty_line}")
683     else:
684         raise exc from None
685
686     if isinstance(result, Leaf):
687         result = Node(syms.file_input, [result])
688     return result
689
690
691 def lib2to3_unparse(node: Node) -> str:
692     """Given a lib2to3 node, return its string representation."""
693     code = str(node)
694     return code
695
696
697 T = TypeVar("T")
698
699
700 class Visitor(Generic[T]):
701     """Basic lib2to3 visitor that yields things of type `T` on `visit()`."""
702
703     def visit(self, node: LN) -> Iterator[T]:
704         """Main method to visit `node` and its children.
705
706         It tries to find a `visit_*()` method for the given `node.type`, like
707         `visit_simple_stmt` for Node objects or `visit_INDENT` for Leaf objects.
708         If no dedicated `visit_*()` method is found, chooses `visit_default()`
709         instead.
710
711         Then yields objects of type `T` from the selected visitor.
712         """
713         if node.type < 256:
714             name = token.tok_name[node.type]
715         else:
716             name = type_repr(node.type)
717         yield from getattr(self, f"visit_{name}", self.visit_default)(node)
718
719     def visit_default(self, node: LN) -> Iterator[T]:
720         """Default `visit_*()` implementation. Recurses to children of `node`."""
721         if isinstance(node, Node):
722             for child in node.children:
723                 yield from self.visit(child)
724
725
726 @dataclass
727 class DebugVisitor(Visitor[T]):
728     tree_depth: int = 0
729
730     def visit_default(self, node: LN) -> Iterator[T]:
731         indent = " " * (2 * self.tree_depth)
732         if isinstance(node, Node):
733             _type = type_repr(node.type)
734             out(f"{indent}{_type}", fg="yellow")
735             self.tree_depth += 1
736             for child in node.children:
737                 yield from self.visit(child)
738
739             self.tree_depth -= 1
740             out(f"{indent}/{_type}", fg="yellow", bold=False)
741         else:
742             _type = token.tok_name.get(node.type, str(node.type))
743             out(f"{indent}{_type}", fg="blue", nl=False)
744             if node.prefix:
745                 # We don't have to handle prefixes for `Node` objects since
746                 # that delegates to the first child anyway.
747                 out(f" {node.prefix!r}", fg="green", bold=False, nl=False)
748             out(f" {node.value!r}", fg="blue", bold=False)
749
750     @classmethod
751     def show(cls, code: Union[str, Leaf, Node]) -> None:
752         """Pretty-print the lib2to3 AST of a given string of `code`.
753
754         Convenience method for debugging.
755         """
756         v: DebugVisitor[None] = DebugVisitor()
757         if isinstance(code, str):
758             code = lib2to3_parse(code)
759         list(v.visit(code))
760
761
762 KEYWORDS = set(keyword.kwlist)
763 WHITESPACE = {token.DEDENT, token.INDENT, token.NEWLINE}
764 FLOW_CONTROL = {"return", "raise", "break", "continue"}
765 STATEMENT = {
766     syms.if_stmt,
767     syms.while_stmt,
768     syms.for_stmt,
769     syms.try_stmt,
770     syms.except_clause,
771     syms.with_stmt,
772     syms.funcdef,
773     syms.classdef,
774 }
775 STANDALONE_COMMENT = 153
776 token.tok_name[STANDALONE_COMMENT] = "STANDALONE_COMMENT"
777 LOGIC_OPERATORS = {"and", "or"}
778 COMPARATORS = {
779     token.LESS,
780     token.GREATER,
781     token.EQEQUAL,
782     token.NOTEQUAL,
783     token.LESSEQUAL,
784     token.GREATEREQUAL,
785 }
786 MATH_OPERATORS = {
787     token.VBAR,
788     token.CIRCUMFLEX,
789     token.AMPER,
790     token.LEFTSHIFT,
791     token.RIGHTSHIFT,
792     token.PLUS,
793     token.MINUS,
794     token.STAR,
795     token.SLASH,
796     token.DOUBLESLASH,
797     token.PERCENT,
798     token.AT,
799     token.TILDE,
800     token.DOUBLESTAR,
801 }
802 STARS = {token.STAR, token.DOUBLESTAR}
803 VARARGS_PARENTS = {
804     syms.arglist,
805     syms.argument,  # double star in arglist
806     syms.trailer,  # single argument to call
807     syms.typedargslist,
808     syms.varargslist,  # lambdas
809 }
810 UNPACKING_PARENTS = {
811     syms.atom,  # single element of a list or set literal
812     syms.dictsetmaker,
813     syms.listmaker,
814     syms.testlist_gexp,
815     syms.testlist_star_expr,
816 }
817 TEST_DESCENDANTS = {
818     syms.test,
819     syms.lambdef,
820     syms.or_test,
821     syms.and_test,
822     syms.not_test,
823     syms.comparison,
824     syms.star_expr,
825     syms.expr,
826     syms.xor_expr,
827     syms.and_expr,
828     syms.shift_expr,
829     syms.arith_expr,
830     syms.trailer,
831     syms.term,
832     syms.power,
833 }
834 ASSIGNMENTS = {
835     "=",
836     "+=",
837     "-=",
838     "*=",
839     "@=",
840     "/=",
841     "%=",
842     "&=",
843     "|=",
844     "^=",
845     "<<=",
846     ">>=",
847     "**=",
848     "//=",
849 }
850 COMPREHENSION_PRIORITY = 20
851 COMMA_PRIORITY = 18
852 TERNARY_PRIORITY = 16
853 LOGIC_PRIORITY = 14
854 STRING_PRIORITY = 12
855 COMPARATOR_PRIORITY = 10
856 MATH_PRIORITIES = {
857     token.VBAR: 9,
858     token.CIRCUMFLEX: 8,
859     token.AMPER: 7,
860     token.LEFTSHIFT: 6,
861     token.RIGHTSHIFT: 6,
862     token.PLUS: 5,
863     token.MINUS: 5,
864     token.STAR: 4,
865     token.SLASH: 4,
866     token.DOUBLESLASH: 4,
867     token.PERCENT: 4,
868     token.AT: 4,
869     token.TILDE: 3,
870     token.DOUBLESTAR: 2,
871 }
872 DOT_PRIORITY = 1
873
874
875 @dataclass
876 class BracketTracker:
877     """Keeps track of brackets on a line."""
878
879     depth: int = 0
880     bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = Factory(dict)
881     delimiters: Dict[LeafID, Priority] = Factory(dict)
882     previous: Optional[Leaf] = None
883     _for_loop_variable: int = 0
884     _lambda_arguments: int = 0
885
886     def mark(self, leaf: Leaf) -> None:
887         """Mark `leaf` with bracket-related metadata. Keep track of delimiters.
888
889         All leaves receive an int `bracket_depth` field that stores how deep
890         within brackets a given leaf is. 0 means there are no enclosing brackets
891         that started on this line.
892
893         If a leaf is itself a closing bracket, it receives an `opening_bracket`
894         field that it forms a pair with. This is a one-directional link to
895         avoid reference cycles.
896
897         If a leaf is a delimiter (a token on which Black can split the line if
898         needed) and it's on depth 0, its `id()` is stored in the tracker's
899         `delimiters` field.
900         """
901         if leaf.type == token.COMMENT:
902             return
903
904         self.maybe_decrement_after_for_loop_variable(leaf)
905         self.maybe_decrement_after_lambda_arguments(leaf)
906         if leaf.type in CLOSING_BRACKETS:
907             self.depth -= 1
908             opening_bracket = self.bracket_match.pop((self.depth, leaf.type))
909             leaf.opening_bracket = opening_bracket
910         leaf.bracket_depth = self.depth
911         if self.depth == 0:
912             delim = is_split_before_delimiter(leaf, self.previous)
913             if delim and self.previous is not None:
914                 self.delimiters[id(self.previous)] = delim
915             else:
916                 delim = is_split_after_delimiter(leaf, self.previous)
917                 if delim:
918                     self.delimiters[id(leaf)] = delim
919         if leaf.type in OPENING_BRACKETS:
920             self.bracket_match[self.depth, BRACKET[leaf.type]] = leaf
921             self.depth += 1
922         self.previous = leaf
923         self.maybe_increment_lambda_arguments(leaf)
924         self.maybe_increment_for_loop_variable(leaf)
925
926     def any_open_brackets(self) -> bool:
927         """Return True if there is an yet unmatched open bracket on the line."""
928         return bool(self.bracket_match)
929
930     def max_delimiter_priority(self, exclude: Iterable[LeafID] = ()) -> int:
931         """Return the highest priority of a delimiter found on the line.
932
933         Values are consistent with what `is_split_*_delimiter()` return.
934         Raises ValueError on no delimiters.
935         """
936         return max(v for k, v in self.delimiters.items() if k not in exclude)
937
938     def delimiter_count_with_priority(self, priority: int = 0) -> int:
939         """Return the number of delimiters with the given `priority`.
940
941         If no `priority` is passed, defaults to max priority on the line.
942         """
943         if not self.delimiters:
944             return 0
945
946         priority = priority or self.max_delimiter_priority()
947         return sum(1 for p in self.delimiters.values() if p == priority)
948
949     def maybe_increment_for_loop_variable(self, leaf: Leaf) -> bool:
950         """In a for loop, or comprehension, the variables are often unpacks.
951
952         To avoid splitting on the comma in this situation, increase the depth of
953         tokens between `for` and `in`.
954         """
955         if leaf.type == token.NAME and leaf.value == "for":
956             self.depth += 1
957             self._for_loop_variable += 1
958             return True
959
960         return False
961
962     def maybe_decrement_after_for_loop_variable(self, leaf: Leaf) -> bool:
963         """See `maybe_increment_for_loop_variable` above for explanation."""
964         if self._for_loop_variable and leaf.type == token.NAME and leaf.value == "in":
965             self.depth -= 1
966             self._for_loop_variable -= 1
967             return True
968
969         return False
970
971     def maybe_increment_lambda_arguments(self, leaf: Leaf) -> bool:
972         """In a lambda expression, there might be more than one argument.
973
974         To avoid splitting on the comma in this situation, increase the depth of
975         tokens between `lambda` and `:`.
976         """
977         if leaf.type == token.NAME and leaf.value == "lambda":
978             self.depth += 1
979             self._lambda_arguments += 1
980             return True
981
982         return False
983
984     def maybe_decrement_after_lambda_arguments(self, leaf: Leaf) -> bool:
985         """See `maybe_increment_lambda_arguments` above for explanation."""
986         if self._lambda_arguments and leaf.type == token.COLON:
987             self.depth -= 1
988             self._lambda_arguments -= 1
989             return True
990
991         return False
992
993     def get_open_lsqb(self) -> Optional[Leaf]:
994         """Return the most recent opening square bracket (if any)."""
995         return self.bracket_match.get((self.depth - 1, token.RSQB))
996
997
998 @dataclass
999 class Line:
1000     """Holds leaves and comments. Can be printed with `str(line)`."""
1001
1002     depth: int = 0
1003     leaves: List[Leaf] = Factory(list)
1004     comments: List[Tuple[Index, Leaf]] = Factory(list)
1005     bracket_tracker: BracketTracker = Factory(BracketTracker)
1006     inside_brackets: bool = False
1007     should_explode: bool = False
1008
1009     def append(self, leaf: Leaf, preformatted: bool = False) -> None:
1010         """Add a new `leaf` to the end of the line.
1011
1012         Unless `preformatted` is True, the `leaf` will receive a new consistent
1013         whitespace prefix and metadata applied by :class:`BracketTracker`.
1014         Trailing commas are maybe removed, unpacked for loop variables are
1015         demoted from being delimiters.
1016
1017         Inline comments are put aside.
1018         """
1019         has_value = leaf.type in BRACKETS or bool(leaf.value.strip())
1020         if not has_value:
1021             return
1022
1023         if token.COLON == leaf.type and self.is_class_paren_empty:
1024             del self.leaves[-2:]
1025         if self.leaves and not preformatted:
1026             # Note: at this point leaf.prefix should be empty except for
1027             # imports, for which we only preserve newlines.
1028             leaf.prefix += whitespace(
1029                 leaf, complex_subscript=self.is_complex_subscript(leaf)
1030             )
1031         if self.inside_brackets or not preformatted:
1032             self.bracket_tracker.mark(leaf)
1033             self.maybe_remove_trailing_comma(leaf)
1034         if not self.append_comment(leaf):
1035             self.leaves.append(leaf)
1036
1037     def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
1038         """Like :func:`append()` but disallow invalid standalone comment structure.
1039
1040         Raises ValueError when any `leaf` is appended after a standalone comment
1041         or when a standalone comment is not the first leaf on the line.
1042         """
1043         if self.bracket_tracker.depth == 0:
1044             if self.is_comment:
1045                 raise ValueError("cannot append to standalone comments")
1046
1047             if self.leaves and leaf.type == STANDALONE_COMMENT:
1048                 raise ValueError(
1049                     "cannot append standalone comments to a populated line"
1050                 )
1051
1052         self.append(leaf, preformatted=preformatted)
1053
1054     @property
1055     def is_comment(self) -> bool:
1056         """Is this line a standalone comment?"""
1057         return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
1058
1059     @property
1060     def is_decorator(self) -> bool:
1061         """Is this line a decorator?"""
1062         return bool(self) and self.leaves[0].type == token.AT
1063
1064     @property
1065     def is_import(self) -> bool:
1066         """Is this an import line?"""
1067         return bool(self) and is_import(self.leaves[0])
1068
1069     @property
1070     def is_class(self) -> bool:
1071         """Is this line a class definition?"""
1072         return (
1073             bool(self)
1074             and self.leaves[0].type == token.NAME
1075             and self.leaves[0].value == "class"
1076         )
1077
1078     @property
1079     def is_stub_class(self) -> bool:
1080         """Is this line a class definition with a body consisting only of "..."?"""
1081         return self.is_class and self.leaves[-3:] == [
1082             Leaf(token.DOT, ".") for _ in range(3)
1083         ]
1084
1085     @property
1086     def is_def(self) -> bool:
1087         """Is this a function definition? (Also returns True for async defs.)"""
1088         try:
1089             first_leaf = self.leaves[0]
1090         except IndexError:
1091             return False
1092
1093         try:
1094             second_leaf: Optional[Leaf] = self.leaves[1]
1095         except IndexError:
1096             second_leaf = None
1097         return (first_leaf.type == token.NAME and first_leaf.value == "def") or (
1098             first_leaf.type == token.ASYNC
1099             and second_leaf is not None
1100             and second_leaf.type == token.NAME
1101             and second_leaf.value == "def"
1102         )
1103
1104     @property
1105     def is_class_paren_empty(self) -> bool:
1106         """Is this a class with no base classes but using parentheses?
1107
1108         Those are unnecessary and should be removed.
1109         """
1110         return (
1111             bool(self)
1112             and len(self.leaves) == 4
1113             and self.is_class
1114             and self.leaves[2].type == token.LPAR
1115             and self.leaves[2].value == "("
1116             and self.leaves[3].type == token.RPAR
1117             and self.leaves[3].value == ")"
1118         )
1119
1120     @property
1121     def is_triple_quoted_string(self) -> bool:
1122         """Is the line a triple quoted string?"""
1123         return (
1124             bool(self)
1125             and self.leaves[0].type == token.STRING
1126             and self.leaves[0].value.startswith(('"""', "'''"))
1127         )
1128
1129     def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
1130         """If so, needs to be split before emitting."""
1131         for leaf in self.leaves:
1132             if leaf.type == STANDALONE_COMMENT:
1133                 if leaf.bracket_depth <= depth_limit:
1134                     return True
1135
1136         return False
1137
1138     def contains_multiline_strings(self) -> bool:
1139         for leaf in self.leaves:
1140             if is_multiline_string(leaf):
1141                 return True
1142
1143         return False
1144
1145     def maybe_remove_trailing_comma(self, closing: Leaf) -> bool:
1146         """Remove trailing comma if there is one and it's safe."""
1147         if not (
1148             self.leaves
1149             and self.leaves[-1].type == token.COMMA
1150             and closing.type in CLOSING_BRACKETS
1151         ):
1152             return False
1153
1154         if closing.type == token.RBRACE:
1155             self.remove_trailing_comma()
1156             return True
1157
1158         if closing.type == token.RSQB:
1159             comma = self.leaves[-1]
1160             if comma.parent and comma.parent.type == syms.listmaker:
1161                 self.remove_trailing_comma()
1162                 return True
1163
1164         # For parens let's check if it's safe to remove the comma.
1165         # Imports are always safe.
1166         if self.is_import:
1167             self.remove_trailing_comma()
1168             return True
1169
1170         # Otheriwsse, if the trailing one is the only one, we might mistakenly
1171         # change a tuple into a different type by removing the comma.
1172         depth = closing.bracket_depth + 1
1173         commas = 0
1174         opening = closing.opening_bracket
1175         for _opening_index, leaf in enumerate(self.leaves):
1176             if leaf is opening:
1177                 break
1178
1179         else:
1180             return False
1181
1182         for leaf in self.leaves[_opening_index + 1 :]:
1183             if leaf is closing:
1184                 break
1185
1186             bracket_depth = leaf.bracket_depth
1187             if bracket_depth == depth and leaf.type == token.COMMA:
1188                 commas += 1
1189                 if leaf.parent and leaf.parent.type == syms.arglist:
1190                     commas += 1
1191                     break
1192
1193         if commas > 1:
1194             self.remove_trailing_comma()
1195             return True
1196
1197         return False
1198
1199     def append_comment(self, comment: Leaf) -> bool:
1200         """Add an inline or standalone comment to the line."""
1201         if (
1202             comment.type == STANDALONE_COMMENT
1203             and self.bracket_tracker.any_open_brackets()
1204         ):
1205             comment.prefix = ""
1206             return False
1207
1208         if comment.type != token.COMMENT:
1209             return False
1210
1211         after = len(self.leaves) - 1
1212         if after == -1:
1213             comment.type = STANDALONE_COMMENT
1214             comment.prefix = ""
1215             return False
1216
1217         else:
1218             self.comments.append((after, comment))
1219             return True
1220
1221     def comments_after(self, leaf: Leaf, _index: int = -1) -> Iterator[Leaf]:
1222         """Generate comments that should appear directly after `leaf`.
1223
1224         Provide a non-negative leaf `_index` to speed up the function.
1225         """
1226         if not self.comments:
1227             return
1228
1229         if _index == -1:
1230             for _index, _leaf in enumerate(self.leaves):
1231                 if leaf is _leaf:
1232                     break
1233
1234             else:
1235                 return
1236
1237         for index, comment_after in self.comments:
1238             if _index == index:
1239                 yield comment_after
1240
1241     def remove_trailing_comma(self) -> None:
1242         """Remove the trailing comma and moves the comments attached to it."""
1243         comma_index = len(self.leaves) - 1
1244         for i in range(len(self.comments)):
1245             comment_index, comment = self.comments[i]
1246             if comment_index == comma_index:
1247                 self.comments[i] = (comma_index - 1, comment)
1248         self.leaves.pop()
1249
1250     def is_complex_subscript(self, leaf: Leaf) -> bool:
1251         """Return True iff `leaf` is part of a slice with non-trivial exprs."""
1252         open_lsqb = self.bracket_tracker.get_open_lsqb()
1253         if open_lsqb is None:
1254             return False
1255
1256         subscript_start = open_lsqb.next_sibling
1257
1258         if isinstance(subscript_start, Node):
1259             if subscript_start.type == syms.listmaker:
1260                 return False
1261
1262             if subscript_start.type == syms.subscriptlist:
1263                 subscript_start = child_towards(subscript_start, leaf)
1264         return subscript_start is not None and any(
1265             n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
1266         )
1267
1268     def __str__(self) -> str:
1269         """Render the line."""
1270         if not self:
1271             return "\n"
1272
1273         indent = "    " * self.depth
1274         leaves = iter(self.leaves)
1275         first = next(leaves)
1276         res = f"{first.prefix}{indent}{first.value}"
1277         for leaf in leaves:
1278             res += str(leaf)
1279         for _, comment in self.comments:
1280             res += str(comment)
1281         return res + "\n"
1282
1283     def __bool__(self) -> bool:
1284         """Return True if the line has leaves or comments."""
1285         return bool(self.leaves or self.comments)
1286
1287
1288 @dataclass
1289 class EmptyLineTracker:
1290     """Provides a stateful method that returns the number of potential extra
1291     empty lines needed before and after the currently processed line.
1292
1293     Note: this tracker works on lines that haven't been split yet.  It assumes
1294     the prefix of the first leaf consists of optional newlines.  Those newlines
1295     are consumed by `maybe_empty_lines()` and included in the computation.
1296     """
1297
1298     is_pyi: bool = False
1299     previous_line: Optional[Line] = None
1300     previous_after: int = 0
1301     previous_defs: List[int] = Factory(list)
1302
1303     def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
1304         """Return the number of extra empty lines before and after the `current_line`.
1305
1306         This is for separating `def`, `async def` and `class` with extra empty
1307         lines (two on module-level).
1308         """
1309         before, after = self._maybe_empty_lines(current_line)
1310         before -= self.previous_after
1311         self.previous_after = after
1312         self.previous_line = current_line
1313         return before, after
1314
1315     def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
1316         max_allowed = 1
1317         if current_line.depth == 0:
1318             max_allowed = 1 if self.is_pyi else 2
1319         if current_line.leaves:
1320             # Consume the first leaf's extra newlines.
1321             first_leaf = current_line.leaves[0]
1322             before = first_leaf.prefix.count("\n")
1323             before = min(before, max_allowed)
1324             first_leaf.prefix = ""
1325         else:
1326             before = 0
1327         depth = current_line.depth
1328         while self.previous_defs and self.previous_defs[-1] >= depth:
1329             self.previous_defs.pop()
1330             if self.is_pyi:
1331                 before = 0 if depth else 1
1332             else:
1333                 before = 1 if depth else 2
1334         if current_line.is_decorator or current_line.is_def or current_line.is_class:
1335             return self._maybe_empty_lines_for_class_or_def(current_line, before)
1336
1337         if (
1338             self.previous_line
1339             and self.previous_line.is_import
1340             and not current_line.is_import
1341             and depth == self.previous_line.depth
1342         ):
1343             return (before or 1), 0
1344
1345         if (
1346             self.previous_line
1347             and self.previous_line.is_class
1348             and current_line.is_triple_quoted_string
1349         ):
1350             return before, 1
1351
1352         return before, 0
1353
1354     def _maybe_empty_lines_for_class_or_def(
1355         self, current_line: Line, before: int
1356     ) -> Tuple[int, int]:
1357         if not current_line.is_decorator:
1358             self.previous_defs.append(current_line.depth)
1359         if self.previous_line is None:
1360             # Don't insert empty lines before the first line in the file.
1361             return 0, 0
1362
1363         if self.previous_line.is_decorator:
1364             return 0, 0
1365
1366         if self.previous_line.depth < current_line.depth and (
1367             self.previous_line.is_class or self.previous_line.is_def
1368         ):
1369             return 0, 0
1370
1371         if (
1372             self.previous_line.is_comment
1373             and self.previous_line.depth == current_line.depth
1374             and before == 0
1375         ):
1376             return 0, 0
1377
1378         if self.is_pyi:
1379             if self.previous_line.depth > current_line.depth:
1380                 newlines = 1
1381             elif current_line.is_class or self.previous_line.is_class:
1382                 if current_line.is_stub_class and self.previous_line.is_stub_class:
1383                     # No blank line between classes with an emty body
1384                     newlines = 0
1385                 else:
1386                     newlines = 1
1387             elif current_line.is_def and not self.previous_line.is_def:
1388                 # Blank line between a block of functions and a block of non-functions
1389                 newlines = 1
1390             else:
1391                 newlines = 0
1392         else:
1393             newlines = 2
1394         if current_line.depth and newlines:
1395             newlines -= 1
1396         return newlines, 0
1397
1398
1399 @dataclass
1400 class LineGenerator(Visitor[Line]):
1401     """Generates reformatted Line objects.  Empty lines are not emitted.
1402
1403     Note: destroys the tree it's visiting by mutating prefixes of its leaves
1404     in ways that will no longer stringify to valid Python code on the tree.
1405     """
1406
1407     is_pyi: bool = False
1408     normalize_strings: bool = True
1409     current_line: Line = Factory(Line)
1410     remove_u_prefix: bool = False
1411     allow_underscores: bool = False
1412
1413     def line(self, indent: int = 0) -> Iterator[Line]:
1414         """Generate a line.
1415
1416         If the line is empty, only emit if it makes sense.
1417         If the line is too long, split it first and then generate.
1418
1419         If any lines were generated, set up a new current_line.
1420         """
1421         if not self.current_line:
1422             self.current_line.depth += indent
1423             return  # Line is empty, don't emit. Creating a new one unnecessary.
1424
1425         complete_line = self.current_line
1426         self.current_line = Line(depth=complete_line.depth + indent)
1427         yield complete_line
1428
1429     def visit_default(self, node: LN) -> Iterator[Line]:
1430         """Default `visit_*()` implementation. Recurses to children of `node`."""
1431         if isinstance(node, Leaf):
1432             any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
1433             for comment in generate_comments(node):
1434                 if any_open_brackets:
1435                     # any comment within brackets is subject to splitting
1436                     self.current_line.append(comment)
1437                 elif comment.type == token.COMMENT:
1438                     # regular trailing comment
1439                     self.current_line.append(comment)
1440                     yield from self.line()
1441
1442                 else:
1443                     # regular standalone comment
1444                     yield from self.line()
1445
1446                     self.current_line.append(comment)
1447                     yield from self.line()
1448
1449             normalize_prefix(node, inside_brackets=any_open_brackets)
1450             if self.normalize_strings and node.type == token.STRING:
1451                 normalize_string_prefix(node, remove_u_prefix=self.remove_u_prefix)
1452                 normalize_string_quotes(node)
1453             if node.type == token.NUMBER:
1454                 normalize_numeric_literal(node, self.allow_underscores)
1455             if node.type not in WHITESPACE:
1456                 self.current_line.append(node)
1457         yield from super().visit_default(node)
1458
1459     def visit_INDENT(self, node: Node) -> Iterator[Line]:
1460         """Increase indentation level, maybe yield a line."""
1461         # In blib2to3 INDENT never holds comments.
1462         yield from self.line(+1)
1463         yield from self.visit_default(node)
1464
1465     def visit_DEDENT(self, node: Node) -> Iterator[Line]:
1466         """Decrease indentation level, maybe yield a line."""
1467         # The current line might still wait for trailing comments.  At DEDENT time
1468         # there won't be any (they would be prefixes on the preceding NEWLINE).
1469         # Emit the line then.
1470         yield from self.line()
1471
1472         # While DEDENT has no value, its prefix may contain standalone comments
1473         # that belong to the current indentation level.  Get 'em.
1474         yield from self.visit_default(node)
1475
1476         # Finally, emit the dedent.
1477         yield from self.line(-1)
1478
1479     def visit_stmt(
1480         self, node: Node, keywords: Set[str], parens: Set[str]
1481     ) -> Iterator[Line]:
1482         """Visit a statement.
1483
1484         This implementation is shared for `if`, `while`, `for`, `try`, `except`,
1485         `def`, `with`, `class`, `assert` and assignments.
1486
1487         The relevant Python language `keywords` for a given statement will be
1488         NAME leaves within it. This methods puts those on a separate line.
1489
1490         `parens` holds a set of string leaf values immediately after which
1491         invisible parens should be put.
1492         """
1493         normalize_invisible_parens(node, parens_after=parens)
1494         for child in node.children:
1495             if child.type == token.NAME and child.value in keywords:  # type: ignore
1496                 yield from self.line()
1497
1498             yield from self.visit(child)
1499
1500     def visit_suite(self, node: Node) -> Iterator[Line]:
1501         """Visit a suite."""
1502         if self.is_pyi and is_stub_suite(node):
1503             yield from self.visit(node.children[2])
1504         else:
1505             yield from self.visit_default(node)
1506
1507     def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
1508         """Visit a statement without nested statements."""
1509         is_suite_like = node.parent and node.parent.type in STATEMENT
1510         if is_suite_like:
1511             if self.is_pyi and is_stub_body(node):
1512                 yield from self.visit_default(node)
1513             else:
1514                 yield from self.line(+1)
1515                 yield from self.visit_default(node)
1516                 yield from self.line(-1)
1517
1518         else:
1519             if not self.is_pyi or not node.parent or not is_stub_suite(node.parent):
1520                 yield from self.line()
1521             yield from self.visit_default(node)
1522
1523     def visit_async_stmt(self, node: Node) -> Iterator[Line]:
1524         """Visit `async def`, `async for`, `async with`."""
1525         yield from self.line()
1526
1527         children = iter(node.children)
1528         for child in children:
1529             yield from self.visit(child)
1530
1531             if child.type == token.ASYNC:
1532                 break
1533
1534         internal_stmt = next(children)
1535         for child in internal_stmt.children:
1536             yield from self.visit(child)
1537
1538     def visit_decorators(self, node: Node) -> Iterator[Line]:
1539         """Visit decorators."""
1540         for child in node.children:
1541             yield from self.line()
1542             yield from self.visit(child)
1543
1544     def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]:
1545         """Remove a semicolon and put the other statement on a separate line."""
1546         yield from self.line()
1547
1548     def visit_ENDMARKER(self, leaf: Leaf) -> Iterator[Line]:
1549         """End of file. Process outstanding comments and end with a newline."""
1550         yield from self.visit_default(leaf)
1551         yield from self.line()
1552
1553     def visit_STANDALONE_COMMENT(self, leaf: Leaf) -> Iterator[Line]:
1554         if not self.current_line.bracket_tracker.any_open_brackets():
1555             yield from self.line()
1556         yield from self.visit_default(leaf)
1557
1558     def __attrs_post_init__(self) -> None:
1559         """You are in a twisty little maze of passages."""
1560         v = self.visit_stmt
1561         Ø: Set[str] = set()
1562         self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
1563         self.visit_if_stmt = partial(
1564             v, keywords={"if", "else", "elif"}, parens={"if", "elif"}
1565         )
1566         self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"})
1567         self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"})
1568         self.visit_try_stmt = partial(
1569             v, keywords={"try", "except", "else", "finally"}, parens=Ø
1570         )
1571         self.visit_except_clause = partial(v, keywords={"except"}, parens=Ø)
1572         self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø)
1573         self.visit_funcdef = partial(v, keywords={"def"}, parens=Ø)
1574         self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
1575         self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS)
1576         self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
1577         self.visit_import_from = partial(v, keywords=Ø, parens={"import"})
1578         self.visit_async_funcdef = self.visit_async_stmt
1579         self.visit_decorated = self.visit_decorators
1580
1581
1582 IMPLICIT_TUPLE = {syms.testlist, syms.testlist_star_expr, syms.exprlist}
1583 BRACKET = {token.LPAR: token.RPAR, token.LSQB: token.RSQB, token.LBRACE: token.RBRACE}
1584 OPENING_BRACKETS = set(BRACKET.keys())
1585 CLOSING_BRACKETS = set(BRACKET.values())
1586 BRACKETS = OPENING_BRACKETS | CLOSING_BRACKETS
1587 ALWAYS_NO_SPACE = CLOSING_BRACKETS | {token.COMMA, STANDALONE_COMMENT}
1588
1589
1590 def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str:  # noqa C901
1591     """Return whitespace prefix if needed for the given `leaf`.
1592
1593     `complex_subscript` signals whether the given leaf is part of a subscription
1594     which has non-trivial arguments, like arithmetic expressions or function calls.
1595     """
1596     NO = ""
1597     SPACE = " "
1598     DOUBLESPACE = "  "
1599     t = leaf.type
1600     p = leaf.parent
1601     v = leaf.value
1602     if t in ALWAYS_NO_SPACE:
1603         return NO
1604
1605     if t == token.COMMENT:
1606         return DOUBLESPACE
1607
1608     assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
1609     if t == token.COLON and p.type not in {
1610         syms.subscript,
1611         syms.subscriptlist,
1612         syms.sliceop,
1613     }:
1614         return NO
1615
1616     prev = leaf.prev_sibling
1617     if not prev:
1618         prevp = preceding_leaf(p)
1619         if not prevp or prevp.type in OPENING_BRACKETS:
1620             return NO
1621
1622         if t == token.COLON:
1623             if prevp.type == token.COLON:
1624                 return NO
1625
1626             elif prevp.type != token.COMMA and not complex_subscript:
1627                 return NO
1628
1629             return SPACE
1630
1631         if prevp.type == token.EQUAL:
1632             if prevp.parent:
1633                 if prevp.parent.type in {
1634                     syms.arglist,
1635                     syms.argument,
1636                     syms.parameters,
1637                     syms.varargslist,
1638                 }:
1639                     return NO
1640
1641                 elif prevp.parent.type == syms.typedargslist:
1642                     # A bit hacky: if the equal sign has whitespace, it means we
1643                     # previously found it's a typed argument.  So, we're using
1644                     # that, too.
1645                     return prevp.prefix
1646
1647         elif prevp.type in STARS:
1648             if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS):
1649                 return NO
1650
1651         elif prevp.type == token.COLON:
1652             if prevp.parent and prevp.parent.type in {syms.subscript, syms.sliceop}:
1653                 return SPACE if complex_subscript else NO
1654
1655         elif (
1656             prevp.parent
1657             and prevp.parent.type == syms.factor
1658             and prevp.type in MATH_OPERATORS
1659         ):
1660             return NO
1661
1662         elif (
1663             prevp.type == token.RIGHTSHIFT
1664             and prevp.parent
1665             and prevp.parent.type == syms.shift_expr
1666             and prevp.prev_sibling
1667             and prevp.prev_sibling.type == token.NAME
1668             and prevp.prev_sibling.value == "print"  # type: ignore
1669         ):
1670             # Python 2 print chevron
1671             return NO
1672
1673     elif prev.type in OPENING_BRACKETS:
1674         return NO
1675
1676     if p.type in {syms.parameters, syms.arglist}:
1677         # untyped function signatures or calls
1678         if not prev or prev.type != token.COMMA:
1679             return NO
1680
1681     elif p.type == syms.varargslist:
1682         # lambdas
1683         if prev and prev.type != token.COMMA:
1684             return NO
1685
1686     elif p.type == syms.typedargslist:
1687         # typed function signatures
1688         if not prev:
1689             return NO
1690
1691         if t == token.EQUAL:
1692             if prev.type != syms.tname:
1693                 return NO
1694
1695         elif prev.type == token.EQUAL:
1696             # A bit hacky: if the equal sign has whitespace, it means we
1697             # previously found it's a typed argument.  So, we're using that, too.
1698             return prev.prefix
1699
1700         elif prev.type != token.COMMA:
1701             return NO
1702
1703     elif p.type == syms.tname:
1704         # type names
1705         if not prev:
1706             prevp = preceding_leaf(p)
1707             if not prevp or prevp.type != token.COMMA:
1708                 return NO
1709
1710     elif p.type == syms.trailer:
1711         # attributes and calls
1712         if t == token.LPAR or t == token.RPAR:
1713             return NO
1714
1715         if not prev:
1716             if t == token.DOT:
1717                 prevp = preceding_leaf(p)
1718                 if not prevp or prevp.type != token.NUMBER:
1719                     return NO
1720
1721             elif t == token.LSQB:
1722                 return NO
1723
1724         elif prev.type != token.COMMA:
1725             return NO
1726
1727     elif p.type == syms.argument:
1728         # single argument
1729         if t == token.EQUAL:
1730             return NO
1731
1732         if not prev:
1733             prevp = preceding_leaf(p)
1734             if not prevp or prevp.type == token.LPAR:
1735                 return NO
1736
1737         elif prev.type in {token.EQUAL} | STARS:
1738             return NO
1739
1740     elif p.type == syms.decorator:
1741         # decorators
1742         return NO
1743
1744     elif p.type == syms.dotted_name:
1745         if prev:
1746             return NO
1747
1748         prevp = preceding_leaf(p)
1749         if not prevp or prevp.type == token.AT or prevp.type == token.DOT:
1750             return NO
1751
1752     elif p.type == syms.classdef:
1753         if t == token.LPAR:
1754             return NO
1755
1756         if prev and prev.type == token.LPAR:
1757             return NO
1758
1759     elif p.type in {syms.subscript, syms.sliceop}:
1760         # indexing
1761         if not prev:
1762             assert p.parent is not None, "subscripts are always parented"
1763             if p.parent.type == syms.subscriptlist:
1764                 return SPACE
1765
1766             return NO
1767
1768         elif not complex_subscript:
1769             return NO
1770
1771     elif p.type == syms.atom:
1772         if prev and t == token.DOT:
1773             # dots, but not the first one.
1774             return NO
1775
1776     elif p.type == syms.dictsetmaker:
1777         # dict unpacking
1778         if prev and prev.type == token.DOUBLESTAR:
1779             return NO
1780
1781     elif p.type in {syms.factor, syms.star_expr}:
1782         # unary ops
1783         if not prev:
1784             prevp = preceding_leaf(p)
1785             if not prevp or prevp.type in OPENING_BRACKETS:
1786                 return NO
1787
1788             prevp_parent = prevp.parent
1789             assert prevp_parent is not None
1790             if prevp.type == token.COLON and prevp_parent.type in {
1791                 syms.subscript,
1792                 syms.sliceop,
1793             }:
1794                 return NO
1795
1796             elif prevp.type == token.EQUAL and prevp_parent.type == syms.argument:
1797                 return NO
1798
1799         elif t in {token.NAME, token.NUMBER, token.STRING}:
1800             return NO
1801
1802     elif p.type == syms.import_from:
1803         if t == token.DOT:
1804             if prev and prev.type == token.DOT:
1805                 return NO
1806
1807         elif t == token.NAME:
1808             if v == "import":
1809                 return SPACE
1810
1811             if prev and prev.type == token.DOT:
1812                 return NO
1813
1814     elif p.type == syms.sliceop:
1815         return NO
1816
1817     return SPACE
1818
1819
1820 def preceding_leaf(node: Optional[LN]) -> Optional[Leaf]:
1821     """Return the first leaf that precedes `node`, if any."""
1822     while node:
1823         res = node.prev_sibling
1824         if res:
1825             if isinstance(res, Leaf):
1826                 return res
1827
1828             try:
1829                 return list(res.leaves())[-1]
1830
1831             except IndexError:
1832                 return None
1833
1834         node = node.parent
1835     return None
1836
1837
1838 def child_towards(ancestor: Node, descendant: LN) -> Optional[LN]:
1839     """Return the child of `ancestor` that contains `descendant`."""
1840     node: Optional[LN] = descendant
1841     while node and node.parent != ancestor:
1842         node = node.parent
1843     return node
1844
1845
1846 def container_of(leaf: Leaf) -> LN:
1847     """Return `leaf` or one of its ancestors that is the topmost container of it.
1848
1849     By "container" we mean a node where `leaf` is the very first child.
1850     """
1851     same_prefix = leaf.prefix
1852     container: LN = leaf
1853     while container:
1854         parent = container.parent
1855         if parent is None:
1856             break
1857
1858         if parent.children[0].prefix != same_prefix:
1859             break
1860
1861         if parent.type == syms.file_input:
1862             break
1863
1864         if parent.prev_sibling is not None and parent.prev_sibling.type in BRACKETS:
1865             break
1866
1867         container = parent
1868     return container
1869
1870
1871 def is_split_after_delimiter(leaf: Leaf, previous: Leaf = None) -> int:
1872     """Return the priority of the `leaf` delimiter, given a line break after it.
1873
1874     The delimiter priorities returned here are from those delimiters that would
1875     cause a line break after themselves.
1876
1877     Higher numbers are higher priority.
1878     """
1879     if leaf.type == token.COMMA:
1880         return COMMA_PRIORITY
1881
1882     return 0
1883
1884
1885 def is_split_before_delimiter(leaf: Leaf, previous: Leaf = None) -> int:
1886     """Return the priority of the `leaf` delimiter, given a line before after it.
1887
1888     The delimiter priorities returned here are from those delimiters that would
1889     cause a line break before themselves.
1890
1891     Higher numbers are higher priority.
1892     """
1893     if is_vararg(leaf, within=VARARGS_PARENTS | UNPACKING_PARENTS):
1894         # * and ** might also be MATH_OPERATORS but in this case they are not.
1895         # Don't treat them as a delimiter.
1896         return 0
1897
1898     if (
1899         leaf.type == token.DOT
1900         and leaf.parent
1901         and leaf.parent.type not in {syms.import_from, syms.dotted_name}
1902         and (previous is None or previous.type in CLOSING_BRACKETS)
1903     ):
1904         return DOT_PRIORITY
1905
1906     if (
1907         leaf.type in MATH_OPERATORS
1908         and leaf.parent
1909         and leaf.parent.type not in {syms.factor, syms.star_expr}
1910     ):
1911         return MATH_PRIORITIES[leaf.type]
1912
1913     if leaf.type in COMPARATORS:
1914         return COMPARATOR_PRIORITY
1915
1916     if (
1917         leaf.type == token.STRING
1918         and previous is not None
1919         and previous.type == token.STRING
1920     ):
1921         return STRING_PRIORITY
1922
1923     if leaf.type != token.NAME:
1924         return 0
1925
1926     if (
1927         leaf.value == "for"
1928         and leaf.parent
1929         and leaf.parent.type in {syms.comp_for, syms.old_comp_for}
1930     ):
1931         return COMPREHENSION_PRIORITY
1932
1933     if (
1934         leaf.value == "if"
1935         and leaf.parent
1936         and leaf.parent.type in {syms.comp_if, syms.old_comp_if}
1937     ):
1938         return COMPREHENSION_PRIORITY
1939
1940     if leaf.value in {"if", "else"} and leaf.parent and leaf.parent.type == syms.test:
1941         return TERNARY_PRIORITY
1942
1943     if leaf.value == "is":
1944         return COMPARATOR_PRIORITY
1945
1946     if (
1947         leaf.value == "in"
1948         and leaf.parent
1949         and leaf.parent.type in {syms.comp_op, syms.comparison}
1950         and not (
1951             previous is not None
1952             and previous.type == token.NAME
1953             and previous.value == "not"
1954         )
1955     ):
1956         return COMPARATOR_PRIORITY
1957
1958     if (
1959         leaf.value == "not"
1960         and leaf.parent
1961         and leaf.parent.type == syms.comp_op
1962         and not (
1963             previous is not None
1964             and previous.type == token.NAME
1965             and previous.value == "is"
1966         )
1967     ):
1968         return COMPARATOR_PRIORITY
1969
1970     if leaf.value in LOGIC_OPERATORS and leaf.parent:
1971         return LOGIC_PRIORITY
1972
1973     return 0
1974
1975
1976 FMT_OFF = {"# fmt: off", "# fmt:off", "# yapf: disable"}
1977 FMT_ON = {"# fmt: on", "# fmt:on", "# yapf: enable"}
1978
1979
1980 def generate_comments(leaf: LN) -> Iterator[Leaf]:
1981     """Clean the prefix of the `leaf` and generate comments from it, if any.
1982
1983     Comments in lib2to3 are shoved into the whitespace prefix.  This happens
1984     in `pgen2/driver.py:Driver.parse_tokens()`.  This was a brilliant implementation
1985     move because it does away with modifying the grammar to include all the
1986     possible places in which comments can be placed.
1987
1988     The sad consequence for us though is that comments don't "belong" anywhere.
1989     This is why this function generates simple parentless Leaf objects for
1990     comments.  We simply don't know what the correct parent should be.
1991
1992     No matter though, we can live without this.  We really only need to
1993     differentiate between inline and standalone comments.  The latter don't
1994     share the line with any code.
1995
1996     Inline comments are emitted as regular token.COMMENT leaves.  Standalone
1997     are emitted with a fake STANDALONE_COMMENT token identifier.
1998     """
1999     for pc in list_comments(leaf.prefix, is_endmarker=leaf.type == token.ENDMARKER):
2000         yield Leaf(pc.type, pc.value, prefix="\n" * pc.newlines)
2001
2002
2003 @dataclass
2004 class ProtoComment:
2005     type: int  # token.COMMENT or STANDALONE_COMMENT
2006     value: str  # content of the comment
2007     newlines: int  # how many newlines before the comment
2008     consumed: int  # how many characters of the original leaf's prefix did we consume
2009
2010
2011 @lru_cache(maxsize=4096)
2012 def list_comments(prefix: str, *, is_endmarker: bool) -> List[ProtoComment]:
2013     result: List[ProtoComment] = []
2014     if not prefix or "#" not in prefix:
2015         return result
2016
2017     consumed = 0
2018     nlines = 0
2019     for index, line in enumerate(prefix.split("\n")):
2020         consumed += len(line) + 1  # adding the length of the split '\n'
2021         line = line.lstrip()
2022         if not line:
2023             nlines += 1
2024         if not line.startswith("#"):
2025             continue
2026
2027         if index == 0 and not is_endmarker:
2028             comment_type = token.COMMENT  # simple trailing comment
2029         else:
2030             comment_type = STANDALONE_COMMENT
2031         comment = make_comment(line)
2032         result.append(
2033             ProtoComment(
2034                 type=comment_type, value=comment, newlines=nlines, consumed=consumed
2035             )
2036         )
2037         nlines = 0
2038     return result
2039
2040
2041 def make_comment(content: str) -> str:
2042     """Return a consistently formatted comment from the given `content` string.
2043
2044     All comments (except for "##", "#!", "#:") should have a single space between
2045     the hash sign and the content.
2046
2047     If `content` didn't start with a hash sign, one is provided.
2048     """
2049     content = content.rstrip()
2050     if not content:
2051         return "#"
2052
2053     if content[0] == "#":
2054         content = content[1:]
2055     if content and content[0] not in " !:#":
2056         content = " " + content
2057     return "#" + content
2058
2059
2060 def split_line(
2061     line: Line, line_length: int, inner: bool = False, py36: bool = False
2062 ) -> Iterator[Line]:
2063     """Split a `line` into potentially many lines.
2064
2065     They should fit in the allotted `line_length` but might not be able to.
2066     `inner` signifies that there were a pair of brackets somewhere around the
2067     current `line`, possibly transitively. This means we can fallback to splitting
2068     by delimiters if the LHS/RHS don't yield any results.
2069
2070     If `py36` is True, splitting may generate syntax that is only compatible
2071     with Python 3.6 and later.
2072     """
2073     if line.is_comment:
2074         yield line
2075         return
2076
2077     line_str = str(line).strip("\n")
2078     if not line.should_explode and is_line_short_enough(
2079         line, line_length=line_length, line_str=line_str
2080     ):
2081         yield line
2082         return
2083
2084     split_funcs: List[SplitFunc]
2085     if line.is_def:
2086         split_funcs = [left_hand_split]
2087     else:
2088
2089         def rhs(line: Line, py36: bool = False) -> Iterator[Line]:
2090             for omit in generate_trailers_to_omit(line, line_length):
2091                 lines = list(right_hand_split(line, line_length, py36, omit=omit))
2092                 if is_line_short_enough(lines[0], line_length=line_length):
2093                     yield from lines
2094                     return
2095
2096             # All splits failed, best effort split with no omits.
2097             # This mostly happens to multiline strings that are by definition
2098             # reported as not fitting a single line.
2099             yield from right_hand_split(line, py36)
2100
2101         if line.inside_brackets:
2102             split_funcs = [delimiter_split, standalone_comment_split, rhs]
2103         else:
2104             split_funcs = [rhs]
2105     for split_func in split_funcs:
2106         # We are accumulating lines in `result` because we might want to abort
2107         # mission and return the original line in the end, or attempt a different
2108         # split altogether.
2109         result: List[Line] = []
2110         try:
2111             for l in split_func(line, py36):
2112                 if str(l).strip("\n") == line_str:
2113                     raise CannotSplit("Split function returned an unchanged result")
2114
2115                 result.extend(
2116                     split_line(l, line_length=line_length, inner=True, py36=py36)
2117                 )
2118         except CannotSplit as cs:
2119             continue
2120
2121         else:
2122             yield from result
2123             break
2124
2125     else:
2126         yield line
2127
2128
2129 def left_hand_split(line: Line, py36: bool = False) -> Iterator[Line]:
2130     """Split line into many lines, starting with the first matching bracket pair.
2131
2132     Note: this usually looks weird, only use this for function definitions.
2133     Prefer RHS otherwise.  This is why this function is not symmetrical with
2134     :func:`right_hand_split` which also handles optional parentheses.
2135     """
2136     head = Line(depth=line.depth)
2137     body = Line(depth=line.depth + 1, inside_brackets=True)
2138     tail = Line(depth=line.depth)
2139     tail_leaves: List[Leaf] = []
2140     body_leaves: List[Leaf] = []
2141     head_leaves: List[Leaf] = []
2142     current_leaves = head_leaves
2143     matching_bracket = None
2144     for leaf in line.leaves:
2145         if (
2146             current_leaves is body_leaves
2147             and leaf.type in CLOSING_BRACKETS
2148             and leaf.opening_bracket is matching_bracket
2149         ):
2150             current_leaves = tail_leaves if body_leaves else head_leaves
2151         current_leaves.append(leaf)
2152         if current_leaves is head_leaves:
2153             if leaf.type in OPENING_BRACKETS:
2154                 matching_bracket = leaf
2155                 current_leaves = body_leaves
2156     # Since body is a new indent level, remove spurious leading whitespace.
2157     if body_leaves:
2158         normalize_prefix(body_leaves[0], inside_brackets=True)
2159     # Build the new lines.
2160     for result, leaves in (head, head_leaves), (body, body_leaves), (tail, tail_leaves):
2161         for leaf in leaves:
2162             result.append(leaf, preformatted=True)
2163             for comment_after in line.comments_after(leaf):
2164                 result.append(comment_after, preformatted=True)
2165     bracket_split_succeeded_or_raise(head, body, tail)
2166     for result in (head, body, tail):
2167         if result:
2168             yield result
2169
2170
2171 def right_hand_split(
2172     line: Line, line_length: int, py36: bool = False, omit: Collection[LeafID] = ()
2173 ) -> Iterator[Line]:
2174     """Split line into many lines, starting with the last matching bracket pair.
2175
2176     If the split was by optional parentheses, attempt splitting without them, too.
2177     `omit` is a collection of closing bracket IDs that shouldn't be considered for
2178     this split.
2179
2180     Note: running this function modifies `bracket_depth` on the leaves of `line`.
2181     """
2182     head = Line(depth=line.depth)
2183     body = Line(depth=line.depth + 1, inside_brackets=True)
2184     tail = Line(depth=line.depth)
2185     tail_leaves: List[Leaf] = []
2186     body_leaves: List[Leaf] = []
2187     head_leaves: List[Leaf] = []
2188     current_leaves = tail_leaves
2189     opening_bracket = None
2190     closing_bracket = None
2191     for leaf in reversed(line.leaves):
2192         if current_leaves is body_leaves:
2193             if leaf is opening_bracket:
2194                 current_leaves = head_leaves if body_leaves else tail_leaves
2195         current_leaves.append(leaf)
2196         if current_leaves is tail_leaves:
2197             if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit:
2198                 opening_bracket = leaf.opening_bracket
2199                 closing_bracket = leaf
2200                 current_leaves = body_leaves
2201     tail_leaves.reverse()
2202     body_leaves.reverse()
2203     head_leaves.reverse()
2204     # Since body is a new indent level, remove spurious leading whitespace.
2205     if body_leaves:
2206         normalize_prefix(body_leaves[0], inside_brackets=True)
2207     if not head_leaves:
2208         # No `head` means the split failed. Either `tail` has all content or
2209         # the matching `opening_bracket` wasn't available on `line` anymore.
2210         raise CannotSplit("No brackets found")
2211
2212     # Build the new lines.
2213     for result, leaves in (head, head_leaves), (body, body_leaves), (tail, tail_leaves):
2214         for leaf in leaves:
2215             result.append(leaf, preformatted=True)
2216             for comment_after in line.comments_after(leaf):
2217                 result.append(comment_after, preformatted=True)
2218     assert opening_bracket and closing_bracket
2219     body.should_explode = should_explode(body, opening_bracket)
2220     bracket_split_succeeded_or_raise(head, body, tail)
2221     if (
2222         # the body shouldn't be exploded
2223         not body.should_explode
2224         # the opening bracket is an optional paren
2225         and opening_bracket.type == token.LPAR
2226         and not opening_bracket.value
2227         # the closing bracket is an optional paren
2228         and closing_bracket.type == token.RPAR
2229         and not closing_bracket.value
2230         # it's not an import (optional parens are the only thing we can split on
2231         # in this case; attempting a split without them is a waste of time)
2232         and not line.is_import
2233         # there are no standalone comments in the body
2234         and not body.contains_standalone_comments(0)
2235         # and we can actually remove the parens
2236         and can_omit_invisible_parens(body, line_length)
2237     ):
2238         omit = {id(closing_bracket), *omit}
2239         try:
2240             yield from right_hand_split(line, line_length, py36=py36, omit=omit)
2241             return
2242
2243         except CannotSplit:
2244             if not (
2245                 can_be_split(body)
2246                 or is_line_short_enough(body, line_length=line_length)
2247             ):
2248                 raise CannotSplit(
2249                     "Splitting failed, body is still too long and can't be split."
2250                 )
2251
2252             elif head.contains_multiline_strings() or tail.contains_multiline_strings():
2253                 raise CannotSplit(
2254                     "The current optional pair of parentheses is bound to fail to "
2255                     "satisfy the splitting algorithm because the head or the tail "
2256                     "contains multiline strings which by definition never fit one "
2257                     "line."
2258                 )
2259
2260     ensure_visible(opening_bracket)
2261     ensure_visible(closing_bracket)
2262     for result in (head, body, tail):
2263         if result:
2264             yield result
2265
2266
2267 def bracket_split_succeeded_or_raise(head: Line, body: Line, tail: Line) -> None:
2268     """Raise :exc:`CannotSplit` if the last left- or right-hand split failed.
2269
2270     Do nothing otherwise.
2271
2272     A left- or right-hand split is based on a pair of brackets. Content before
2273     (and including) the opening bracket is left on one line, content inside the
2274     brackets is put on a separate line, and finally content starting with and
2275     following the closing bracket is put on a separate line.
2276
2277     Those are called `head`, `body`, and `tail`, respectively. If the split
2278     produced the same line (all content in `head`) or ended up with an empty `body`
2279     and the `tail` is just the closing bracket, then it's considered failed.
2280     """
2281     tail_len = len(str(tail).strip())
2282     if not body:
2283         if tail_len == 0:
2284             raise CannotSplit("Splitting brackets produced the same line")
2285
2286         elif tail_len < 3:
2287             raise CannotSplit(
2288                 f"Splitting brackets on an empty body to save "
2289                 f"{tail_len} characters is not worth it"
2290             )
2291
2292
2293 def dont_increase_indentation(split_func: SplitFunc) -> SplitFunc:
2294     """Normalize prefix of the first leaf in every line returned by `split_func`.
2295
2296     This is a decorator over relevant split functions.
2297     """
2298
2299     @wraps(split_func)
2300     def split_wrapper(line: Line, py36: bool = False) -> Iterator[Line]:
2301         for l in split_func(line, py36):
2302             normalize_prefix(l.leaves[0], inside_brackets=True)
2303             yield l
2304
2305     return split_wrapper
2306
2307
2308 @dont_increase_indentation
2309 def delimiter_split(line: Line, py36: bool = False) -> Iterator[Line]:
2310     """Split according to delimiters of the highest priority.
2311
2312     If `py36` is True, the split will add trailing commas also in function
2313     signatures that contain `*` and `**`.
2314     """
2315     try:
2316         last_leaf = line.leaves[-1]
2317     except IndexError:
2318         raise CannotSplit("Line empty")
2319
2320     bt = line.bracket_tracker
2321     try:
2322         delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)})
2323     except ValueError:
2324         raise CannotSplit("No delimiters found")
2325
2326     if delimiter_priority == DOT_PRIORITY:
2327         if bt.delimiter_count_with_priority(delimiter_priority) == 1:
2328             raise CannotSplit("Splitting a single attribute from its owner looks wrong")
2329
2330     current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2331     lowest_depth = sys.maxsize
2332     trailing_comma_safe = True
2333
2334     def append_to_line(leaf: Leaf) -> Iterator[Line]:
2335         """Append `leaf` to current line or to new line if appending impossible."""
2336         nonlocal current_line
2337         try:
2338             current_line.append_safe(leaf, preformatted=True)
2339         except ValueError as ve:
2340             yield current_line
2341
2342             current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2343             current_line.append(leaf)
2344
2345     for index, leaf in enumerate(line.leaves):
2346         yield from append_to_line(leaf)
2347
2348         for comment_after in line.comments_after(leaf, index):
2349             yield from append_to_line(comment_after)
2350
2351         lowest_depth = min(lowest_depth, leaf.bracket_depth)
2352         if leaf.bracket_depth == lowest_depth and is_vararg(
2353             leaf, within=VARARGS_PARENTS
2354         ):
2355             trailing_comma_safe = trailing_comma_safe and py36
2356         leaf_priority = bt.delimiters.get(id(leaf))
2357         if leaf_priority == delimiter_priority:
2358             yield current_line
2359
2360             current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2361     if current_line:
2362         if (
2363             trailing_comma_safe
2364             and delimiter_priority == COMMA_PRIORITY
2365             and current_line.leaves[-1].type != token.COMMA
2366             and current_line.leaves[-1].type != STANDALONE_COMMENT
2367         ):
2368             current_line.append(Leaf(token.COMMA, ","))
2369         yield current_line
2370
2371
2372 @dont_increase_indentation
2373 def standalone_comment_split(line: Line, py36: bool = False) -> Iterator[Line]:
2374     """Split standalone comments from the rest of the line."""
2375     if not line.contains_standalone_comments(0):
2376         raise CannotSplit("Line does not have any standalone comments")
2377
2378     current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2379
2380     def append_to_line(leaf: Leaf) -> Iterator[Line]:
2381         """Append `leaf` to current line or to new line if appending impossible."""
2382         nonlocal current_line
2383         try:
2384             current_line.append_safe(leaf, preformatted=True)
2385         except ValueError as ve:
2386             yield current_line
2387
2388             current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2389             current_line.append(leaf)
2390
2391     for index, leaf in enumerate(line.leaves):
2392         yield from append_to_line(leaf)
2393
2394         for comment_after in line.comments_after(leaf, index):
2395             yield from append_to_line(comment_after)
2396
2397     if current_line:
2398         yield current_line
2399
2400
2401 def is_import(leaf: Leaf) -> bool:
2402     """Return True if the given leaf starts an import statement."""
2403     p = leaf.parent
2404     t = leaf.type
2405     v = leaf.value
2406     return bool(
2407         t == token.NAME
2408         and (
2409             (v == "import" and p and p.type == syms.import_name)
2410             or (v == "from" and p and p.type == syms.import_from)
2411         )
2412     )
2413
2414
2415 def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
2416     """Leave existing extra newlines if not `inside_brackets`. Remove everything
2417     else.
2418
2419     Note: don't use backslashes for formatting or you'll lose your voting rights.
2420     """
2421     if not inside_brackets:
2422         spl = leaf.prefix.split("#")
2423         if "\\" not in spl[0]:
2424             nl_count = spl[-1].count("\n")
2425             if len(spl) > 1:
2426                 nl_count -= 1
2427             leaf.prefix = "\n" * nl_count
2428             return
2429
2430     leaf.prefix = ""
2431
2432
2433 def normalize_string_prefix(leaf: Leaf, remove_u_prefix: bool = False) -> None:
2434     """Make all string prefixes lowercase.
2435
2436     If remove_u_prefix is given, also removes any u prefix from the string.
2437
2438     Note: Mutates its argument.
2439     """
2440     match = re.match(r"^([furbFURB]*)(.*)$", leaf.value, re.DOTALL)
2441     assert match is not None, f"failed to match string {leaf.value!r}"
2442     orig_prefix = match.group(1)
2443     new_prefix = orig_prefix.lower()
2444     if remove_u_prefix:
2445         new_prefix = new_prefix.replace("u", "")
2446     leaf.value = f"{new_prefix}{match.group(2)}"
2447
2448
2449 def normalize_string_quotes(leaf: Leaf) -> None:
2450     """Prefer double quotes but only if it doesn't cause more escaping.
2451
2452     Adds or removes backslashes as appropriate. Doesn't parse and fix
2453     strings nested in f-strings (yet).
2454
2455     Note: Mutates its argument.
2456     """
2457     value = leaf.value.lstrip("furbFURB")
2458     if value[:3] == '"""':
2459         return
2460
2461     elif value[:3] == "'''":
2462         orig_quote = "'''"
2463         new_quote = '"""'
2464     elif value[0] == '"':
2465         orig_quote = '"'
2466         new_quote = "'"
2467     else:
2468         orig_quote = "'"
2469         new_quote = '"'
2470     first_quote_pos = leaf.value.find(orig_quote)
2471     if first_quote_pos == -1:
2472         return  # There's an internal error
2473
2474     prefix = leaf.value[:first_quote_pos]
2475     unescaped_new_quote = re.compile(rf"(([^\\]|^)(\\\\)*){new_quote}")
2476     escaped_new_quote = re.compile(rf"([^\\]|^)\\((?:\\\\)*){new_quote}")
2477     escaped_orig_quote = re.compile(rf"([^\\]|^)\\((?:\\\\)*){orig_quote}")
2478     body = leaf.value[first_quote_pos + len(orig_quote) : -len(orig_quote)]
2479     if "r" in prefix.casefold():
2480         if unescaped_new_quote.search(body):
2481             # There's at least one unescaped new_quote in this raw string
2482             # so converting is impossible
2483             return
2484
2485         # Do not introduce or remove backslashes in raw strings
2486         new_body = body
2487     else:
2488         # remove unnecessary escapes
2489         new_body = sub_twice(escaped_new_quote, rf"\1\2{new_quote}", body)
2490         if body != new_body:
2491             # Consider the string without unnecessary escapes as the original
2492             body = new_body
2493             leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
2494         new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
2495         new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
2496     if "f" in prefix.casefold():
2497         matches = re.findall(r"[^{]\{(.*?)\}[^}]", new_body)
2498         for m in matches:
2499             if "\\" in str(m):
2500                 # Do not introduce backslashes in interpolated expressions
2501                 return
2502     if new_quote == '"""' and new_body[-1:] == '"':
2503         # edge case:
2504         new_body = new_body[:-1] + '\\"'
2505     orig_escape_count = body.count("\\")
2506     new_escape_count = new_body.count("\\")
2507     if new_escape_count > orig_escape_count:
2508         return  # Do not introduce more escaping
2509
2510     if new_escape_count == orig_escape_count and orig_quote == '"':
2511         return  # Prefer double quotes
2512
2513     leaf.value = f"{prefix}{new_quote}{new_body}{new_quote}"
2514
2515
2516 def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None:
2517     """Normalizes numeric (float, int, and complex) literals."""
2518     # We want all letters (e in exponents, j in complex literals, a-f
2519     # in hex literals) to be lowercase.
2520     text = leaf.value.lower()
2521     if text.startswith(("0o", "0x", "0b")):
2522         # Leave octal, hex, and binary literals alone for now.
2523         pass
2524     elif "e" in text:
2525         before, after = text.split("e")
2526         if after.startswith("-"):
2527             after = after[1:]
2528             sign = "-"
2529         elif after.startswith("+"):
2530             after = after[1:]
2531             sign = ""
2532         else:
2533             sign = ""
2534         before = format_float_or_int_string(before, allow_underscores)
2535         after = format_int_string(after, allow_underscores)
2536         text = f"{before}e{sign}{after}"
2537     # Complex numbers and Python 2 longs
2538     elif "j" in text or "l" in text:
2539         number = text[:-1]
2540         suffix = text[-1]
2541         text = f"{format_float_or_int_string(number, allow_underscores)}{suffix}"
2542     else:
2543         text = format_float_or_int_string(text, allow_underscores)
2544     leaf.value = text
2545
2546
2547 def format_float_or_int_string(text: str, allow_underscores: bool) -> str:
2548     """Formats a float string like "1.0"."""
2549     if "." not in text:
2550         return format_int_string(text, allow_underscores)
2551     before, after = text.split(".")
2552     before = format_int_string(before, allow_underscores) if before else "0"
2553     after = format_int_string(after, allow_underscores) if after else "0"
2554     return f"{before}.{after}"
2555
2556
2557 def format_int_string(text: str, allow_underscores: bool) -> str:
2558     """Normalizes underscores in a string to e.g. 1_000_000.
2559
2560     Input must be a string consisting only of digits and underscores.
2561     """
2562     if not allow_underscores:
2563         return text
2564     text = text.replace("_", "")
2565     if len(text) <= 6:
2566         # No underscores for numbers <= 6 digits long.
2567         return text
2568     return format(int(text), "3_")
2569
2570
2571 def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None:
2572     """Make existing optional parentheses invisible or create new ones.
2573
2574     `parens_after` is a set of string leaf values immeditely after which parens
2575     should be put.
2576
2577     Standardizes on visible parentheses for single-element tuples, and keeps
2578     existing visible parentheses for other tuples and generator expressions.
2579     """
2580     for pc in list_comments(node.prefix, is_endmarker=False):
2581         if pc.value in FMT_OFF:
2582             # This `node` has a prefix with `# fmt: off`, don't mess with parens.
2583             return
2584
2585     check_lpar = False
2586     for index, child in enumerate(list(node.children)):
2587         if check_lpar:
2588             if child.type == syms.atom:
2589                 maybe_make_parens_invisible_in_atom(child)
2590             elif is_one_tuple(child):
2591                 # wrap child in visible parentheses
2592                 lpar = Leaf(token.LPAR, "(")
2593                 rpar = Leaf(token.RPAR, ")")
2594                 child.remove()
2595                 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2596             elif node.type == syms.import_from:
2597                 # "import from" nodes store parentheses directly as part of
2598                 # the statement
2599                 if child.type == token.LPAR:
2600                     # make parentheses invisible
2601                     child.value = ""  # type: ignore
2602                     node.children[-1].value = ""  # type: ignore
2603                 elif child.type != token.STAR:
2604                     # insert invisible parentheses
2605                     node.insert_child(index, Leaf(token.LPAR, ""))
2606                     node.append_child(Leaf(token.RPAR, ""))
2607                 break
2608
2609             elif not (isinstance(child, Leaf) and is_multiline_string(child)):
2610                 # wrap child in invisible parentheses
2611                 lpar = Leaf(token.LPAR, "")
2612                 rpar = Leaf(token.RPAR, "")
2613                 index = child.remove() or 0
2614                 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2615
2616         check_lpar = isinstance(child, Leaf) and child.value in parens_after
2617
2618
2619 def normalize_fmt_off(node: Node) -> None:
2620     """Convert content between `# fmt: off`/`# fmt: on` into standalone comments."""
2621     try_again = True
2622     while try_again:
2623         try_again = convert_one_fmt_off_pair(node)
2624
2625
2626 def convert_one_fmt_off_pair(node: Node) -> bool:
2627     """Convert content of a single `# fmt: off`/`# fmt: on` into a standalone comment.
2628
2629     Returns True if a pair was converted.
2630     """
2631     for leaf in node.leaves():
2632         previous_consumed = 0
2633         for comment in list_comments(leaf.prefix, is_endmarker=False):
2634             if comment.value in FMT_OFF:
2635                 # We only want standalone comments. If there's no previous leaf or
2636                 # the previous leaf is indentation, it's a standalone comment in
2637                 # disguise.
2638                 if comment.type != STANDALONE_COMMENT:
2639                     prev = preceding_leaf(leaf)
2640                     if prev and prev.type not in WHITESPACE:
2641                         continue
2642
2643                 ignored_nodes = list(generate_ignored_nodes(leaf))
2644                 if not ignored_nodes:
2645                     continue
2646
2647                 first = ignored_nodes[0]  # Can be a container node with the `leaf`.
2648                 parent = first.parent
2649                 prefix = first.prefix
2650                 first.prefix = prefix[comment.consumed :]
2651                 hidden_value = (
2652                     comment.value + "\n" + "".join(str(n) for n in ignored_nodes)
2653                 )
2654                 if hidden_value.endswith("\n"):
2655                     # That happens when one of the `ignored_nodes` ended with a NEWLINE
2656                     # leaf (possibly followed by a DEDENT).
2657                     hidden_value = hidden_value[:-1]
2658                 first_idx = None
2659                 for ignored in ignored_nodes:
2660                     index = ignored.remove()
2661                     if first_idx is None:
2662                         first_idx = index
2663                 assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)"
2664                 assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)"
2665                 parent.insert_child(
2666                     first_idx,
2667                     Leaf(
2668                         STANDALONE_COMMENT,
2669                         hidden_value,
2670                         prefix=prefix[:previous_consumed] + "\n" * comment.newlines,
2671                     ),
2672                 )
2673                 return True
2674
2675             previous_consumed = comment.consumed
2676
2677     return False
2678
2679
2680 def generate_ignored_nodes(leaf: Leaf) -> Iterator[LN]:
2681     """Starting from the container of `leaf`, generate all leaves until `# fmt: on`.
2682
2683     Stops at the end of the block.
2684     """
2685     container: Optional[LN] = container_of(leaf)
2686     while container is not None and container.type != token.ENDMARKER:
2687         for comment in list_comments(container.prefix, is_endmarker=False):
2688             if comment.value in FMT_ON:
2689                 return
2690
2691         yield container
2692
2693         container = container.next_sibling
2694
2695
2696 def maybe_make_parens_invisible_in_atom(node: LN) -> bool:
2697     """If it's safe, make the parens in the atom `node` invisible, recursively."""
2698     if (
2699         node.type != syms.atom
2700         or is_empty_tuple(node)
2701         or is_one_tuple(node)
2702         or is_yield(node)
2703         or max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
2704     ):
2705         return False
2706
2707     first = node.children[0]
2708     last = node.children[-1]
2709     if first.type == token.LPAR and last.type == token.RPAR:
2710         # make parentheses invisible
2711         first.value = ""  # type: ignore
2712         last.value = ""  # type: ignore
2713         if len(node.children) > 1:
2714             maybe_make_parens_invisible_in_atom(node.children[1])
2715         return True
2716
2717     return False
2718
2719
2720 def is_empty_tuple(node: LN) -> bool:
2721     """Return True if `node` holds an empty tuple."""
2722     return (
2723         node.type == syms.atom
2724         and len(node.children) == 2
2725         and node.children[0].type == token.LPAR
2726         and node.children[1].type == token.RPAR
2727     )
2728
2729
2730 def is_one_tuple(node: LN) -> bool:
2731     """Return True if `node` holds a tuple with one element, with or without parens."""
2732     if node.type == syms.atom:
2733         if len(node.children) != 3:
2734             return False
2735
2736         lpar, gexp, rpar = node.children
2737         if not (
2738             lpar.type == token.LPAR
2739             and gexp.type == syms.testlist_gexp
2740             and rpar.type == token.RPAR
2741         ):
2742             return False
2743
2744         return len(gexp.children) == 2 and gexp.children[1].type == token.COMMA
2745
2746     return (
2747         node.type in IMPLICIT_TUPLE
2748         and len(node.children) == 2
2749         and node.children[1].type == token.COMMA
2750     )
2751
2752
2753 def is_yield(node: LN) -> bool:
2754     """Return True if `node` holds a `yield` or `yield from` expression."""
2755     if node.type == syms.yield_expr:
2756         return True
2757
2758     if node.type == token.NAME and node.value == "yield":  # type: ignore
2759         return True
2760
2761     if node.type != syms.atom:
2762         return False
2763
2764     if len(node.children) != 3:
2765         return False
2766
2767     lpar, expr, rpar = node.children
2768     if lpar.type == token.LPAR and rpar.type == token.RPAR:
2769         return is_yield(expr)
2770
2771     return False
2772
2773
2774 def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool:
2775     """Return True if `leaf` is a star or double star in a vararg or kwarg.
2776
2777     If `within` includes VARARGS_PARENTS, this applies to function signatures.
2778     If `within` includes UNPACKING_PARENTS, it applies to right hand-side
2779     extended iterable unpacking (PEP 3132) and additional unpacking
2780     generalizations (PEP 448).
2781     """
2782     if leaf.type not in STARS or not leaf.parent:
2783         return False
2784
2785     p = leaf.parent
2786     if p.type == syms.star_expr:
2787         # Star expressions are also used as assignment targets in extended
2788         # iterable unpacking (PEP 3132).  See what its parent is instead.
2789         if not p.parent:
2790             return False
2791
2792         p = p.parent
2793
2794     return p.type in within
2795
2796
2797 def is_multiline_string(leaf: Leaf) -> bool:
2798     """Return True if `leaf` is a multiline string that actually spans many lines."""
2799     value = leaf.value.lstrip("furbFURB")
2800     return value[:3] in {'"""', "'''"} and "\n" in value
2801
2802
2803 def is_stub_suite(node: Node) -> bool:
2804     """Return True if `node` is a suite with a stub body."""
2805     if (
2806         len(node.children) != 4
2807         or node.children[0].type != token.NEWLINE
2808         or node.children[1].type != token.INDENT
2809         or node.children[3].type != token.DEDENT
2810     ):
2811         return False
2812
2813     return is_stub_body(node.children[2])
2814
2815
2816 def is_stub_body(node: LN) -> bool:
2817     """Return True if `node` is a simple statement containing an ellipsis."""
2818     if not isinstance(node, Node) or node.type != syms.simple_stmt:
2819         return False
2820
2821     if len(node.children) != 2:
2822         return False
2823
2824     child = node.children[0]
2825     return (
2826         child.type == syms.atom
2827         and len(child.children) == 3
2828         and all(leaf == Leaf(token.DOT, ".") for leaf in child.children)
2829     )
2830
2831
2832 def max_delimiter_priority_in_atom(node: LN) -> int:
2833     """Return maximum delimiter priority inside `node`.
2834
2835     This is specific to atoms with contents contained in a pair of parentheses.
2836     If `node` isn't an atom or there are no enclosing parentheses, returns 0.
2837     """
2838     if node.type != syms.atom:
2839         return 0
2840
2841     first = node.children[0]
2842     last = node.children[-1]
2843     if not (first.type == token.LPAR and last.type == token.RPAR):
2844         return 0
2845
2846     bt = BracketTracker()
2847     for c in node.children[1:-1]:
2848         if isinstance(c, Leaf):
2849             bt.mark(c)
2850         else:
2851             for leaf in c.leaves():
2852                 bt.mark(leaf)
2853     try:
2854         return bt.max_delimiter_priority()
2855
2856     except ValueError:
2857         return 0
2858
2859
2860 def ensure_visible(leaf: Leaf) -> None:
2861     """Make sure parentheses are visible.
2862
2863     They could be invisible as part of some statements (see
2864     :func:`normalize_invible_parens` and :func:`visit_import_from`).
2865     """
2866     if leaf.type == token.LPAR:
2867         leaf.value = "("
2868     elif leaf.type == token.RPAR:
2869         leaf.value = ")"
2870
2871
2872 def should_explode(line: Line, opening_bracket: Leaf) -> bool:
2873     """Should `line` immediately be split with `delimiter_split()` after RHS?"""
2874     if not (
2875         opening_bracket.parent
2876         and opening_bracket.parent.type in {syms.atom, syms.import_from}
2877         and opening_bracket.value in "[{("
2878     ):
2879         return False
2880
2881     try:
2882         last_leaf = line.leaves[-1]
2883         exclude = {id(last_leaf)} if last_leaf.type == token.COMMA else set()
2884         max_priority = line.bracket_tracker.max_delimiter_priority(exclude=exclude)
2885     except (IndexError, ValueError):
2886         return False
2887
2888     return max_priority == COMMA_PRIORITY
2889
2890
2891 def is_python36(node: Node) -> bool:
2892     """Return True if the current file is using Python 3.6+ features.
2893
2894     Currently looking for:
2895     - f-strings; and
2896     - trailing commas after * or ** in function signatures and calls.
2897     """
2898     for n in node.pre_order():
2899         if n.type == token.STRING:
2900             value_head = n.value[:2]  # type: ignore
2901             if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
2902                 return True
2903
2904         elif (
2905             n.type in {syms.typedargslist, syms.arglist}
2906             and n.children
2907             and n.children[-1].type == token.COMMA
2908         ):
2909             for ch in n.children:
2910                 if ch.type in STARS:
2911                     return True
2912
2913                 if ch.type == syms.argument:
2914                     for argch in ch.children:
2915                         if argch.type in STARS:
2916                             return True
2917
2918     return False
2919
2920
2921 def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[LeafID]]:
2922     """Generate sets of closing bracket IDs that should be omitted in a RHS.
2923
2924     Brackets can be omitted if the entire trailer up to and including
2925     a preceding closing bracket fits in one line.
2926
2927     Yielded sets are cumulative (contain results of previous yields, too).  First
2928     set is empty.
2929     """
2930
2931     omit: Set[LeafID] = set()
2932     yield omit
2933
2934     length = 4 * line.depth
2935     opening_bracket = None
2936     closing_bracket = None
2937     optional_brackets: Set[LeafID] = set()
2938     inner_brackets: Set[LeafID] = set()
2939     for index, leaf, leaf_length in enumerate_with_length(line, reversed=True):
2940         length += leaf_length
2941         if length > line_length:
2942             break
2943
2944         has_inline_comment = leaf_length > len(leaf.value) + len(leaf.prefix)
2945         if leaf.type == STANDALONE_COMMENT or has_inline_comment:
2946             break
2947
2948         optional_brackets.discard(id(leaf))
2949         if opening_bracket:
2950             if leaf is opening_bracket:
2951                 opening_bracket = None
2952             elif leaf.type in CLOSING_BRACKETS:
2953                 inner_brackets.add(id(leaf))
2954         elif leaf.type in CLOSING_BRACKETS:
2955             if not leaf.value:
2956                 optional_brackets.add(id(opening_bracket))
2957                 continue
2958
2959             if index > 0 and line.leaves[index - 1].type in OPENING_BRACKETS:
2960                 # Empty brackets would fail a split so treat them as "inner"
2961                 # brackets (e.g. only add them to the `omit` set if another
2962                 # pair of brackets was good enough.
2963                 inner_brackets.add(id(leaf))
2964                 continue
2965
2966             opening_bracket = leaf.opening_bracket
2967             if closing_bracket:
2968                 omit.add(id(closing_bracket))
2969                 omit.update(inner_brackets)
2970                 inner_brackets.clear()
2971                 yield omit
2972             closing_bracket = leaf
2973
2974
2975 def get_future_imports(node: Node) -> Set[str]:
2976     """Return a set of __future__ imports in the file."""
2977     imports: Set[str] = set()
2978
2979     def get_imports_from_children(children: List[LN]) -> Generator[str, None, None]:
2980         for child in children:
2981             if isinstance(child, Leaf):
2982                 if child.type == token.NAME:
2983                     yield child.value
2984             elif child.type == syms.import_as_name:
2985                 orig_name = child.children[0]
2986                 assert isinstance(orig_name, Leaf), "Invalid syntax parsing imports"
2987                 assert orig_name.type == token.NAME, "Invalid syntax parsing imports"
2988                 yield orig_name.value
2989             elif child.type == syms.import_as_names:
2990                 yield from get_imports_from_children(child.children)
2991             else:
2992                 assert False, "Invalid syntax parsing imports"
2993
2994     for child in node.children:
2995         if child.type != syms.simple_stmt:
2996             break
2997         first_child = child.children[0]
2998         if isinstance(first_child, Leaf):
2999             # Continue looking if we see a docstring; otherwise stop.
3000             if (
3001                 len(child.children) == 2
3002                 and first_child.type == token.STRING
3003                 and child.children[1].type == token.NEWLINE
3004             ):
3005                 continue
3006             else:
3007                 break
3008         elif first_child.type == syms.import_from:
3009             module_name = first_child.children[1]
3010             if not isinstance(module_name, Leaf) or module_name.value != "__future__":
3011                 break
3012             imports |= set(get_imports_from_children(first_child.children[3:]))
3013         else:
3014             break
3015     return imports
3016
3017
3018 def gen_python_files_in_dir(
3019     path: Path,
3020     root: Path,
3021     include: Pattern[str],
3022     exclude: Pattern[str],
3023     report: "Report",
3024 ) -> Iterator[Path]:
3025     """Generate all files under `path` whose paths are not excluded by the
3026     `exclude` regex, but are included by the `include` regex.
3027
3028     Symbolic links pointing outside of the `root` directory are ignored.
3029
3030     `report` is where output about exclusions goes.
3031     """
3032     assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}"
3033     for child in path.iterdir():
3034         try:
3035             normalized_path = "/" + child.resolve().relative_to(root).as_posix()
3036         except ValueError:
3037             if child.is_symlink():
3038                 report.path_ignored(
3039                     child, f"is a symbolic link that points outside {root}"
3040                 )
3041                 continue
3042
3043             raise
3044
3045         if child.is_dir():
3046             normalized_path += "/"
3047         exclude_match = exclude.search(normalized_path)
3048         if exclude_match and exclude_match.group(0):
3049             report.path_ignored(child, f"matches the --exclude regular expression")
3050             continue
3051
3052         if child.is_dir():
3053             yield from gen_python_files_in_dir(child, root, include, exclude, report)
3054
3055         elif child.is_file():
3056             include_match = include.search(normalized_path)
3057             if include_match:
3058                 yield child
3059
3060
3061 @lru_cache()
3062 def find_project_root(srcs: Iterable[str]) -> Path:
3063     """Return a directory containing .git, .hg, or pyproject.toml.
3064
3065     That directory can be one of the directories passed in `srcs` or their
3066     common parent.
3067
3068     If no directory in the tree contains a marker that would specify it's the
3069     project root, the root of the file system is returned.
3070     """
3071     if not srcs:
3072         return Path("/").resolve()
3073
3074     common_base = min(Path(src).resolve() for src in srcs)
3075     if common_base.is_dir():
3076         # Append a fake file so `parents` below returns `common_base_dir`, too.
3077         common_base /= "fake-file"
3078     for directory in common_base.parents:
3079         if (directory / ".git").is_dir():
3080             return directory
3081
3082         if (directory / ".hg").is_dir():
3083             return directory
3084
3085         if (directory / "pyproject.toml").is_file():
3086             return directory
3087
3088     return directory
3089
3090
3091 @dataclass
3092 class Report:
3093     """Provides a reformatting counter. Can be rendered with `str(report)`."""
3094
3095     check: bool = False
3096     quiet: bool = False
3097     verbose: bool = False
3098     change_count: int = 0
3099     same_count: int = 0
3100     failure_count: int = 0
3101
3102     def done(self, src: Path, changed: Changed) -> None:
3103         """Increment the counter for successful reformatting. Write out a message."""
3104         if changed is Changed.YES:
3105             reformatted = "would reformat" if self.check else "reformatted"
3106             if self.verbose or not self.quiet:
3107                 out(f"{reformatted} {src}")
3108             self.change_count += 1
3109         else:
3110             if self.verbose:
3111                 if changed is Changed.NO:
3112                     msg = f"{src} already well formatted, good job."
3113                 else:
3114                     msg = f"{src} wasn't modified on disk since last run."
3115                 out(msg, bold=False)
3116             self.same_count += 1
3117
3118     def failed(self, src: Path, message: str) -> None:
3119         """Increment the counter for failed reformatting. Write out a message."""
3120         err(f"error: cannot format {src}: {message}")
3121         self.failure_count += 1
3122
3123     def path_ignored(self, path: Path, message: str) -> None:
3124         if self.verbose:
3125             out(f"{path} ignored: {message}", bold=False)
3126
3127     @property
3128     def return_code(self) -> int:
3129         """Return the exit code that the app should use.
3130
3131         This considers the current state of changed files and failures:
3132         - if there were any failures, return 123;
3133         - if any files were changed and --check is being used, return 1;
3134         - otherwise return 0.
3135         """
3136         # According to http://tldp.org/LDP/abs/html/exitcodes.html starting with
3137         # 126 we have special returncodes reserved by the shell.
3138         if self.failure_count:
3139             return 123
3140
3141         elif self.change_count and self.check:
3142             return 1
3143
3144         return 0
3145
3146     def __str__(self) -> str:
3147         """Render a color report of the current state.
3148
3149         Use `click.unstyle` to remove colors.
3150         """
3151         if self.check:
3152             reformatted = "would be reformatted"
3153             unchanged = "would be left unchanged"
3154             failed = "would fail to reformat"
3155         else:
3156             reformatted = "reformatted"
3157             unchanged = "left unchanged"
3158             failed = "failed to reformat"
3159         report = []
3160         if self.change_count:
3161             s = "s" if self.change_count > 1 else ""
3162             report.append(
3163                 click.style(f"{self.change_count} file{s} {reformatted}", bold=True)
3164             )
3165         if self.same_count:
3166             s = "s" if self.same_count > 1 else ""
3167             report.append(f"{self.same_count} file{s} {unchanged}")
3168         if self.failure_count:
3169             s = "s" if self.failure_count > 1 else ""
3170             report.append(
3171                 click.style(f"{self.failure_count} file{s} {failed}", fg="red")
3172             )
3173         return ", ".join(report) + "."
3174
3175
3176 def assert_equivalent(src: str, dst: str) -> None:
3177     """Raise AssertionError if `src` and `dst` aren't equivalent."""
3178
3179     import ast
3180     import traceback
3181
3182     def _v(node: ast.AST, depth: int = 0) -> Iterator[str]:
3183         """Simple visitor generating strings to compare ASTs by content."""
3184         yield f"{'  ' * depth}{node.__class__.__name__}("
3185
3186         for field in sorted(node._fields):
3187             try:
3188                 value = getattr(node, field)
3189             except AttributeError:
3190                 continue
3191
3192             yield f"{'  ' * (depth+1)}{field}="
3193
3194             if isinstance(value, list):
3195                 for item in value:
3196                     if isinstance(item, ast.AST):
3197                         yield from _v(item, depth + 2)
3198
3199             elif isinstance(value, ast.AST):
3200                 yield from _v(value, depth + 2)
3201
3202             else:
3203                 yield f"{'  ' * (depth+2)}{value!r},  # {value.__class__.__name__}"
3204
3205         yield f"{'  ' * depth})  # /{node.__class__.__name__}"
3206
3207     try:
3208         src_ast = ast.parse(src)
3209     except Exception as exc:
3210         major, minor = sys.version_info[:2]
3211         raise AssertionError(
3212             f"cannot use --safe with this file; failed to parse source file "
3213             f"with Python {major}.{minor}'s builtin AST. Re-run with --fast "
3214             f"or stop using deprecated Python 2 syntax. AST error message: {exc}"
3215         )
3216
3217     try:
3218         dst_ast = ast.parse(dst)
3219     except Exception as exc:
3220         log = dump_to_file("".join(traceback.format_tb(exc.__traceback__)), dst)
3221         raise AssertionError(
3222             f"INTERNAL ERROR: Black produced invalid code: {exc}. "
3223             f"Please report a bug on https://github.com/ambv/black/issues.  "
3224             f"This invalid output might be helpful: {log}"
3225         ) from None
3226
3227     src_ast_str = "\n".join(_v(src_ast))
3228     dst_ast_str = "\n".join(_v(dst_ast))
3229     if src_ast_str != dst_ast_str:
3230         log = dump_to_file(diff(src_ast_str, dst_ast_str, "src", "dst"))
3231         raise AssertionError(
3232             f"INTERNAL ERROR: Black produced code that is not equivalent to "
3233             f"the source.  "
3234             f"Please report a bug on https://github.com/ambv/black/issues.  "
3235             f"This diff might be helpful: {log}"
3236         ) from None
3237
3238
3239 def assert_stable(
3240     src: str, dst: str, line_length: int, mode: FileMode = FileMode.AUTO_DETECT
3241 ) -> None:
3242     """Raise AssertionError if `dst` reformats differently the second time."""
3243     newdst = format_str(dst, line_length=line_length, mode=mode)
3244     if dst != newdst:
3245         log = dump_to_file(
3246             diff(src, dst, "source", "first pass"),
3247             diff(dst, newdst, "first pass", "second pass"),
3248         )
3249         raise AssertionError(
3250             f"INTERNAL ERROR: Black produced different code on the second pass "
3251             f"of the formatter.  "
3252             f"Please report a bug on https://github.com/ambv/black/issues.  "
3253             f"This diff might be helpful: {log}"
3254         ) from None
3255
3256
3257 def dump_to_file(*output: str) -> str:
3258     """Dump `output` to a temporary file. Return path to the file."""
3259     import tempfile
3260
3261     with tempfile.NamedTemporaryFile(
3262         mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8"
3263     ) as f:
3264         for lines in output:
3265             f.write(lines)
3266             if lines and lines[-1] != "\n":
3267                 f.write("\n")
3268     return f.name
3269
3270
3271 def diff(a: str, b: str, a_name: str, b_name: str) -> str:
3272     """Return a unified diff string between strings `a` and `b`."""
3273     import difflib
3274
3275     a_lines = [line + "\n" for line in a.split("\n")]
3276     b_lines = [line + "\n" for line in b.split("\n")]
3277     return "".join(
3278         difflib.unified_diff(a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5)
3279     )
3280
3281
3282 def cancel(tasks: Iterable[asyncio.Task]) -> None:
3283     """asyncio signal handler that cancels all `tasks` and reports to stderr."""
3284     err("Aborted!")
3285     for task in tasks:
3286         task.cancel()
3287
3288
3289 def shutdown(loop: BaseEventLoop) -> None:
3290     """Cancel all pending tasks on `loop`, wait for them, and close the loop."""
3291     try:
3292         # This part is borrowed from asyncio/runners.py in Python 3.7b2.
3293         to_cancel = [task for task in asyncio.Task.all_tasks(loop) if not task.done()]
3294         if not to_cancel:
3295             return
3296
3297         for task in to_cancel:
3298             task.cancel()
3299         loop.run_until_complete(
3300             asyncio.gather(*to_cancel, loop=loop, return_exceptions=True)
3301         )
3302     finally:
3303         # `concurrent.futures.Future` objects cannot be cancelled once they
3304         # are already running. There might be some when the `shutdown()` happened.
3305         # Silence their logger's spew about the event loop being closed.
3306         cf_logger = logging.getLogger("concurrent.futures")
3307         cf_logger.setLevel(logging.CRITICAL)
3308         loop.close()
3309
3310
3311 def sub_twice(regex: Pattern[str], replacement: str, original: str) -> str:
3312     """Replace `regex` with `replacement` twice on `original`.
3313
3314     This is used by string normalization to perform replaces on
3315     overlapping matches.
3316     """
3317     return regex.sub(replacement, regex.sub(replacement, original))
3318
3319
3320 def re_compile_maybe_verbose(regex: str) -> Pattern[str]:
3321     """Compile a regular expression string in `regex`.
3322
3323     If it contains newlines, use verbose mode.
3324     """
3325     if "\n" in regex:
3326         regex = "(?x)" + regex
3327     return re.compile(regex)
3328
3329
3330 def enumerate_reversed(sequence: Sequence[T]) -> Iterator[Tuple[Index, T]]:
3331     """Like `reversed(enumerate(sequence))` if that were possible."""
3332     index = len(sequence) - 1
3333     for element in reversed(sequence):
3334         yield (index, element)
3335         index -= 1
3336
3337
3338 def enumerate_with_length(
3339     line: Line, reversed: bool = False
3340 ) -> Iterator[Tuple[Index, Leaf, int]]:
3341     """Return an enumeration of leaves with their length.
3342
3343     Stops prematurely on multiline strings and standalone comments.
3344     """
3345     op = cast(
3346         Callable[[Sequence[Leaf]], Iterator[Tuple[Index, Leaf]]],
3347         enumerate_reversed if reversed else enumerate,
3348     )
3349     for index, leaf in op(line.leaves):
3350         length = len(leaf.prefix) + len(leaf.value)
3351         if "\n" in leaf.value:
3352             return  # Multiline strings, we can't continue.
3353
3354         comment: Optional[Leaf]
3355         for comment in line.comments_after(leaf, index):
3356             length += len(comment.value)
3357
3358         yield index, leaf, length
3359
3360
3361 def is_line_short_enough(line: Line, *, line_length: int, line_str: str = "") -> bool:
3362     """Return True if `line` is no longer than `line_length`.
3363
3364     Uses the provided `line_str` rendering, if any, otherwise computes a new one.
3365     """
3366     if not line_str:
3367         line_str = str(line).strip("\n")
3368     return (
3369         len(line_str) <= line_length
3370         and "\n" not in line_str  # multiline strings
3371         and not line.contains_standalone_comments()
3372     )
3373
3374
3375 def can_be_split(line: Line) -> bool:
3376     """Return False if the line cannot be split *for sure*.
3377
3378     This is not an exhaustive search but a cheap heuristic that we can use to
3379     avoid some unfortunate formattings (mostly around wrapping unsplittable code
3380     in unnecessary parentheses).
3381     """
3382     leaves = line.leaves
3383     if len(leaves) < 2:
3384         return False
3385
3386     if leaves[0].type == token.STRING and leaves[1].type == token.DOT:
3387         call_count = 0
3388         dot_count = 0
3389         next = leaves[-1]
3390         for leaf in leaves[-2::-1]:
3391             if leaf.type in OPENING_BRACKETS:
3392                 if next.type not in CLOSING_BRACKETS:
3393                     return False
3394
3395                 call_count += 1
3396             elif leaf.type == token.DOT:
3397                 dot_count += 1
3398             elif leaf.type == token.NAME:
3399                 if not (next.type == token.DOT or next.type in OPENING_BRACKETS):
3400                     return False
3401
3402             elif leaf.type not in CLOSING_BRACKETS:
3403                 return False
3404
3405             if dot_count > 1 and call_count > 1:
3406                 return False
3407
3408     return True
3409
3410
3411 def can_omit_invisible_parens(line: Line, line_length: int) -> bool:
3412     """Does `line` have a shape safe to reformat without optional parens around it?
3413
3414     Returns True for only a subset of potentially nice looking formattings but
3415     the point is to not return false positives that end up producing lines that
3416     are too long.
3417     """
3418     bt = line.bracket_tracker
3419     if not bt.delimiters:
3420         # Without delimiters the optional parentheses are useless.
3421         return True
3422
3423     max_priority = bt.max_delimiter_priority()
3424     if bt.delimiter_count_with_priority(max_priority) > 1:
3425         # With more than one delimiter of a kind the optional parentheses read better.
3426         return False
3427
3428     if max_priority == DOT_PRIORITY:
3429         # A single stranded method call doesn't require optional parentheses.
3430         return True
3431
3432     assert len(line.leaves) >= 2, "Stranded delimiter"
3433
3434     first = line.leaves[0]
3435     second = line.leaves[1]
3436     penultimate = line.leaves[-2]
3437     last = line.leaves[-1]
3438
3439     # With a single delimiter, omit if the expression starts or ends with
3440     # a bracket.
3441     if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS:
3442         remainder = False
3443         length = 4 * line.depth
3444         for _index, leaf, leaf_length in enumerate_with_length(line):
3445             if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first:
3446                 remainder = True
3447             if remainder:
3448                 length += leaf_length
3449                 if length > line_length:
3450                     break
3451
3452                 if leaf.type in OPENING_BRACKETS:
3453                     # There are brackets we can further split on.
3454                     remainder = False
3455
3456         else:
3457             # checked the entire string and line length wasn't exceeded
3458             if len(line.leaves) == _index + 1:
3459                 return True
3460
3461         # Note: we are not returning False here because a line might have *both*
3462         # a leading opening bracket and a trailing closing bracket.  If the
3463         # opening bracket doesn't match our rule, maybe the closing will.
3464
3465     if (
3466         last.type == token.RPAR
3467         or last.type == token.RBRACE
3468         or (
3469             # don't use indexing for omitting optional parentheses;
3470             # it looks weird
3471             last.type == token.RSQB
3472             and last.parent
3473             and last.parent.type != syms.trailer
3474         )
3475     ):
3476         if penultimate.type in OPENING_BRACKETS:
3477             # Empty brackets don't help.
3478             return False
3479
3480         if is_multiline_string(first):
3481             # Additional wrapping of a multiline string in this situation is
3482             # unnecessary.
3483             return True
3484
3485         length = 4 * line.depth
3486         seen_other_brackets = False
3487         for _index, leaf, leaf_length in enumerate_with_length(line):
3488             length += leaf_length
3489             if leaf is last.opening_bracket:
3490                 if seen_other_brackets or length <= line_length:
3491                     return True
3492
3493             elif leaf.type in OPENING_BRACKETS:
3494                 # There are brackets we can further split on.
3495                 seen_other_brackets = True
3496
3497     return False
3498
3499
3500 def get_cache_file(line_length: int, mode: FileMode) -> Path:
3501     return CACHE_DIR / f"cache.{line_length}.{mode.value}.pickle"
3502
3503
3504 def read_cache(line_length: int, mode: FileMode) -> Cache:
3505     """Read the cache if it exists and is well formed.
3506
3507     If it is not well formed, the call to write_cache later should resolve the issue.
3508     """
3509     cache_file = get_cache_file(line_length, mode)
3510     if not cache_file.exists():
3511         return {}
3512
3513     with cache_file.open("rb") as fobj:
3514         try:
3515             cache: Cache = pickle.load(fobj)
3516         except pickle.UnpicklingError:
3517             return {}
3518
3519     return cache
3520
3521
3522 def get_cache_info(path: Path) -> CacheInfo:
3523     """Return the information used to check if a file is already formatted or not."""
3524     stat = path.stat()
3525     return stat.st_mtime, stat.st_size
3526
3527
3528 def filter_cached(cache: Cache, sources: Iterable[Path]) -> Tuple[Set[Path], Set[Path]]:
3529     """Split an iterable of paths in `sources` into two sets.
3530
3531     The first contains paths of files that modified on disk or are not in the
3532     cache. The other contains paths to non-modified files.
3533     """
3534     todo, done = set(), set()
3535     for src in sources:
3536         src = src.resolve()
3537         if cache.get(src) != get_cache_info(src):
3538             todo.add(src)
3539         else:
3540             done.add(src)
3541     return todo, done
3542
3543
3544 def write_cache(
3545     cache: Cache, sources: Iterable[Path], line_length: int, mode: FileMode
3546 ) -> None:
3547     """Update the cache file."""
3548     cache_file = get_cache_file(line_length, mode)
3549     try:
3550         if not CACHE_DIR.exists():
3551             CACHE_DIR.mkdir(parents=True)
3552         new_cache = {**cache, **{src.resolve(): get_cache_info(src) for src in sources}}
3553         with cache_file.open("wb") as fobj:
3554             pickle.dump(new_cache, fobj, protocol=pickle.HIGHEST_PROTOCOL)
3555     except OSError:
3556         pass
3557
3558
3559 def patch_click() -> None:
3560     """Make Click not crash.
3561
3562     On certain misconfigured environments, Python 3 selects the ASCII encoding as the
3563     default which restricts paths that it can access during the lifetime of the
3564     application.  Click refuses to work in this scenario by raising a RuntimeError.
3565
3566     In case of Black the likelihood that non-ASCII characters are going to be used in
3567     file paths is minimal since it's Python source code.  Moreover, this crash was
3568     spurious on Python 3.7 thanks to PEP 538 and PEP 540.
3569     """
3570     try:
3571         from click import core
3572         from click import _unicodefun  # type: ignore
3573     except ModuleNotFoundError:
3574         return
3575
3576     for module in (core, _unicodefun):
3577         if hasattr(module, "_verify_python3_env"):
3578             module._verify_python3_env = lambda: None
3579
3580
3581 if __name__ == "__main__":
3582     patch_click()
3583     main()