All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
2 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
11 from multiprocessing import Manager, freeze_support
13 from pathlib import Path
39 from appdirs import user_cache_dir
40 from attr import dataclass, Factory
45 from blib2to3.pytree import Node, Leaf, type_repr
46 from blib2to3 import pygram, pytree
47 from blib2to3.pgen2 import driver, token
48 from blib2to3.pgen2.parse import ParseError
51 __version__ = "18.9b0"
52 DEFAULT_LINE_LENGTH = 88
54 r"/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|_build|buck-out|build|dist)/"
56 DEFAULT_INCLUDES = r"\.pyi?$"
57 CACHE_DIR = Path(user_cache_dir("black", version=__version__))
69 LN = Union[Leaf, Node]
70 SplitFunc = Callable[["Line", bool], Iterator["Line"]]
73 CacheInfo = Tuple[Timestamp, FileSize]
74 Cache = Dict[Path, CacheInfo]
75 out = partial(click.secho, bold=True, err=True)
76 err = partial(click.secho, fg="red", err=True)
78 pygram.initialize(CACHE_DIR)
79 syms = pygram.python_symbols
82 class NothingChanged(UserWarning):
83 """Raised when reformatted code is the same as source."""
86 class CannotSplit(Exception):
87 """A readable split that fits the allotted line length is impossible."""
90 class InvalidInput(ValueError):
91 """Raised when input source code fails all parse attempts."""
94 class WriteBack(Enum):
101 def from_configuration(cls, *, check: bool, diff: bool) -> "WriteBack":
102 if check and not diff:
105 return cls.DIFF if diff else cls.YES
114 class FileMode(Flag):
118 NO_STRING_NORMALIZATION = 4
119 NO_NUMERIC_UNDERSCORE_NORMALIZATION = 8
122 def from_configuration(
127 skip_string_normalization: bool,
128 skip_numeric_underscore_normalization: bool,
130 mode = cls.AUTO_DETECT
135 if skip_string_normalization:
136 mode |= cls.NO_STRING_NORMALIZATION
137 if skip_numeric_underscore_normalization:
138 mode |= cls.NO_NUMERIC_UNDERSCORE_NORMALIZATION
142 def read_pyproject_toml(
143 ctx: click.Context, param: click.Parameter, value: Union[str, int, bool, None]
145 """Inject Black configuration from "pyproject.toml" into defaults in `ctx`.
147 Returns the path to a successfully found and read configuration file, None
150 assert not isinstance(value, (int, bool)), "Invalid parameter type passed"
152 root = find_project_root(ctx.params.get("src", ()))
153 path = root / "pyproject.toml"
160 pyproject_toml = toml.load(value)
161 config = pyproject_toml.get("tool", {}).get("black", {})
162 except (toml.TomlDecodeError, OSError) as e:
163 raise click.FileError(
164 filename=value, hint=f"Error reading configuration file: {e}"
170 if ctx.default_map is None:
172 ctx.default_map.update( # type: ignore # bad types in .pyi
173 {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
178 @click.command(context_settings=dict(help_option_names=["-h", "--help"]))
183 default=DEFAULT_LINE_LENGTH,
184 help="How many characters per line to allow.",
191 "Allow using Python 3.6-only syntax on all input files. This will put "
192 "trailing commas in function signatures and calls also after *args and "
193 "**kwargs. [default: per-file auto-detection]"
200 "Format all input files like typing stubs regardless of file extension "
201 "(useful when piping source on standard input)."
206 "--skip-string-normalization",
208 help="Don't normalize string quotes or prefixes.",
212 "--skip-numeric-underscore-normalization",
214 help="Don't normalize underscores in numeric literals.",
220 "Don't write the files back, just return the status. Return code 0 "
221 "means nothing would change. Return code 1 means some files would be "
222 "reformatted. Return code 123 means there was an internal error."
228 help="Don't write the files back, just output a diff for each file on stdout.",
233 help="If --fast given, skip temporary sanity checks. [default: --safe]",
238 default=DEFAULT_INCLUDES,
240 "A regular expression that matches files and directories that should be "
241 "included on recursive searches. An empty value means all files are "
242 "included regardless of the name. Use forward slashes for directories on "
243 "all platforms (Windows, too). Exclusions are calculated first, inclusions "
251 default=DEFAULT_EXCLUDES,
253 "A regular expression that matches files and directories that should be "
254 "excluded on recursive searches. An empty value means no paths are excluded. "
255 "Use forward slashes for directories on all platforms (Windows, too). "
256 "Exclusions are calculated first, inclusions later."
265 "Don't emit non-error messages to stderr. Errors are still emitted, "
266 "silence those with 2>/dev/null."
274 "Also emit messages to stderr about files that were not changed or were "
275 "ignored due to --exclude=."
278 @click.version_option(version=__version__)
283 exists=True, file_okay=True, dir_okay=True, readable=True, allow_dash=True
290 exists=False, file_okay=True, dir_okay=False, readable=True, allow_dash=False
293 callback=read_pyproject_toml,
294 help="Read configuration from PATH.",
305 skip_string_normalization: bool,
306 skip_numeric_underscore_normalization: bool,
312 config: Optional[str],
314 """The uncompromising code formatter."""
315 write_back = WriteBack.from_configuration(check=check, diff=diff)
316 mode = FileMode.from_configuration(
319 skip_string_normalization=skip_string_normalization,
320 skip_numeric_underscore_normalization=skip_numeric_underscore_normalization,
322 if config and verbose:
323 out(f"Using configuration from {config}.", bold=False, fg="blue")
325 include_regex = re_compile_maybe_verbose(include)
327 err(f"Invalid regular expression for include given: {include!r}")
330 exclude_regex = re_compile_maybe_verbose(exclude)
332 err(f"Invalid regular expression for exclude given: {exclude!r}")
334 report = Report(check=check, quiet=quiet, verbose=verbose)
335 root = find_project_root(src)
336 sources: Set[Path] = set()
341 gen_python_files_in_dir(p, root, include_regex, exclude_regex, report)
343 elif p.is_file() or s == "-":
344 # if a file was explicitly given, we don't care about its extension
347 err(f"invalid path: {s}")
348 if len(sources) == 0:
349 if verbose or not quiet:
350 out("No paths given. Nothing to do 😴")
353 if len(sources) == 1:
356 line_length=line_length,
358 write_back=write_back,
363 loop = asyncio.get_event_loop()
364 executor = ProcessPoolExecutor(max_workers=os.cpu_count())
366 loop.run_until_complete(
369 line_length=line_length,
371 write_back=write_back,
380 if verbose or not quiet:
381 bang = "💥 💔 💥" if report.return_code else "✨ 🍰 ✨"
382 out(f"All done! {bang}")
383 click.secho(str(report), err=True)
384 ctx.exit(report.return_code)
391 write_back: WriteBack,
395 """Reformat a single file under `src` without spawning child processes.
397 If `quiet` is True, non-error messages are not output. `line_length`,
398 `write_back`, `fast` and `pyi` options are passed to
399 :func:`format_file_in_place` or :func:`format_stdin_to_stdout`.
403 if not src.is_file() and str(src) == "-":
404 if format_stdin_to_stdout(
405 line_length=line_length, fast=fast, write_back=write_back, mode=mode
407 changed = Changed.YES
410 if write_back != WriteBack.DIFF:
411 cache = read_cache(line_length, mode)
412 res_src = src.resolve()
413 if res_src in cache and cache[res_src] == get_cache_info(res_src):
414 changed = Changed.CACHED
415 if changed is not Changed.CACHED and format_file_in_place(
417 line_length=line_length,
419 write_back=write_back,
422 changed = Changed.YES
423 if (write_back is WriteBack.YES and changed is not Changed.CACHED) or (
424 write_back is WriteBack.CHECK and changed is Changed.NO
426 write_cache(cache, [src], line_length, mode)
427 report.done(src, changed)
428 except Exception as exc:
429 report.failed(src, str(exc))
432 async def schedule_formatting(
436 write_back: WriteBack,
442 """Run formatting of `sources` in parallel using the provided `executor`.
444 (Use ProcessPoolExecutors for actual parallelism.)
446 `line_length`, `write_back`, `fast`, and `pyi` options are passed to
447 :func:`format_file_in_place`.
450 if write_back != WriteBack.DIFF:
451 cache = read_cache(line_length, mode)
452 sources, cached = filter_cached(cache, sources)
453 for src in sorted(cached):
454 report.done(src, Changed.CACHED)
459 sources_to_cache = []
461 if write_back == WriteBack.DIFF:
462 # For diff output, we need locks to ensure we don't interleave output
463 # from different processes.
465 lock = manager.Lock()
467 loop.run_in_executor(
469 format_file_in_place,
477 for src in sorted(sources)
479 pending: Iterable[asyncio.Task] = tasks.keys()
481 loop.add_signal_handler(signal.SIGINT, cancel, pending)
482 loop.add_signal_handler(signal.SIGTERM, cancel, pending)
483 except NotImplementedError:
484 # There are no good alternatives for these on Windows.
487 done, _ = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
489 src = tasks.pop(task)
491 cancelled.append(task)
492 elif task.exception():
493 report.failed(src, str(task.exception()))
495 changed = Changed.YES if task.result() else Changed.NO
496 # If the file was written back or was successfully checked as
497 # well-formatted, store this information in the cache.
498 if write_back is WriteBack.YES or (
499 write_back is WriteBack.CHECK and changed is Changed.NO
501 sources_to_cache.append(src)
502 report.done(src, changed)
504 await asyncio.gather(*cancelled, loop=loop, return_exceptions=True)
506 write_cache(cache, sources_to_cache, line_length, mode)
509 def format_file_in_place(
513 write_back: WriteBack = WriteBack.NO,
514 mode: FileMode = FileMode.AUTO_DETECT,
515 lock: Any = None, # multiprocessing.Manager().Lock() is some crazy proxy
517 """Format file under `src` path. Return True if changed.
519 If `write_back` is DIFF, write a diff to stdout. If it is YES, write reformatted
521 `line_length` and `fast` options are passed to :func:`format_file_contents`.
523 if src.suffix == ".pyi":
526 then = datetime.utcfromtimestamp(src.stat().st_mtime)
527 with open(src, "rb") as buf:
528 src_contents, encoding, newline = decode_bytes(buf.read())
530 dst_contents = format_file_contents(
531 src_contents, line_length=line_length, fast=fast, mode=mode
533 except NothingChanged:
536 if write_back == write_back.YES:
537 with open(src, "w", encoding=encoding, newline=newline) as f:
538 f.write(dst_contents)
539 elif write_back == write_back.DIFF:
540 now = datetime.utcnow()
541 src_name = f"{src}\t{then} +0000"
542 dst_name = f"{src}\t{now} +0000"
543 diff_contents = diff(src_contents, dst_contents, src_name, dst_name)
547 f = io.TextIOWrapper(
553 f.write(diff_contents)
561 def format_stdin_to_stdout(
564 write_back: WriteBack = WriteBack.NO,
565 mode: FileMode = FileMode.AUTO_DETECT,
567 """Format file on stdin. Return True if changed.
569 If `write_back` is YES, write reformatted code back to stdout. If it is DIFF,
570 write a diff to stdout.
571 `line_length`, `fast`, `is_pyi`, and `force_py36` arguments are passed to
572 :func:`format_file_contents`.
574 then = datetime.utcnow()
575 src, encoding, newline = decode_bytes(sys.stdin.buffer.read())
578 dst = format_file_contents(src, line_length=line_length, fast=fast, mode=mode)
581 except NothingChanged:
585 f = io.TextIOWrapper(
586 sys.stdout.buffer, encoding=encoding, newline=newline, write_through=True
588 if write_back == WriteBack.YES:
590 elif write_back == WriteBack.DIFF:
591 now = datetime.utcnow()
592 src_name = f"STDIN\t{then} +0000"
593 dst_name = f"STDOUT\t{now} +0000"
594 f.write(diff(src, dst, src_name, dst_name))
598 def format_file_contents(
603 mode: FileMode = FileMode.AUTO_DETECT,
605 """Reformat contents a file and return new contents.
607 If `fast` is False, additionally confirm that the reformatted code is
608 valid by calling :func:`assert_equivalent` and :func:`assert_stable` on it.
609 `line_length` is passed to :func:`format_str`.
611 if src_contents.strip() == "":
614 dst_contents = format_str(src_contents, line_length=line_length, mode=mode)
615 if src_contents == dst_contents:
619 assert_equivalent(src_contents, dst_contents)
620 assert_stable(src_contents, dst_contents, line_length=line_length, mode=mode)
625 src_contents: str, line_length: int, *, mode: FileMode = FileMode.AUTO_DETECT
627 """Reformat a string and return new contents.
629 `line_length` determines how many characters per line are allowed.
631 src_node = lib2to3_parse(src_contents.lstrip())
633 future_imports = get_future_imports(src_node)
634 is_pyi = bool(mode & FileMode.PYI)
635 py36 = bool(mode & FileMode.PYTHON36) or is_python36(src_node)
636 normalize_strings = not bool(mode & FileMode.NO_STRING_NORMALIZATION)
637 normalize_fmt_off(src_node)
638 lines = LineGenerator(
639 remove_u_prefix=py36 or "unicode_literals" in future_imports,
641 normalize_strings=normalize_strings,
642 allow_underscores=py36
643 and not bool(mode & FileMode.NO_NUMERIC_UNDERSCORE_NORMALIZATION),
645 elt = EmptyLineTracker(is_pyi=is_pyi)
648 for current_line in lines.visit(src_node):
649 for _ in range(after):
650 dst_contents += str(empty_line)
651 before, after = elt.maybe_empty_lines(current_line)
652 for _ in range(before):
653 dst_contents += str(empty_line)
654 for line in split_line(current_line, line_length=line_length, py36=py36):
655 dst_contents += str(line)
659 def decode_bytes(src: bytes) -> Tuple[FileContent, Encoding, NewLine]:
660 """Return a tuple of (decoded_contents, encoding, newline).
662 `newline` is either CRLF or LF but `decoded_contents` is decoded with
663 universal newlines (i.e. only contains LF).
665 srcbuf = io.BytesIO(src)
666 encoding, lines = tokenize.detect_encoding(srcbuf.readline)
668 return "", encoding, "\n"
670 newline = "\r\n" if b"\r\n" == lines[0][-2:] else "\n"
672 with io.TextIOWrapper(srcbuf, encoding) as tiow:
673 return tiow.read(), encoding, newline
677 pygram.python_grammar_no_print_statement_no_exec_statement,
678 pygram.python_grammar_no_print_statement,
679 pygram.python_grammar,
683 def lib2to3_parse(src_txt: str) -> Node:
684 """Given a string with source, return the lib2to3 Node."""
685 if src_txt[-1:] != "\n":
687 for grammar in GRAMMARS:
688 drv = driver.Driver(grammar, pytree.convert)
690 result = drv.parse_string(src_txt, True)
693 except ParseError as pe:
694 lineno, column = pe.context[1]
695 lines = src_txt.splitlines()
697 faulty_line = lines[lineno - 1]
699 faulty_line = "<line number missing in source>"
700 exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {faulty_line}")
704 if isinstance(result, Leaf):
705 result = Node(syms.file_input, [result])
709 def lib2to3_unparse(node: Node) -> str:
710 """Given a lib2to3 node, return its string representation."""
718 class Visitor(Generic[T]):
719 """Basic lib2to3 visitor that yields things of type `T` on `visit()`."""
721 def visit(self, node: LN) -> Iterator[T]:
722 """Main method to visit `node` and its children.
724 It tries to find a `visit_*()` method for the given `node.type`, like
725 `visit_simple_stmt` for Node objects or `visit_INDENT` for Leaf objects.
726 If no dedicated `visit_*()` method is found, chooses `visit_default()`
729 Then yields objects of type `T` from the selected visitor.
732 name = token.tok_name[node.type]
734 name = type_repr(node.type)
735 yield from getattr(self, f"visit_{name}", self.visit_default)(node)
737 def visit_default(self, node: LN) -> Iterator[T]:
738 """Default `visit_*()` implementation. Recurses to children of `node`."""
739 if isinstance(node, Node):
740 for child in node.children:
741 yield from self.visit(child)
745 class DebugVisitor(Visitor[T]):
748 def visit_default(self, node: LN) -> Iterator[T]:
749 indent = " " * (2 * self.tree_depth)
750 if isinstance(node, Node):
751 _type = type_repr(node.type)
752 out(f"{indent}{_type}", fg="yellow")
754 for child in node.children:
755 yield from self.visit(child)
758 out(f"{indent}/{_type}", fg="yellow", bold=False)
760 _type = token.tok_name.get(node.type, str(node.type))
761 out(f"{indent}{_type}", fg="blue", nl=False)
763 # We don't have to handle prefixes for `Node` objects since
764 # that delegates to the first child anyway.
765 out(f" {node.prefix!r}", fg="green", bold=False, nl=False)
766 out(f" {node.value!r}", fg="blue", bold=False)
769 def show(cls, code: Union[str, Leaf, Node]) -> None:
770 """Pretty-print the lib2to3 AST of a given string of `code`.
772 Convenience method for debugging.
774 v: DebugVisitor[None] = DebugVisitor()
775 if isinstance(code, str):
776 code = lib2to3_parse(code)
780 KEYWORDS = set(keyword.kwlist)
781 WHITESPACE = {token.DEDENT, token.INDENT, token.NEWLINE}
782 FLOW_CONTROL = {"return", "raise", "break", "continue"}
793 STANDALONE_COMMENT = 153
794 token.tok_name[STANDALONE_COMMENT] = "STANDALONE_COMMENT"
795 LOGIC_OPERATORS = {"and", "or"}
820 STARS = {token.STAR, token.DOUBLESTAR}
823 syms.argument, # double star in arglist
824 syms.trailer, # single argument to call
826 syms.varargslist, # lambdas
828 UNPACKING_PARENTS = {
829 syms.atom, # single element of a list or set literal
833 syms.testlist_star_expr,
868 COMPREHENSION_PRIORITY = 20
870 TERNARY_PRIORITY = 16
873 COMPARATOR_PRIORITY = 10
884 token.DOUBLESLASH: 4,
894 class BracketTracker:
895 """Keeps track of brackets on a line."""
898 bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = Factory(dict)
899 delimiters: Dict[LeafID, Priority] = Factory(dict)
900 previous: Optional[Leaf] = None
901 _for_loop_depths: List[int] = Factory(list)
902 _lambda_argument_depths: List[int] = Factory(list)
904 def mark(self, leaf: Leaf) -> None:
905 """Mark `leaf` with bracket-related metadata. Keep track of delimiters.
907 All leaves receive an int `bracket_depth` field that stores how deep
908 within brackets a given leaf is. 0 means there are no enclosing brackets
909 that started on this line.
911 If a leaf is itself a closing bracket, it receives an `opening_bracket`
912 field that it forms a pair with. This is a one-directional link to
913 avoid reference cycles.
915 If a leaf is a delimiter (a token on which Black can split the line if
916 needed) and it's on depth 0, its `id()` is stored in the tracker's
919 if leaf.type == token.COMMENT:
922 self.maybe_decrement_after_for_loop_variable(leaf)
923 self.maybe_decrement_after_lambda_arguments(leaf)
924 if leaf.type in CLOSING_BRACKETS:
926 opening_bracket = self.bracket_match.pop((self.depth, leaf.type))
927 leaf.opening_bracket = opening_bracket
928 leaf.bracket_depth = self.depth
930 delim = is_split_before_delimiter(leaf, self.previous)
931 if delim and self.previous is not None:
932 self.delimiters[id(self.previous)] = delim
934 delim = is_split_after_delimiter(leaf, self.previous)
936 self.delimiters[id(leaf)] = delim
937 if leaf.type in OPENING_BRACKETS:
938 self.bracket_match[self.depth, BRACKET[leaf.type]] = leaf
941 self.maybe_increment_lambda_arguments(leaf)
942 self.maybe_increment_for_loop_variable(leaf)
944 def any_open_brackets(self) -> bool:
945 """Return True if there is an yet unmatched open bracket on the line."""
946 return bool(self.bracket_match)
948 def max_delimiter_priority(self, exclude: Iterable[LeafID] = ()) -> int:
949 """Return the highest priority of a delimiter found on the line.
951 Values are consistent with what `is_split_*_delimiter()` return.
952 Raises ValueError on no delimiters.
954 return max(v for k, v in self.delimiters.items() if k not in exclude)
956 def delimiter_count_with_priority(self, priority: int = 0) -> int:
957 """Return the number of delimiters with the given `priority`.
959 If no `priority` is passed, defaults to max priority on the line.
961 if not self.delimiters:
964 priority = priority or self.max_delimiter_priority()
965 return sum(1 for p in self.delimiters.values() if p == priority)
967 def maybe_increment_for_loop_variable(self, leaf: Leaf) -> bool:
968 """In a for loop, or comprehension, the variables are often unpacks.
970 To avoid splitting on the comma in this situation, increase the depth of
971 tokens between `for` and `in`.
973 if leaf.type == token.NAME and leaf.value == "for":
975 self._for_loop_depths.append(self.depth)
980 def maybe_decrement_after_for_loop_variable(self, leaf: Leaf) -> bool:
981 """See `maybe_increment_for_loop_variable` above for explanation."""
983 self._for_loop_depths
984 and self._for_loop_depths[-1] == self.depth
985 and leaf.type == token.NAME
986 and leaf.value == "in"
989 self._for_loop_depths.pop()
994 def maybe_increment_lambda_arguments(self, leaf: Leaf) -> bool:
995 """In a lambda expression, there might be more than one argument.
997 To avoid splitting on the comma in this situation, increase the depth of
998 tokens between `lambda` and `:`.
1000 if leaf.type == token.NAME and leaf.value == "lambda":
1002 self._lambda_argument_depths.append(self.depth)
1007 def maybe_decrement_after_lambda_arguments(self, leaf: Leaf) -> bool:
1008 """See `maybe_increment_lambda_arguments` above for explanation."""
1010 self._lambda_argument_depths
1011 and self._lambda_argument_depths[-1] == self.depth
1012 and leaf.type == token.COLON
1015 self._lambda_argument_depths.pop()
1020 def get_open_lsqb(self) -> Optional[Leaf]:
1021 """Return the most recent opening square bracket (if any)."""
1022 return self.bracket_match.get((self.depth - 1, token.RSQB))
1027 """Holds leaves and comments. Can be printed with `str(line)`."""
1030 leaves: List[Leaf] = Factory(list)
1031 # The LeafID keys of comments must remain ordered by the corresponding leaf's index
1033 comments: Dict[LeafID, List[Leaf]] = Factory(dict)
1034 bracket_tracker: BracketTracker = Factory(BracketTracker)
1035 inside_brackets: bool = False
1036 should_explode: bool = False
1038 def append(self, leaf: Leaf, preformatted: bool = False) -> None:
1039 """Add a new `leaf` to the end of the line.
1041 Unless `preformatted` is True, the `leaf` will receive a new consistent
1042 whitespace prefix and metadata applied by :class:`BracketTracker`.
1043 Trailing commas are maybe removed, unpacked for loop variables are
1044 demoted from being delimiters.
1046 Inline comments are put aside.
1048 has_value = leaf.type in BRACKETS or bool(leaf.value.strip())
1052 if token.COLON == leaf.type and self.is_class_paren_empty:
1053 del self.leaves[-2:]
1054 if self.leaves and not preformatted:
1055 # Note: at this point leaf.prefix should be empty except for
1056 # imports, for which we only preserve newlines.
1057 leaf.prefix += whitespace(
1058 leaf, complex_subscript=self.is_complex_subscript(leaf)
1060 if self.inside_brackets or not preformatted:
1061 self.bracket_tracker.mark(leaf)
1062 self.maybe_remove_trailing_comma(leaf)
1063 if not self.append_comment(leaf):
1064 self.leaves.append(leaf)
1066 def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
1067 """Like :func:`append()` but disallow invalid standalone comment structure.
1069 Raises ValueError when any `leaf` is appended after a standalone comment
1070 or when a standalone comment is not the first leaf on the line.
1072 if self.bracket_tracker.depth == 0:
1074 raise ValueError("cannot append to standalone comments")
1076 if self.leaves and leaf.type == STANDALONE_COMMENT:
1078 "cannot append standalone comments to a populated line"
1081 self.append(leaf, preformatted=preformatted)
1084 def is_comment(self) -> bool:
1085 """Is this line a standalone comment?"""
1086 return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
1089 def is_decorator(self) -> bool:
1090 """Is this line a decorator?"""
1091 return bool(self) and self.leaves[0].type == token.AT
1094 def is_import(self) -> bool:
1095 """Is this an import line?"""
1096 return bool(self) and is_import(self.leaves[0])
1099 def is_class(self) -> bool:
1100 """Is this line a class definition?"""
1103 and self.leaves[0].type == token.NAME
1104 and self.leaves[0].value == "class"
1108 def is_stub_class(self) -> bool:
1109 """Is this line a class definition with a body consisting only of "..."?"""
1110 return self.is_class and self.leaves[-3:] == [
1111 Leaf(token.DOT, ".") for _ in range(3)
1115 def is_def(self) -> bool:
1116 """Is this a function definition? (Also returns True for async defs.)"""
1118 first_leaf = self.leaves[0]
1123 second_leaf: Optional[Leaf] = self.leaves[1]
1126 return (first_leaf.type == token.NAME and first_leaf.value == "def") or (
1127 first_leaf.type == token.ASYNC
1128 and second_leaf is not None
1129 and second_leaf.type == token.NAME
1130 and second_leaf.value == "def"
1134 def is_class_paren_empty(self) -> bool:
1135 """Is this a class with no base classes but using parentheses?
1137 Those are unnecessary and should be removed.
1141 and len(self.leaves) == 4
1143 and self.leaves[2].type == token.LPAR
1144 and self.leaves[2].value == "("
1145 and self.leaves[3].type == token.RPAR
1146 and self.leaves[3].value == ")"
1150 def is_triple_quoted_string(self) -> bool:
1151 """Is the line a triple quoted string?"""
1154 and self.leaves[0].type == token.STRING
1155 and self.leaves[0].value.startswith(('"""', "'''"))
1158 def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
1159 """If so, needs to be split before emitting."""
1160 for leaf in self.leaves:
1161 if leaf.type == STANDALONE_COMMENT:
1162 if leaf.bracket_depth <= depth_limit:
1167 def contains_multiline_strings(self) -> bool:
1168 for leaf in self.leaves:
1169 if is_multiline_string(leaf):
1174 def maybe_remove_trailing_comma(self, closing: Leaf) -> bool:
1175 """Remove trailing comma if there is one and it's safe."""
1178 and self.leaves[-1].type == token.COMMA
1179 and closing.type in CLOSING_BRACKETS
1183 if closing.type == token.RBRACE:
1184 self.remove_trailing_comma()
1187 if closing.type == token.RSQB:
1188 comma = self.leaves[-1]
1189 if comma.parent and comma.parent.type == syms.listmaker:
1190 self.remove_trailing_comma()
1193 # For parens let's check if it's safe to remove the comma.
1194 # Imports are always safe.
1196 self.remove_trailing_comma()
1199 # Otherwise, if the trailing one is the only one, we might mistakenly
1200 # change a tuple into a different type by removing the comma.
1201 depth = closing.bracket_depth + 1
1203 opening = closing.opening_bracket
1204 for _opening_index, leaf in enumerate(self.leaves):
1211 for leaf in self.leaves[_opening_index + 1 :]:
1215 bracket_depth = leaf.bracket_depth
1216 if bracket_depth == depth and leaf.type == token.COMMA:
1218 if leaf.parent and leaf.parent.type == syms.arglist:
1223 self.remove_trailing_comma()
1228 def append_comment(self, comment: Leaf) -> bool:
1229 """Add an inline or standalone comment to the line."""
1231 comment.type == STANDALONE_COMMENT
1232 and self.bracket_tracker.any_open_brackets()
1237 if comment.type != token.COMMENT:
1241 comment.type = STANDALONE_COMMENT
1246 leaf_id = id(self.leaves[-1])
1247 if leaf_id not in self.comments:
1248 self.comments[leaf_id] = [comment]
1250 self.comments[leaf_id].append(comment)
1253 def comments_after(self, leaf: Leaf) -> List[Leaf]:
1254 """Generate comments that should appear directly after `leaf`."""
1255 return self.comments.get(id(leaf), [])
1257 def remove_trailing_comma(self) -> None:
1258 """Remove the trailing comma and moves the comments attached to it."""
1259 # Remember, the LeafID keys of self.comments are ordered by the
1260 # corresponding leaf's index in self.leaves
1261 # If id(self.leaves[-2]) is in self.comments, the order doesn't change.
1262 # Otherwise, we insert it into self.comments, and it becomes the last entry.
1263 # However, since we delete id(self.leaves[-1]) from self.comments, the invariant
1265 self.comments.setdefault(id(self.leaves[-2]), []).extend(
1266 self.comments.get(id(self.leaves[-1]), [])
1268 self.comments.pop(id(self.leaves[-1]), None)
1271 def is_complex_subscript(self, leaf: Leaf) -> bool:
1272 """Return True iff `leaf` is part of a slice with non-trivial exprs."""
1273 open_lsqb = self.bracket_tracker.get_open_lsqb()
1274 if open_lsqb is None:
1277 subscript_start = open_lsqb.next_sibling
1279 if isinstance(subscript_start, Node):
1280 if subscript_start.type == syms.listmaker:
1283 if subscript_start.type == syms.subscriptlist:
1284 subscript_start = child_towards(subscript_start, leaf)
1285 return subscript_start is not None and any(
1286 n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
1289 def __str__(self) -> str:
1290 """Render the line."""
1294 indent = " " * self.depth
1295 leaves = iter(self.leaves)
1296 first = next(leaves)
1297 res = f"{first.prefix}{indent}{first.value}"
1300 for comment in itertools.chain.from_iterable(self.comments.values()):
1304 def __bool__(self) -> bool:
1305 """Return True if the line has leaves or comments."""
1306 return bool(self.leaves or self.comments)
1310 class EmptyLineTracker:
1311 """Provides a stateful method that returns the number of potential extra
1312 empty lines needed before and after the currently processed line.
1314 Note: this tracker works on lines that haven't been split yet. It assumes
1315 the prefix of the first leaf consists of optional newlines. Those newlines
1316 are consumed by `maybe_empty_lines()` and included in the computation.
1319 is_pyi: bool = False
1320 previous_line: Optional[Line] = None
1321 previous_after: int = 0
1322 previous_defs: List[int] = Factory(list)
1324 def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
1325 """Return the number of extra empty lines before and after the `current_line`.
1327 This is for separating `def`, `async def` and `class` with extra empty
1328 lines (two on module-level).
1330 before, after = self._maybe_empty_lines(current_line)
1331 before -= self.previous_after
1332 self.previous_after = after
1333 self.previous_line = current_line
1334 return before, after
1336 def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
1338 if current_line.depth == 0:
1339 max_allowed = 1 if self.is_pyi else 2
1340 if current_line.leaves:
1341 # Consume the first leaf's extra newlines.
1342 first_leaf = current_line.leaves[0]
1343 before = first_leaf.prefix.count("\n")
1344 before = min(before, max_allowed)
1345 first_leaf.prefix = ""
1348 depth = current_line.depth
1349 while self.previous_defs and self.previous_defs[-1] >= depth:
1350 self.previous_defs.pop()
1352 before = 0 if depth else 1
1354 before = 1 if depth else 2
1355 if current_line.is_decorator or current_line.is_def or current_line.is_class:
1356 return self._maybe_empty_lines_for_class_or_def(current_line, before)
1360 and self.previous_line.is_import
1361 and not current_line.is_import
1362 and depth == self.previous_line.depth
1364 return (before or 1), 0
1368 and self.previous_line.is_class
1369 and current_line.is_triple_quoted_string
1375 def _maybe_empty_lines_for_class_or_def(
1376 self, current_line: Line, before: int
1377 ) -> Tuple[int, int]:
1378 if not current_line.is_decorator:
1379 self.previous_defs.append(current_line.depth)
1380 if self.previous_line is None:
1381 # Don't insert empty lines before the first line in the file.
1384 if self.previous_line.is_decorator:
1387 if self.previous_line.depth < current_line.depth and (
1388 self.previous_line.is_class or self.previous_line.is_def
1393 self.previous_line.is_comment
1394 and self.previous_line.depth == current_line.depth
1400 if self.previous_line.depth > current_line.depth:
1402 elif current_line.is_class or self.previous_line.is_class:
1403 if current_line.is_stub_class and self.previous_line.is_stub_class:
1404 # No blank line between classes with an empty body
1408 elif current_line.is_def and not self.previous_line.is_def:
1409 # Blank line between a block of functions and a block of non-functions
1415 if current_line.depth and newlines:
1421 class LineGenerator(Visitor[Line]):
1422 """Generates reformatted Line objects. Empty lines are not emitted.
1424 Note: destroys the tree it's visiting by mutating prefixes of its leaves
1425 in ways that will no longer stringify to valid Python code on the tree.
1428 is_pyi: bool = False
1429 normalize_strings: bool = True
1430 current_line: Line = Factory(Line)
1431 remove_u_prefix: bool = False
1432 allow_underscores: bool = False
1434 def line(self, indent: int = 0) -> Iterator[Line]:
1437 If the line is empty, only emit if it makes sense.
1438 If the line is too long, split it first and then generate.
1440 If any lines were generated, set up a new current_line.
1442 if not self.current_line:
1443 self.current_line.depth += indent
1444 return # Line is empty, don't emit. Creating a new one unnecessary.
1446 complete_line = self.current_line
1447 self.current_line = Line(depth=complete_line.depth + indent)
1450 def visit_default(self, node: LN) -> Iterator[Line]:
1451 """Default `visit_*()` implementation. Recurses to children of `node`."""
1452 if isinstance(node, Leaf):
1453 any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
1454 for comment in generate_comments(node):
1455 if any_open_brackets:
1456 # any comment within brackets is subject to splitting
1457 self.current_line.append(comment)
1458 elif comment.type == token.COMMENT:
1459 # regular trailing comment
1460 self.current_line.append(comment)
1461 yield from self.line()
1464 # regular standalone comment
1465 yield from self.line()
1467 self.current_line.append(comment)
1468 yield from self.line()
1470 normalize_prefix(node, inside_brackets=any_open_brackets)
1471 if self.normalize_strings and node.type == token.STRING:
1472 normalize_string_prefix(node, remove_u_prefix=self.remove_u_prefix)
1473 normalize_string_quotes(node)
1474 if node.type == token.NUMBER:
1475 normalize_numeric_literal(node, self.allow_underscores)
1476 if node.type not in WHITESPACE:
1477 self.current_line.append(node)
1478 yield from super().visit_default(node)
1480 def visit_INDENT(self, node: Node) -> Iterator[Line]:
1481 """Increase indentation level, maybe yield a line."""
1482 # In blib2to3 INDENT never holds comments.
1483 yield from self.line(+1)
1484 yield from self.visit_default(node)
1486 def visit_DEDENT(self, node: Node) -> Iterator[Line]:
1487 """Decrease indentation level, maybe yield a line."""
1488 # The current line might still wait for trailing comments. At DEDENT time
1489 # there won't be any (they would be prefixes on the preceding NEWLINE).
1490 # Emit the line then.
1491 yield from self.line()
1493 # While DEDENT has no value, its prefix may contain standalone comments
1494 # that belong to the current indentation level. Get 'em.
1495 yield from self.visit_default(node)
1497 # Finally, emit the dedent.
1498 yield from self.line(-1)
1501 self, node: Node, keywords: Set[str], parens: Set[str]
1502 ) -> Iterator[Line]:
1503 """Visit a statement.
1505 This implementation is shared for `if`, `while`, `for`, `try`, `except`,
1506 `def`, `with`, `class`, `assert` and assignments.
1508 The relevant Python language `keywords` for a given statement will be
1509 NAME leaves within it. This methods puts those on a separate line.
1511 `parens` holds a set of string leaf values immediately after which
1512 invisible parens should be put.
1514 normalize_invisible_parens(node, parens_after=parens)
1515 for child in node.children:
1516 if child.type == token.NAME and child.value in keywords: # type: ignore
1517 yield from self.line()
1519 yield from self.visit(child)
1521 def visit_suite(self, node: Node) -> Iterator[Line]:
1522 """Visit a suite."""
1523 if self.is_pyi and is_stub_suite(node):
1524 yield from self.visit(node.children[2])
1526 yield from self.visit_default(node)
1528 def visit_simple_stmt(self, node: Node) -> Iterator[Line]:
1529 """Visit a statement without nested statements."""
1530 is_suite_like = node.parent and node.parent.type in STATEMENT
1532 if self.is_pyi and is_stub_body(node):
1533 yield from self.visit_default(node)
1535 yield from self.line(+1)
1536 yield from self.visit_default(node)
1537 yield from self.line(-1)
1540 if not self.is_pyi or not node.parent or not is_stub_suite(node.parent):
1541 yield from self.line()
1542 yield from self.visit_default(node)
1544 def visit_async_stmt(self, node: Node) -> Iterator[Line]:
1545 """Visit `async def`, `async for`, `async with`."""
1546 yield from self.line()
1548 children = iter(node.children)
1549 for child in children:
1550 yield from self.visit(child)
1552 if child.type == token.ASYNC:
1555 internal_stmt = next(children)
1556 for child in internal_stmt.children:
1557 yield from self.visit(child)
1559 def visit_decorators(self, node: Node) -> Iterator[Line]:
1560 """Visit decorators."""
1561 for child in node.children:
1562 yield from self.line()
1563 yield from self.visit(child)
1565 def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]:
1566 """Remove a semicolon and put the other statement on a separate line."""
1567 yield from self.line()
1569 def visit_ENDMARKER(self, leaf: Leaf) -> Iterator[Line]:
1570 """End of file. Process outstanding comments and end with a newline."""
1571 yield from self.visit_default(leaf)
1572 yield from self.line()
1574 def visit_STANDALONE_COMMENT(self, leaf: Leaf) -> Iterator[Line]:
1575 if not self.current_line.bracket_tracker.any_open_brackets():
1576 yield from self.line()
1577 yield from self.visit_default(leaf)
1579 def __attrs_post_init__(self) -> None:
1580 """You are in a twisty little maze of passages."""
1583 self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
1584 self.visit_if_stmt = partial(
1585 v, keywords={"if", "else", "elif"}, parens={"if", "elif"}
1587 self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"})
1588 self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"})
1589 self.visit_try_stmt = partial(
1590 v, keywords={"try", "except", "else", "finally"}, parens=Ø
1592 self.visit_except_clause = partial(v, keywords={"except"}, parens=Ø)
1593 self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø)
1594 self.visit_funcdef = partial(v, keywords={"def"}, parens=Ø)
1595 self.visit_classdef = partial(v, keywords={"class"}, parens=Ø)
1596 self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS)
1597 self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"})
1598 self.visit_import_from = partial(v, keywords=Ø, parens={"import"})
1599 self.visit_async_funcdef = self.visit_async_stmt
1600 self.visit_decorated = self.visit_decorators
1603 IMPLICIT_TUPLE = {syms.testlist, syms.testlist_star_expr, syms.exprlist}
1604 BRACKET = {token.LPAR: token.RPAR, token.LSQB: token.RSQB, token.LBRACE: token.RBRACE}
1605 OPENING_BRACKETS = set(BRACKET.keys())
1606 CLOSING_BRACKETS = set(BRACKET.values())
1607 BRACKETS = OPENING_BRACKETS | CLOSING_BRACKETS
1608 ALWAYS_NO_SPACE = CLOSING_BRACKETS | {token.COMMA, STANDALONE_COMMENT}
1611 def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa C901
1612 """Return whitespace prefix if needed for the given `leaf`.
1614 `complex_subscript` signals whether the given leaf is part of a subscription
1615 which has non-trivial arguments, like arithmetic expressions or function calls.
1623 if t in ALWAYS_NO_SPACE:
1626 if t == token.COMMENT:
1629 assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
1630 if t == token.COLON and p.type not in {
1637 prev = leaf.prev_sibling
1639 prevp = preceding_leaf(p)
1640 if not prevp or prevp.type in OPENING_BRACKETS:
1643 if t == token.COLON:
1644 if prevp.type == token.COLON:
1647 elif prevp.type != token.COMMA and not complex_subscript:
1652 if prevp.type == token.EQUAL:
1654 if prevp.parent.type in {
1662 elif prevp.parent.type == syms.typedargslist:
1663 # A bit hacky: if the equal sign has whitespace, it means we
1664 # previously found it's a typed argument. So, we're using
1668 elif prevp.type in STARS:
1669 if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS):
1672 elif prevp.type == token.COLON:
1673 if prevp.parent and prevp.parent.type in {syms.subscript, syms.sliceop}:
1674 return SPACE if complex_subscript else NO
1678 and prevp.parent.type == syms.factor
1679 and prevp.type in MATH_OPERATORS
1684 prevp.type == token.RIGHTSHIFT
1686 and prevp.parent.type == syms.shift_expr
1687 and prevp.prev_sibling
1688 and prevp.prev_sibling.type == token.NAME
1689 and prevp.prev_sibling.value == "print" # type: ignore
1691 # Python 2 print chevron
1694 elif prev.type in OPENING_BRACKETS:
1697 if p.type in {syms.parameters, syms.arglist}:
1698 # untyped function signatures or calls
1699 if not prev or prev.type != token.COMMA:
1702 elif p.type == syms.varargslist:
1704 if prev and prev.type != token.COMMA:
1707 elif p.type == syms.typedargslist:
1708 # typed function signatures
1712 if t == token.EQUAL:
1713 if prev.type != syms.tname:
1716 elif prev.type == token.EQUAL:
1717 # A bit hacky: if the equal sign has whitespace, it means we
1718 # previously found it's a typed argument. So, we're using that, too.
1721 elif prev.type != token.COMMA:
1724 elif p.type == syms.tname:
1727 prevp = preceding_leaf(p)
1728 if not prevp or prevp.type != token.COMMA:
1731 elif p.type == syms.trailer:
1732 # attributes and calls
1733 if t == token.LPAR or t == token.RPAR:
1738 prevp = preceding_leaf(p)
1739 if not prevp or prevp.type != token.NUMBER:
1742 elif t == token.LSQB:
1745 elif prev.type != token.COMMA:
1748 elif p.type == syms.argument:
1750 if t == token.EQUAL:
1754 prevp = preceding_leaf(p)
1755 if not prevp or prevp.type == token.LPAR:
1758 elif prev.type in {token.EQUAL} | STARS:
1761 elif p.type == syms.decorator:
1765 elif p.type == syms.dotted_name:
1769 prevp = preceding_leaf(p)
1770 if not prevp or prevp.type == token.AT or prevp.type == token.DOT:
1773 elif p.type == syms.classdef:
1777 if prev and prev.type == token.LPAR:
1780 elif p.type in {syms.subscript, syms.sliceop}:
1783 assert p.parent is not None, "subscripts are always parented"
1784 if p.parent.type == syms.subscriptlist:
1789 elif not complex_subscript:
1792 elif p.type == syms.atom:
1793 if prev and t == token.DOT:
1794 # dots, but not the first one.
1797 elif p.type == syms.dictsetmaker:
1799 if prev and prev.type == token.DOUBLESTAR:
1802 elif p.type in {syms.factor, syms.star_expr}:
1805 prevp = preceding_leaf(p)
1806 if not prevp or prevp.type in OPENING_BRACKETS:
1809 prevp_parent = prevp.parent
1810 assert prevp_parent is not None
1811 if prevp.type == token.COLON and prevp_parent.type in {
1817 elif prevp.type == token.EQUAL and prevp_parent.type == syms.argument:
1820 elif t in {token.NAME, token.NUMBER, token.STRING}:
1823 elif p.type == syms.import_from:
1825 if prev and prev.type == token.DOT:
1828 elif t == token.NAME:
1832 if prev and prev.type == token.DOT:
1835 elif p.type == syms.sliceop:
1841 def preceding_leaf(node: Optional[LN]) -> Optional[Leaf]:
1842 """Return the first leaf that precedes `node`, if any."""
1844 res = node.prev_sibling
1846 if isinstance(res, Leaf):
1850 return list(res.leaves())[-1]
1859 def child_towards(ancestor: Node, descendant: LN) -> Optional[LN]:
1860 """Return the child of `ancestor` that contains `descendant`."""
1861 node: Optional[LN] = descendant
1862 while node and node.parent != ancestor:
1867 def container_of(leaf: Leaf) -> LN:
1868 """Return `leaf` or one of its ancestors that is the topmost container of it.
1870 By "container" we mean a node where `leaf` is the very first child.
1872 same_prefix = leaf.prefix
1873 container: LN = leaf
1875 parent = container.parent
1879 if parent.children[0].prefix != same_prefix:
1882 if parent.type == syms.file_input:
1885 if parent.prev_sibling is not None and parent.prev_sibling.type in BRACKETS:
1892 def is_split_after_delimiter(leaf: Leaf, previous: Optional[Leaf] = None) -> int:
1893 """Return the priority of the `leaf` delimiter, given a line break after it.
1895 The delimiter priorities returned here are from those delimiters that would
1896 cause a line break after themselves.
1898 Higher numbers are higher priority.
1900 if leaf.type == token.COMMA:
1901 return COMMA_PRIORITY
1906 def is_split_before_delimiter(leaf: Leaf, previous: Optional[Leaf] = None) -> int:
1907 """Return the priority of the `leaf` delimiter, given a line break before it.
1909 The delimiter priorities returned here are from those delimiters that would
1910 cause a line break before themselves.
1912 Higher numbers are higher priority.
1914 if is_vararg(leaf, within=VARARGS_PARENTS | UNPACKING_PARENTS):
1915 # * and ** might also be MATH_OPERATORS but in this case they are not.
1916 # Don't treat them as a delimiter.
1920 leaf.type == token.DOT
1922 and leaf.parent.type not in {syms.import_from, syms.dotted_name}
1923 and (previous is None or previous.type in CLOSING_BRACKETS)
1928 leaf.type in MATH_OPERATORS
1930 and leaf.parent.type not in {syms.factor, syms.star_expr}
1932 return MATH_PRIORITIES[leaf.type]
1934 if leaf.type in COMPARATORS:
1935 return COMPARATOR_PRIORITY
1938 leaf.type == token.STRING
1939 and previous is not None
1940 and previous.type == token.STRING
1942 return STRING_PRIORITY
1944 if leaf.type not in {token.NAME, token.ASYNC}:
1950 and leaf.parent.type in {syms.comp_for, syms.old_comp_for}
1951 or leaf.type == token.ASYNC
1954 not isinstance(leaf.prev_sibling, Leaf)
1955 or leaf.prev_sibling.value != "async"
1957 return COMPREHENSION_PRIORITY
1962 and leaf.parent.type in {syms.comp_if, syms.old_comp_if}
1964 return COMPREHENSION_PRIORITY
1966 if leaf.value in {"if", "else"} and leaf.parent and leaf.parent.type == syms.test:
1967 return TERNARY_PRIORITY
1969 if leaf.value == "is":
1970 return COMPARATOR_PRIORITY
1975 and leaf.parent.type in {syms.comp_op, syms.comparison}
1977 previous is not None
1978 and previous.type == token.NAME
1979 and previous.value == "not"
1982 return COMPARATOR_PRIORITY
1987 and leaf.parent.type == syms.comp_op
1989 previous is not None
1990 and previous.type == token.NAME
1991 and previous.value == "is"
1994 return COMPARATOR_PRIORITY
1996 if leaf.value in LOGIC_OPERATORS and leaf.parent:
1997 return LOGIC_PRIORITY
2002 FMT_OFF = {"# fmt: off", "# fmt:off", "# yapf: disable"}
2003 FMT_ON = {"# fmt: on", "# fmt:on", "# yapf: enable"}
2006 def generate_comments(leaf: LN) -> Iterator[Leaf]:
2007 """Clean the prefix of the `leaf` and generate comments from it, if any.
2009 Comments in lib2to3 are shoved into the whitespace prefix. This happens
2010 in `pgen2/driver.py:Driver.parse_tokens()`. This was a brilliant implementation
2011 move because it does away with modifying the grammar to include all the
2012 possible places in which comments can be placed.
2014 The sad consequence for us though is that comments don't "belong" anywhere.
2015 This is why this function generates simple parentless Leaf objects for
2016 comments. We simply don't know what the correct parent should be.
2018 No matter though, we can live without this. We really only need to
2019 differentiate between inline and standalone comments. The latter don't
2020 share the line with any code.
2022 Inline comments are emitted as regular token.COMMENT leaves. Standalone
2023 are emitted with a fake STANDALONE_COMMENT token identifier.
2025 for pc in list_comments(leaf.prefix, is_endmarker=leaf.type == token.ENDMARKER):
2026 yield Leaf(pc.type, pc.value, prefix="\n" * pc.newlines)
2031 """Describes a piece of syntax that is a comment.
2033 It's not a :class:`blib2to3.pytree.Leaf` so that:
2035 * it can be cached (`Leaf` objects should not be reused more than once as
2036 they store their lineno, column, prefix, and parent information);
2037 * `newlines` and `consumed` fields are kept separate from the `value`. This
2038 simplifies handling of special marker comments like ``# fmt: off/on``.
2041 type: int # token.COMMENT or STANDALONE_COMMENT
2042 value: str # content of the comment
2043 newlines: int # how many newlines before the comment
2044 consumed: int # how many characters of the original leaf's prefix did we consume
2047 @lru_cache(maxsize=4096)
2048 def list_comments(prefix: str, *, is_endmarker: bool) -> List[ProtoComment]:
2049 """Return a list of :class:`ProtoComment` objects parsed from the given `prefix`."""
2050 result: List[ProtoComment] = []
2051 if not prefix or "#" not in prefix:
2056 for index, line in enumerate(prefix.split("\n")):
2057 consumed += len(line) + 1 # adding the length of the split '\n'
2058 line = line.lstrip()
2061 if not line.startswith("#"):
2064 if index == 0 and not is_endmarker:
2065 comment_type = token.COMMENT # simple trailing comment
2067 comment_type = STANDALONE_COMMENT
2068 comment = make_comment(line)
2071 type=comment_type, value=comment, newlines=nlines, consumed=consumed
2078 def make_comment(content: str) -> str:
2079 """Return a consistently formatted comment from the given `content` string.
2081 All comments (except for "##", "#!", "#:", '#'", "#%%") should have a single
2082 space between the hash sign and the content.
2084 If `content` didn't start with a hash sign, one is provided.
2086 content = content.rstrip()
2090 if content[0] == "#":
2091 content = content[1:]
2092 if content and content[0] not in " !:#'%":
2093 content = " " + content
2094 return "#" + content
2098 line: Line, line_length: int, inner: bool = False, py36: bool = False
2099 ) -> Iterator[Line]:
2100 """Split a `line` into potentially many lines.
2102 They should fit in the allotted `line_length` but might not be able to.
2103 `inner` signifies that there were a pair of brackets somewhere around the
2104 current `line`, possibly transitively. This means we can fallback to splitting
2105 by delimiters if the LHS/RHS don't yield any results.
2107 If `py36` is True, splitting may generate syntax that is only compatible
2108 with Python 3.6 and later.
2114 line_str = str(line).strip("\n")
2116 # we don't want to split special comments like type annotations
2117 # https://github.com/python/typing/issues/186
2118 has_special_comment = False
2119 for leaf in line.leaves:
2120 for comment in line.comments_after(leaf):
2121 if leaf.type == token.COMMA and is_special_comment(comment):
2122 has_special_comment = True
2125 not has_special_comment
2126 and not line.should_explode
2127 and is_line_short_enough(line, line_length=line_length, line_str=line_str)
2132 split_funcs: List[SplitFunc]
2134 split_funcs = [left_hand_split]
2137 def rhs(line: Line, py36: bool = False) -> Iterator[Line]:
2138 for omit in generate_trailers_to_omit(line, line_length):
2139 lines = list(right_hand_split(line, line_length, py36, omit=omit))
2140 if is_line_short_enough(lines[0], line_length=line_length):
2144 # All splits failed, best effort split with no omits.
2145 # This mostly happens to multiline strings that are by definition
2146 # reported as not fitting a single line.
2147 yield from right_hand_split(line, py36)
2149 if line.inside_brackets:
2150 split_funcs = [delimiter_split, standalone_comment_split, rhs]
2153 for split_func in split_funcs:
2154 # We are accumulating lines in `result` because we might want to abort
2155 # mission and return the original line in the end, or attempt a different
2157 result: List[Line] = []
2159 for l in split_func(line, py36):
2160 if str(l).strip("\n") == line_str:
2161 raise CannotSplit("Split function returned an unchanged result")
2164 split_line(l, line_length=line_length, inner=True, py36=py36)
2177 def left_hand_split(line: Line, py36: bool = False) -> Iterator[Line]:
2178 """Split line into many lines, starting with the first matching bracket pair.
2180 Note: this usually looks weird, only use this for function definitions.
2181 Prefer RHS otherwise. This is why this function is not symmetrical with
2182 :func:`right_hand_split` which also handles optional parentheses.
2184 tail_leaves: List[Leaf] = []
2185 body_leaves: List[Leaf] = []
2186 head_leaves: List[Leaf] = []
2187 current_leaves = head_leaves
2188 matching_bracket = None
2189 for leaf in line.leaves:
2191 current_leaves is body_leaves
2192 and leaf.type in CLOSING_BRACKETS
2193 and leaf.opening_bracket is matching_bracket
2195 current_leaves = tail_leaves if body_leaves else head_leaves
2196 current_leaves.append(leaf)
2197 if current_leaves is head_leaves:
2198 if leaf.type in OPENING_BRACKETS:
2199 matching_bracket = leaf
2200 current_leaves = body_leaves
2201 if not matching_bracket:
2202 raise CannotSplit("No brackets found")
2204 head = bracket_split_build_line(head_leaves, line, matching_bracket)
2205 body = bracket_split_build_line(body_leaves, line, matching_bracket, is_body=True)
2206 tail = bracket_split_build_line(tail_leaves, line, matching_bracket)
2207 bracket_split_succeeded_or_raise(head, body, tail)
2208 for result in (head, body, tail):
2213 def right_hand_split(
2214 line: Line, line_length: int, py36: bool = False, omit: Collection[LeafID] = ()
2215 ) -> Iterator[Line]:
2216 """Split line into many lines, starting with the last matching bracket pair.
2218 If the split was by optional parentheses, attempt splitting without them, too.
2219 `omit` is a collection of closing bracket IDs that shouldn't be considered for
2222 Note: running this function modifies `bracket_depth` on the leaves of `line`.
2224 tail_leaves: List[Leaf] = []
2225 body_leaves: List[Leaf] = []
2226 head_leaves: List[Leaf] = []
2227 current_leaves = tail_leaves
2228 opening_bracket = None
2229 closing_bracket = None
2230 for leaf in reversed(line.leaves):
2231 if current_leaves is body_leaves:
2232 if leaf is opening_bracket:
2233 current_leaves = head_leaves if body_leaves else tail_leaves
2234 current_leaves.append(leaf)
2235 if current_leaves is tail_leaves:
2236 if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit:
2237 opening_bracket = leaf.opening_bracket
2238 closing_bracket = leaf
2239 current_leaves = body_leaves
2240 if not (opening_bracket and closing_bracket and head_leaves):
2241 # If there is no opening or closing_bracket that means the split failed and
2242 # all content is in the tail. Otherwise, if `head_leaves` are empty, it means
2243 # the matching `opening_bracket` wasn't available on `line` anymore.
2244 raise CannotSplit("No brackets found")
2246 tail_leaves.reverse()
2247 body_leaves.reverse()
2248 head_leaves.reverse()
2249 head = bracket_split_build_line(head_leaves, line, opening_bracket)
2250 body = bracket_split_build_line(body_leaves, line, opening_bracket, is_body=True)
2251 tail = bracket_split_build_line(tail_leaves, line, opening_bracket)
2252 bracket_split_succeeded_or_raise(head, body, tail)
2254 # the body shouldn't be exploded
2255 not body.should_explode
2256 # the opening bracket is an optional paren
2257 and opening_bracket.type == token.LPAR
2258 and not opening_bracket.value
2259 # the closing bracket is an optional paren
2260 and closing_bracket.type == token.RPAR
2261 and not closing_bracket.value
2262 # it's not an import (optional parens are the only thing we can split on
2263 # in this case; attempting a split without them is a waste of time)
2264 and not line.is_import
2265 # there are no standalone comments in the body
2266 and not body.contains_standalone_comments(0)
2267 # and we can actually remove the parens
2268 and can_omit_invisible_parens(body, line_length)
2270 omit = {id(closing_bracket), *omit}
2272 yield from right_hand_split(line, line_length, py36=py36, omit=omit)
2278 or is_line_short_enough(body, line_length=line_length)
2281 "Splitting failed, body is still too long and can't be split."
2284 elif head.contains_multiline_strings() or tail.contains_multiline_strings():
2286 "The current optional pair of parentheses is bound to fail to "
2287 "satisfy the splitting algorithm because the head or the tail "
2288 "contains multiline strings which by definition never fit one "
2292 ensure_visible(opening_bracket)
2293 ensure_visible(closing_bracket)
2294 for result in (head, body, tail):
2299 def bracket_split_succeeded_or_raise(head: Line, body: Line, tail: Line) -> None:
2300 """Raise :exc:`CannotSplit` if the last left- or right-hand split failed.
2302 Do nothing otherwise.
2304 A left- or right-hand split is based on a pair of brackets. Content before
2305 (and including) the opening bracket is left on one line, content inside the
2306 brackets is put on a separate line, and finally content starting with and
2307 following the closing bracket is put on a separate line.
2309 Those are called `head`, `body`, and `tail`, respectively. If the split
2310 produced the same line (all content in `head`) or ended up with an empty `body`
2311 and the `tail` is just the closing bracket, then it's considered failed.
2313 tail_len = len(str(tail).strip())
2316 raise CannotSplit("Splitting brackets produced the same line")
2320 f"Splitting brackets on an empty body to save "
2321 f"{tail_len} characters is not worth it"
2325 def bracket_split_build_line(
2326 leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False
2328 """Return a new line with given `leaves` and respective comments from `original`.
2330 If `is_body` is True, the result line is one-indented inside brackets and as such
2331 has its first leaf's prefix normalized and a trailing comma added when expected.
2333 result = Line(depth=original.depth)
2335 result.inside_brackets = True
2338 # Since body is a new indent level, remove spurious leading whitespace.
2339 normalize_prefix(leaves[0], inside_brackets=True)
2340 # Ensure a trailing comma when expected.
2341 if original.is_import:
2342 if leaves[-1].type != token.COMMA:
2343 leaves.append(Leaf(token.COMMA, ","))
2346 result.append(leaf, preformatted=True)
2347 for comment_after in original.comments_after(leaf):
2348 result.append(comment_after, preformatted=True)
2350 result.should_explode = should_explode(result, opening_bracket)
2354 def dont_increase_indentation(split_func: SplitFunc) -> SplitFunc:
2355 """Normalize prefix of the first leaf in every line returned by `split_func`.
2357 This is a decorator over relevant split functions.
2361 def split_wrapper(line: Line, py36: bool = False) -> Iterator[Line]:
2362 for l in split_func(line, py36):
2363 normalize_prefix(l.leaves[0], inside_brackets=True)
2366 return split_wrapper
2369 @dont_increase_indentation
2370 def delimiter_split(line: Line, py36: bool = False) -> Iterator[Line]:
2371 """Split according to delimiters of the highest priority.
2373 If `py36` is True, the split will add trailing commas also in function
2374 signatures that contain `*` and `**`.
2377 last_leaf = line.leaves[-1]
2379 raise CannotSplit("Line empty")
2381 bt = line.bracket_tracker
2383 delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)})
2385 raise CannotSplit("No delimiters found")
2387 if delimiter_priority == DOT_PRIORITY:
2388 if bt.delimiter_count_with_priority(delimiter_priority) == 1:
2389 raise CannotSplit("Splitting a single attribute from its owner looks wrong")
2391 current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2392 lowest_depth = sys.maxsize
2393 trailing_comma_safe = True
2395 def append_to_line(leaf: Leaf) -> Iterator[Line]:
2396 """Append `leaf` to current line or to new line if appending impossible."""
2397 nonlocal current_line
2399 current_line.append_safe(leaf, preformatted=True)
2403 current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2404 current_line.append(leaf)
2406 for leaf in line.leaves:
2407 yield from append_to_line(leaf)
2409 for comment_after in line.comments_after(leaf):
2410 yield from append_to_line(comment_after)
2412 lowest_depth = min(lowest_depth, leaf.bracket_depth)
2413 if leaf.bracket_depth == lowest_depth and is_vararg(
2414 leaf, within=VARARGS_PARENTS
2416 trailing_comma_safe = trailing_comma_safe and py36
2417 leaf_priority = bt.delimiters.get(id(leaf))
2418 if leaf_priority == delimiter_priority:
2421 current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2425 and delimiter_priority == COMMA_PRIORITY
2426 and current_line.leaves[-1].type != token.COMMA
2427 and current_line.leaves[-1].type != STANDALONE_COMMENT
2429 current_line.append(Leaf(token.COMMA, ","))
2433 @dont_increase_indentation
2434 def standalone_comment_split(line: Line, py36: bool = False) -> Iterator[Line]:
2435 """Split standalone comments from the rest of the line."""
2436 if not line.contains_standalone_comments(0):
2437 raise CannotSplit("Line does not have any standalone comments")
2439 current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2441 def append_to_line(leaf: Leaf) -> Iterator[Line]:
2442 """Append `leaf` to current line or to new line if appending impossible."""
2443 nonlocal current_line
2445 current_line.append_safe(leaf, preformatted=True)
2449 current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
2450 current_line.append(leaf)
2452 for leaf in line.leaves:
2453 yield from append_to_line(leaf)
2455 for comment_after in line.comments_after(leaf):
2456 yield from append_to_line(comment_after)
2462 def is_import(leaf: Leaf) -> bool:
2463 """Return True if the given leaf starts an import statement."""
2470 (v == "import" and p and p.type == syms.import_name)
2471 or (v == "from" and p and p.type == syms.import_from)
2476 def is_special_comment(leaf: Leaf) -> bool:
2477 """Return True if the given leaf is a special comment.
2478 Only returns true for type comments for now."""
2482 (t == token.COMMENT or t == STANDALONE_COMMENT) and (v.startswith("# type:"))
2486 def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
2487 """Leave existing extra newlines if not `inside_brackets`. Remove everything
2490 Note: don't use backslashes for formatting or you'll lose your voting rights.
2492 if not inside_brackets:
2493 spl = leaf.prefix.split("#")
2494 if "\\" not in spl[0]:
2495 nl_count = spl[-1].count("\n")
2498 leaf.prefix = "\n" * nl_count
2504 def normalize_string_prefix(leaf: Leaf, remove_u_prefix: bool = False) -> None:
2505 """Make all string prefixes lowercase.
2507 If remove_u_prefix is given, also removes any u prefix from the string.
2509 Note: Mutates its argument.
2511 match = re.match(r"^([furbFURB]*)(.*)$", leaf.value, re.DOTALL)
2512 assert match is not None, f"failed to match string {leaf.value!r}"
2513 orig_prefix = match.group(1)
2514 new_prefix = orig_prefix.lower()
2516 new_prefix = new_prefix.replace("u", "")
2517 leaf.value = f"{new_prefix}{match.group(2)}"
2520 def normalize_string_quotes(leaf: Leaf) -> None:
2521 """Prefer double quotes but only if it doesn't cause more escaping.
2523 Adds or removes backslashes as appropriate. Doesn't parse and fix
2524 strings nested in f-strings (yet).
2526 Note: Mutates its argument.
2528 value = leaf.value.lstrip("furbFURB")
2529 if value[:3] == '"""':
2532 elif value[:3] == "'''":
2535 elif value[0] == '"':
2541 first_quote_pos = leaf.value.find(orig_quote)
2542 if first_quote_pos == -1:
2543 return # There's an internal error
2545 prefix = leaf.value[:first_quote_pos]
2546 unescaped_new_quote = re.compile(rf"(([^\\]|^)(\\\\)*){new_quote}")
2547 escaped_new_quote = re.compile(rf"([^\\]|^)\\((?:\\\\)*){new_quote}")
2548 escaped_orig_quote = re.compile(rf"([^\\]|^)\\((?:\\\\)*){orig_quote}")
2549 body = leaf.value[first_quote_pos + len(orig_quote) : -len(orig_quote)]
2550 if "r" in prefix.casefold():
2551 if unescaped_new_quote.search(body):
2552 # There's at least one unescaped new_quote in this raw string
2553 # so converting is impossible
2556 # Do not introduce or remove backslashes in raw strings
2559 # remove unnecessary escapes
2560 new_body = sub_twice(escaped_new_quote, rf"\1\2{new_quote}", body)
2561 if body != new_body:
2562 # Consider the string without unnecessary escapes as the original
2564 leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
2565 new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
2566 new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
2567 if "f" in prefix.casefold():
2568 matches = re.findall(r"[^{]\{(.*?)\}[^}]", new_body)
2571 # Do not introduce backslashes in interpolated expressions
2573 if new_quote == '"""' and new_body[-1:] == '"':
2575 new_body = new_body[:-1] + '\\"'
2576 orig_escape_count = body.count("\\")
2577 new_escape_count = new_body.count("\\")
2578 if new_escape_count > orig_escape_count:
2579 return # Do not introduce more escaping
2581 if new_escape_count == orig_escape_count and orig_quote == '"':
2582 return # Prefer double quotes
2584 leaf.value = f"{prefix}{new_quote}{new_body}{new_quote}"
2587 def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None:
2588 """Normalizes numeric (float, int, and complex) literals.
2590 All letters used in the representation are normalized to lowercase (except
2591 in Python 2 long literals), and long number literals are split using underscores.
2593 text = leaf.value.lower()
2594 if text.startswith(("0o", "0b")):
2595 # Leave octal and binary literals alone.
2597 elif text.startswith("0x"):
2598 # Change hex literals to upper case.
2599 before, after = text[:2], text[2:]
2600 text = f"{before}{after.upper()}"
2602 before, after = text.split("e")
2604 if after.startswith("-"):
2607 elif after.startswith("+"):
2609 before = format_float_or_int_string(before, allow_underscores)
2610 after = format_int_string(after, allow_underscores)
2611 text = f"{before}e{sign}{after}"
2612 elif text.endswith(("j", "l")):
2615 # Capitalize in "2L" because "l" looks too similar to "1".
2618 text = f"{format_float_or_int_string(number, allow_underscores)}{suffix}"
2620 text = format_float_or_int_string(text, allow_underscores)
2624 def format_float_or_int_string(text: str, allow_underscores: bool) -> str:
2625 """Formats a float string like "1.0"."""
2627 return format_int_string(text, allow_underscores)
2629 before, after = text.split(".")
2630 before = format_int_string(before, allow_underscores) if before else "0"
2632 after = format_int_string(after, allow_underscores, count_from_end=False)
2635 return f"{before}.{after}"
2638 def format_int_string(
2639 text: str, allow_underscores: bool, count_from_end: bool = True
2641 """Normalizes underscores in a string to e.g. 1_000_000.
2643 Input must be a string of digits and optional underscores.
2644 If count_from_end is False, we add underscores after groups of three digits
2645 counting from the beginning instead of the end of the strings. This is used
2646 for the fractional part of float literals.
2648 if not allow_underscores:
2651 text = text.replace("_", "")
2653 # No underscores for numbers <= 5 digits long.
2657 # Avoid removing leading zeros, which are important if we're formatting
2658 # part of a number like "0.001".
2659 return format(int("1" + text), "3_")[1:].lstrip("_")
2661 return "_".join(text[i : i + 3] for i in range(0, len(text), 3))
2664 def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None:
2665 """Make existing optional parentheses invisible or create new ones.
2667 `parens_after` is a set of string leaf values immeditely after which parens
2670 Standardizes on visible parentheses for single-element tuples, and keeps
2671 existing visible parentheses for other tuples and generator expressions.
2673 for pc in list_comments(node.prefix, is_endmarker=False):
2674 if pc.value in FMT_OFF:
2675 # This `node` has a prefix with `# fmt: off`, don't mess with parens.
2679 for index, child in enumerate(list(node.children)):
2681 if child.type == syms.atom:
2682 if maybe_make_parens_invisible_in_atom(child):
2683 lpar = Leaf(token.LPAR, "")
2684 rpar = Leaf(token.RPAR, "")
2685 index = child.remove() or 0
2686 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2687 elif is_one_tuple(child):
2688 # wrap child in visible parentheses
2689 lpar = Leaf(token.LPAR, "(")
2690 rpar = Leaf(token.RPAR, ")")
2692 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2693 elif node.type == syms.import_from:
2694 # "import from" nodes store parentheses directly as part of
2696 if child.type == token.LPAR:
2697 # make parentheses invisible
2698 child.value = "" # type: ignore
2699 node.children[-1].value = "" # type: ignore
2700 elif child.type != token.STAR:
2701 # insert invisible parentheses
2702 node.insert_child(index, Leaf(token.LPAR, ""))
2703 node.append_child(Leaf(token.RPAR, ""))
2706 elif not (isinstance(child, Leaf) and is_multiline_string(child)):
2707 # wrap child in invisible parentheses
2708 lpar = Leaf(token.LPAR, "")
2709 rpar = Leaf(token.RPAR, "")
2710 index = child.remove() or 0
2711 node.insert_child(index, Node(syms.atom, [lpar, child, rpar]))
2713 check_lpar = isinstance(child, Leaf) and child.value in parens_after
2716 def normalize_fmt_off(node: Node) -> None:
2717 """Convert content between `# fmt: off`/`# fmt: on` into standalone comments."""
2720 try_again = convert_one_fmt_off_pair(node)
2723 def convert_one_fmt_off_pair(node: Node) -> bool:
2724 """Convert content of a single `# fmt: off`/`# fmt: on` into a standalone comment.
2726 Returns True if a pair was converted.
2728 for leaf in node.leaves():
2729 previous_consumed = 0
2730 for comment in list_comments(leaf.prefix, is_endmarker=False):
2731 if comment.value in FMT_OFF:
2732 # We only want standalone comments. If there's no previous leaf or
2733 # the previous leaf is indentation, it's a standalone comment in
2735 if comment.type != STANDALONE_COMMENT:
2736 prev = preceding_leaf(leaf)
2737 if prev and prev.type not in WHITESPACE:
2740 ignored_nodes = list(generate_ignored_nodes(leaf))
2741 if not ignored_nodes:
2744 first = ignored_nodes[0] # Can be a container node with the `leaf`.
2745 parent = first.parent
2746 prefix = first.prefix
2747 first.prefix = prefix[comment.consumed :]
2749 comment.value + "\n" + "".join(str(n) for n in ignored_nodes)
2751 if hidden_value.endswith("\n"):
2752 # That happens when one of the `ignored_nodes` ended with a NEWLINE
2753 # leaf (possibly followed by a DEDENT).
2754 hidden_value = hidden_value[:-1]
2756 for ignored in ignored_nodes:
2757 index = ignored.remove()
2758 if first_idx is None:
2760 assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)"
2761 assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)"
2762 parent.insert_child(
2767 prefix=prefix[:previous_consumed] + "\n" * comment.newlines,
2772 previous_consumed = comment.consumed
2777 def generate_ignored_nodes(leaf: Leaf) -> Iterator[LN]:
2778 """Starting from the container of `leaf`, generate all leaves until `# fmt: on`.
2780 Stops at the end of the block.
2782 container: Optional[LN] = container_of(leaf)
2783 while container is not None and container.type != token.ENDMARKER:
2784 for comment in list_comments(container.prefix, is_endmarker=False):
2785 if comment.value in FMT_ON:
2790 container = container.next_sibling
2793 def maybe_make_parens_invisible_in_atom(node: LN) -> bool:
2794 """If it's safe, make the parens in the atom `node` invisible, recursively.
2796 Returns whether the node should itself be wrapped in invisible parentheses.
2800 node.type != syms.atom
2801 or is_empty_tuple(node)
2802 or is_one_tuple(node)
2804 or max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
2808 first = node.children[0]
2809 last = node.children[-1]
2810 if first.type == token.LPAR and last.type == token.RPAR:
2811 # make parentheses invisible
2812 first.value = "" # type: ignore
2813 last.value = "" # type: ignore
2814 if len(node.children) > 1:
2815 maybe_make_parens_invisible_in_atom(node.children[1])
2821 def is_empty_tuple(node: LN) -> bool:
2822 """Return True if `node` holds an empty tuple."""
2824 node.type == syms.atom
2825 and len(node.children) == 2
2826 and node.children[0].type == token.LPAR
2827 and node.children[1].type == token.RPAR
2831 def is_one_tuple(node: LN) -> bool:
2832 """Return True if `node` holds a tuple with one element, with or without parens."""
2833 if node.type == syms.atom:
2834 if len(node.children) != 3:
2837 lpar, gexp, rpar = node.children
2839 lpar.type == token.LPAR
2840 and gexp.type == syms.testlist_gexp
2841 and rpar.type == token.RPAR
2845 return len(gexp.children) == 2 and gexp.children[1].type == token.COMMA
2848 node.type in IMPLICIT_TUPLE
2849 and len(node.children) == 2
2850 and node.children[1].type == token.COMMA
2854 def is_yield(node: LN) -> bool:
2855 """Return True if `node` holds a `yield` or `yield from` expression."""
2856 if node.type == syms.yield_expr:
2859 if node.type == token.NAME and node.value == "yield": # type: ignore
2862 if node.type != syms.atom:
2865 if len(node.children) != 3:
2868 lpar, expr, rpar = node.children
2869 if lpar.type == token.LPAR and rpar.type == token.RPAR:
2870 return is_yield(expr)
2875 def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool:
2876 """Return True if `leaf` is a star or double star in a vararg or kwarg.
2878 If `within` includes VARARGS_PARENTS, this applies to function signatures.
2879 If `within` includes UNPACKING_PARENTS, it applies to right hand-side
2880 extended iterable unpacking (PEP 3132) and additional unpacking
2881 generalizations (PEP 448).
2883 if leaf.type not in STARS or not leaf.parent:
2887 if p.type == syms.star_expr:
2888 # Star expressions are also used as assignment targets in extended
2889 # iterable unpacking (PEP 3132). See what its parent is instead.
2895 return p.type in within
2898 def is_multiline_string(leaf: Leaf) -> bool:
2899 """Return True if `leaf` is a multiline string that actually spans many lines."""
2900 value = leaf.value.lstrip("furbFURB")
2901 return value[:3] in {'"""', "'''"} and "\n" in value
2904 def is_stub_suite(node: Node) -> bool:
2905 """Return True if `node` is a suite with a stub body."""
2907 len(node.children) != 4
2908 or node.children[0].type != token.NEWLINE
2909 or node.children[1].type != token.INDENT
2910 or node.children[3].type != token.DEDENT
2914 return is_stub_body(node.children[2])
2917 def is_stub_body(node: LN) -> bool:
2918 """Return True if `node` is a simple statement containing an ellipsis."""
2919 if not isinstance(node, Node) or node.type != syms.simple_stmt:
2922 if len(node.children) != 2:
2925 child = node.children[0]
2927 child.type == syms.atom
2928 and len(child.children) == 3
2929 and all(leaf == Leaf(token.DOT, ".") for leaf in child.children)
2933 def max_delimiter_priority_in_atom(node: LN) -> int:
2934 """Return maximum delimiter priority inside `node`.
2936 This is specific to atoms with contents contained in a pair of parentheses.
2937 If `node` isn't an atom or there are no enclosing parentheses, returns 0.
2939 if node.type != syms.atom:
2942 first = node.children[0]
2943 last = node.children[-1]
2944 if not (first.type == token.LPAR and last.type == token.RPAR):
2947 bt = BracketTracker()
2948 for c in node.children[1:-1]:
2949 if isinstance(c, Leaf):
2952 for leaf in c.leaves():
2955 return bt.max_delimiter_priority()
2961 def ensure_visible(leaf: Leaf) -> None:
2962 """Make sure parentheses are visible.
2964 They could be invisible as part of some statements (see
2965 :func:`normalize_invible_parens` and :func:`visit_import_from`).
2967 if leaf.type == token.LPAR:
2969 elif leaf.type == token.RPAR:
2973 def should_explode(line: Line, opening_bracket: Leaf) -> bool:
2974 """Should `line` immediately be split with `delimiter_split()` after RHS?"""
2977 opening_bracket.parent
2978 and opening_bracket.parent.type in {syms.atom, syms.import_from}
2979 and opening_bracket.value in "[{("
2984 last_leaf = line.leaves[-1]
2985 exclude = {id(last_leaf)} if last_leaf.type == token.COMMA else set()
2986 max_priority = line.bracket_tracker.max_delimiter_priority(exclude=exclude)
2987 except (IndexError, ValueError):
2990 return max_priority == COMMA_PRIORITY
2993 def is_python36(node: Node) -> bool:
2994 """Return True if the current file is using Python 3.6+ features.
2996 Currently looking for:
2998 - underscores in numeric literals; and
2999 - trailing commas after * or ** in function signatures and calls.
3001 for n in node.pre_order():
3002 if n.type == token.STRING:
3003 value_head = n.value[:2] # type: ignore
3004 if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
3007 elif n.type == token.NUMBER:
3008 if "_" in n.value: # type: ignore
3012 n.type in {syms.typedargslist, syms.arglist}
3014 and n.children[-1].type == token.COMMA
3016 for ch in n.children:
3017 if ch.type in STARS:
3020 if ch.type == syms.argument:
3021 for argch in ch.children:
3022 if argch.type in STARS:
3028 def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[LeafID]]:
3029 """Generate sets of closing bracket IDs that should be omitted in a RHS.
3031 Brackets can be omitted if the entire trailer up to and including
3032 a preceding closing bracket fits in one line.
3034 Yielded sets are cumulative (contain results of previous yields, too). First
3038 omit: Set[LeafID] = set()
3041 length = 4 * line.depth
3042 opening_bracket = None
3043 closing_bracket = None
3044 inner_brackets: Set[LeafID] = set()
3045 for index, leaf, leaf_length in enumerate_with_length(line, reversed=True):
3046 length += leaf_length
3047 if length > line_length:
3050 has_inline_comment = leaf_length > len(leaf.value) + len(leaf.prefix)
3051 if leaf.type == STANDALONE_COMMENT or has_inline_comment:
3055 if leaf is opening_bracket:
3056 opening_bracket = None
3057 elif leaf.type in CLOSING_BRACKETS:
3058 inner_brackets.add(id(leaf))
3059 elif leaf.type in CLOSING_BRACKETS:
3060 if index > 0 and line.leaves[index - 1].type in OPENING_BRACKETS:
3061 # Empty brackets would fail a split so treat them as "inner"
3062 # brackets (e.g. only add them to the `omit` set if another
3063 # pair of brackets was good enough.
3064 inner_brackets.add(id(leaf))
3068 omit.add(id(closing_bracket))
3069 omit.update(inner_brackets)
3070 inner_brackets.clear()
3074 opening_bracket = leaf.opening_bracket
3075 closing_bracket = leaf
3078 def get_future_imports(node: Node) -> Set[str]:
3079 """Return a set of __future__ imports in the file."""
3080 imports: Set[str] = set()
3082 def get_imports_from_children(children: List[LN]) -> Generator[str, None, None]:
3083 for child in children:
3084 if isinstance(child, Leaf):
3085 if child.type == token.NAME:
3087 elif child.type == syms.import_as_name:
3088 orig_name = child.children[0]
3089 assert isinstance(orig_name, Leaf), "Invalid syntax parsing imports"
3090 assert orig_name.type == token.NAME, "Invalid syntax parsing imports"
3091 yield orig_name.value
3092 elif child.type == syms.import_as_names:
3093 yield from get_imports_from_children(child.children)
3095 assert False, "Invalid syntax parsing imports"
3097 for child in node.children:
3098 if child.type != syms.simple_stmt:
3100 first_child = child.children[0]
3101 if isinstance(first_child, Leaf):
3102 # Continue looking if we see a docstring; otherwise stop.
3104 len(child.children) == 2
3105 and first_child.type == token.STRING
3106 and child.children[1].type == token.NEWLINE
3111 elif first_child.type == syms.import_from:
3112 module_name = first_child.children[1]
3113 if not isinstance(module_name, Leaf) or module_name.value != "__future__":
3115 imports |= set(get_imports_from_children(first_child.children[3:]))
3121 def gen_python_files_in_dir(
3124 include: Pattern[str],
3125 exclude: Pattern[str],
3127 ) -> Iterator[Path]:
3128 """Generate all files under `path` whose paths are not excluded by the
3129 `exclude` regex, but are included by the `include` regex.
3131 Symbolic links pointing outside of the `root` directory are ignored.
3133 `report` is where output about exclusions goes.
3135 assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}"
3136 for child in path.iterdir():
3138 normalized_path = "/" + child.resolve().relative_to(root).as_posix()
3140 if child.is_symlink():
3141 report.path_ignored(
3142 child, f"is a symbolic link that points outside {root}"
3149 normalized_path += "/"
3150 exclude_match = exclude.search(normalized_path)
3151 if exclude_match and exclude_match.group(0):
3152 report.path_ignored(child, f"matches the --exclude regular expression")
3156 yield from gen_python_files_in_dir(child, root, include, exclude, report)
3158 elif child.is_file():
3159 include_match = include.search(normalized_path)
3165 def find_project_root(srcs: Iterable[str]) -> Path:
3166 """Return a directory containing .git, .hg, or pyproject.toml.
3168 That directory can be one of the directories passed in `srcs` or their
3171 If no directory in the tree contains a marker that would specify it's the
3172 project root, the root of the file system is returned.
3175 return Path("/").resolve()
3177 common_base = min(Path(src).resolve() for src in srcs)
3178 if common_base.is_dir():
3179 # Append a fake file so `parents` below returns `common_base_dir`, too.
3180 common_base /= "fake-file"
3181 for directory in common_base.parents:
3182 if (directory / ".git").is_dir():
3185 if (directory / ".hg").is_dir():
3188 if (directory / "pyproject.toml").is_file():
3196 """Provides a reformatting counter. Can be rendered with `str(report)`."""
3200 verbose: bool = False
3201 change_count: int = 0
3203 failure_count: int = 0
3205 def done(self, src: Path, changed: Changed) -> None:
3206 """Increment the counter for successful reformatting. Write out a message."""
3207 if changed is Changed.YES:
3208 reformatted = "would reformat" if self.check else "reformatted"
3209 if self.verbose or not self.quiet:
3210 out(f"{reformatted} {src}")
3211 self.change_count += 1
3214 if changed is Changed.NO:
3215 msg = f"{src} already well formatted, good job."
3217 msg = f"{src} wasn't modified on disk since last run."
3218 out(msg, bold=False)
3219 self.same_count += 1
3221 def failed(self, src: Path, message: str) -> None:
3222 """Increment the counter for failed reformatting. Write out a message."""
3223 err(f"error: cannot format {src}: {message}")
3224 self.failure_count += 1
3226 def path_ignored(self, path: Path, message: str) -> None:
3228 out(f"{path} ignored: {message}", bold=False)
3231 def return_code(self) -> int:
3232 """Return the exit code that the app should use.
3234 This considers the current state of changed files and failures:
3235 - if there were any failures, return 123;
3236 - if any files were changed and --check is being used, return 1;
3237 - otherwise return 0.
3239 # According to http://tldp.org/LDP/abs/html/exitcodes.html starting with
3240 # 126 we have special return codes reserved by the shell.
3241 if self.failure_count:
3244 elif self.change_count and self.check:
3249 def __str__(self) -> str:
3250 """Render a color report of the current state.
3252 Use `click.unstyle` to remove colors.
3255 reformatted = "would be reformatted"
3256 unchanged = "would be left unchanged"
3257 failed = "would fail to reformat"
3259 reformatted = "reformatted"
3260 unchanged = "left unchanged"
3261 failed = "failed to reformat"
3263 if self.change_count:
3264 s = "s" if self.change_count > 1 else ""
3266 click.style(f"{self.change_count} file{s} {reformatted}", bold=True)
3269 s = "s" if self.same_count > 1 else ""
3270 report.append(f"{self.same_count} file{s} {unchanged}")
3271 if self.failure_count:
3272 s = "s" if self.failure_count > 1 else ""
3274 click.style(f"{self.failure_count} file{s} {failed}", fg="red")
3276 return ", ".join(report) + "."
3279 def assert_equivalent(src: str, dst: str) -> None:
3280 """Raise AssertionError if `src` and `dst` aren't equivalent."""
3285 def _v(node: ast.AST, depth: int = 0) -> Iterator[str]:
3286 """Simple visitor generating strings to compare ASTs by content."""
3287 yield f"{' ' * depth}{node.__class__.__name__}("
3289 for field in sorted(node._fields):
3291 value = getattr(node, field)
3292 except AttributeError:
3295 yield f"{' ' * (depth+1)}{field}="
3297 if isinstance(value, list):
3299 if isinstance(item, ast.AST):
3300 yield from _v(item, depth + 2)
3302 elif isinstance(value, ast.AST):
3303 yield from _v(value, depth + 2)
3306 yield f"{' ' * (depth+2)}{value!r}, # {value.__class__.__name__}"
3308 yield f"{' ' * depth}) # /{node.__class__.__name__}"
3311 src_ast = ast.parse(src)
3312 except Exception as exc:
3313 major, minor = sys.version_info[:2]
3314 raise AssertionError(
3315 f"cannot use --safe with this file; failed to parse source file "
3316 f"with Python {major}.{minor}'s builtin AST. Re-run with --fast "
3317 f"or stop using deprecated Python 2 syntax. AST error message: {exc}"
3321 dst_ast = ast.parse(dst)
3322 except Exception as exc:
3323 log = dump_to_file("".join(traceback.format_tb(exc.__traceback__)), dst)
3324 raise AssertionError(
3325 f"INTERNAL ERROR: Black produced invalid code: {exc}. "
3326 f"Please report a bug on https://github.com/ambv/black/issues. "
3327 f"This invalid output might be helpful: {log}"
3330 src_ast_str = "\n".join(_v(src_ast))
3331 dst_ast_str = "\n".join(_v(dst_ast))
3332 if src_ast_str != dst_ast_str:
3333 log = dump_to_file(diff(src_ast_str, dst_ast_str, "src", "dst"))
3334 raise AssertionError(
3335 f"INTERNAL ERROR: Black produced code that is not equivalent to "
3337 f"Please report a bug on https://github.com/ambv/black/issues. "
3338 f"This diff might be helpful: {log}"
3343 src: str, dst: str, line_length: int, mode: FileMode = FileMode.AUTO_DETECT
3345 """Raise AssertionError if `dst` reformats differently the second time."""
3346 newdst = format_str(dst, line_length=line_length, mode=mode)
3349 diff(src, dst, "source", "first pass"),
3350 diff(dst, newdst, "first pass", "second pass"),
3352 raise AssertionError(
3353 f"INTERNAL ERROR: Black produced different code on the second pass "
3354 f"of the formatter. "
3355 f"Please report a bug on https://github.com/ambv/black/issues. "
3356 f"This diff might be helpful: {log}"
3360 def dump_to_file(*output: str) -> str:
3361 """Dump `output` to a temporary file. Return path to the file."""
3364 with tempfile.NamedTemporaryFile(
3365 mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8"
3367 for lines in output:
3369 if lines and lines[-1] != "\n":
3374 def diff(a: str, b: str, a_name: str, b_name: str) -> str:
3375 """Return a unified diff string between strings `a` and `b`."""
3378 a_lines = [line + "\n" for line in a.split("\n")]
3379 b_lines = [line + "\n" for line in b.split("\n")]
3381 difflib.unified_diff(a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5)
3385 def cancel(tasks: Iterable[asyncio.Task]) -> None:
3386 """asyncio signal handler that cancels all `tasks` and reports to stderr."""
3392 def shutdown(loop: BaseEventLoop) -> None:
3393 """Cancel all pending tasks on `loop`, wait for them, and close the loop."""
3395 # This part is borrowed from asyncio/runners.py in Python 3.7b2.
3396 to_cancel = [task for task in asyncio.Task.all_tasks(loop) if not task.done()]
3400 for task in to_cancel:
3402 loop.run_until_complete(
3403 asyncio.gather(*to_cancel, loop=loop, return_exceptions=True)
3406 # `concurrent.futures.Future` objects cannot be cancelled once they
3407 # are already running. There might be some when the `shutdown()` happened.
3408 # Silence their logger's spew about the event loop being closed.
3409 cf_logger = logging.getLogger("concurrent.futures")
3410 cf_logger.setLevel(logging.CRITICAL)
3414 def sub_twice(regex: Pattern[str], replacement: str, original: str) -> str:
3415 """Replace `regex` with `replacement` twice on `original`.
3417 This is used by string normalization to perform replaces on
3418 overlapping matches.
3420 return regex.sub(replacement, regex.sub(replacement, original))
3423 def re_compile_maybe_verbose(regex: str) -> Pattern[str]:
3424 """Compile a regular expression string in `regex`.
3426 If it contains newlines, use verbose mode.
3429 regex = "(?x)" + regex
3430 return re.compile(regex)
3433 def enumerate_reversed(sequence: Sequence[T]) -> Iterator[Tuple[Index, T]]:
3434 """Like `reversed(enumerate(sequence))` if that were possible."""
3435 index = len(sequence) - 1
3436 for element in reversed(sequence):
3437 yield (index, element)
3441 def enumerate_with_length(
3442 line: Line, reversed: bool = False
3443 ) -> Iterator[Tuple[Index, Leaf, int]]:
3444 """Return an enumeration of leaves with their length.
3446 Stops prematurely on multiline strings and standalone comments.
3449 Callable[[Sequence[Leaf]], Iterator[Tuple[Index, Leaf]]],
3450 enumerate_reversed if reversed else enumerate,
3452 for index, leaf in op(line.leaves):
3453 length = len(leaf.prefix) + len(leaf.value)
3454 if "\n" in leaf.value:
3455 return # Multiline strings, we can't continue.
3457 comment: Optional[Leaf]
3458 for comment in line.comments_after(leaf):
3459 length += len(comment.value)
3461 yield index, leaf, length
3464 def is_line_short_enough(line: Line, *, line_length: int, line_str: str = "") -> bool:
3465 """Return True if `line` is no longer than `line_length`.
3467 Uses the provided `line_str` rendering, if any, otherwise computes a new one.
3470 line_str = str(line).strip("\n")
3472 len(line_str) <= line_length
3473 and "\n" not in line_str # multiline strings
3474 and not line.contains_standalone_comments()
3478 def can_be_split(line: Line) -> bool:
3479 """Return False if the line cannot be split *for sure*.
3481 This is not an exhaustive search but a cheap heuristic that we can use to
3482 avoid some unfortunate formattings (mostly around wrapping unsplittable code
3483 in unnecessary parentheses).
3485 leaves = line.leaves
3489 if leaves[0].type == token.STRING and leaves[1].type == token.DOT:
3493 for leaf in leaves[-2::-1]:
3494 if leaf.type in OPENING_BRACKETS:
3495 if next.type not in CLOSING_BRACKETS:
3499 elif leaf.type == token.DOT:
3501 elif leaf.type == token.NAME:
3502 if not (next.type == token.DOT or next.type in OPENING_BRACKETS):
3505 elif leaf.type not in CLOSING_BRACKETS:
3508 if dot_count > 1 and call_count > 1:
3514 def can_omit_invisible_parens(line: Line, line_length: int) -> bool:
3515 """Does `line` have a shape safe to reformat without optional parens around it?
3517 Returns True for only a subset of potentially nice looking formattings but
3518 the point is to not return false positives that end up producing lines that
3521 bt = line.bracket_tracker
3522 if not bt.delimiters:
3523 # Without delimiters the optional parentheses are useless.
3526 max_priority = bt.max_delimiter_priority()
3527 if bt.delimiter_count_with_priority(max_priority) > 1:
3528 # With more than one delimiter of a kind the optional parentheses read better.
3531 if max_priority == DOT_PRIORITY:
3532 # A single stranded method call doesn't require optional parentheses.
3535 assert len(line.leaves) >= 2, "Stranded delimiter"
3537 first = line.leaves[0]
3538 second = line.leaves[1]
3539 penultimate = line.leaves[-2]
3540 last = line.leaves[-1]
3542 # With a single delimiter, omit if the expression starts or ends with
3544 if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS:
3546 length = 4 * line.depth
3547 for _index, leaf, leaf_length in enumerate_with_length(line):
3548 if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first:
3551 length += leaf_length
3552 if length > line_length:
3555 if leaf.type in OPENING_BRACKETS:
3556 # There are brackets we can further split on.
3560 # checked the entire string and line length wasn't exceeded
3561 if len(line.leaves) == _index + 1:
3564 # Note: we are not returning False here because a line might have *both*
3565 # a leading opening bracket and a trailing closing bracket. If the
3566 # opening bracket doesn't match our rule, maybe the closing will.
3569 last.type == token.RPAR
3570 or last.type == token.RBRACE
3572 # don't use indexing for omitting optional parentheses;
3574 last.type == token.RSQB
3576 and last.parent.type != syms.trailer
3579 if penultimate.type in OPENING_BRACKETS:
3580 # Empty brackets don't help.
3583 if is_multiline_string(first):
3584 # Additional wrapping of a multiline string in this situation is
3588 length = 4 * line.depth
3589 seen_other_brackets = False
3590 for _index, leaf, leaf_length in enumerate_with_length(line):
3591 length += leaf_length
3592 if leaf is last.opening_bracket:
3593 if seen_other_brackets or length <= line_length:
3596 elif leaf.type in OPENING_BRACKETS:
3597 # There are brackets we can further split on.
3598 seen_other_brackets = True
3603 def get_cache_file(line_length: int, mode: FileMode) -> Path:
3604 return CACHE_DIR / f"cache.{line_length}.{mode.value}.pickle"
3607 def read_cache(line_length: int, mode: FileMode) -> Cache:
3608 """Read the cache if it exists and is well formed.
3610 If it is not well formed, the call to write_cache later should resolve the issue.
3612 cache_file = get_cache_file(line_length, mode)
3613 if not cache_file.exists():
3616 with cache_file.open("rb") as fobj:
3618 cache: Cache = pickle.load(fobj)
3619 except pickle.UnpicklingError:
3625 def get_cache_info(path: Path) -> CacheInfo:
3626 """Return the information used to check if a file is already formatted or not."""
3628 return stat.st_mtime, stat.st_size
3631 def filter_cached(cache: Cache, sources: Iterable[Path]) -> Tuple[Set[Path], Set[Path]]:
3632 """Split an iterable of paths in `sources` into two sets.
3634 The first contains paths of files that modified on disk or are not in the
3635 cache. The other contains paths to non-modified files.
3637 todo, done = set(), set()
3640 if cache.get(src) != get_cache_info(src):
3648 cache: Cache, sources: Iterable[Path], line_length: int, mode: FileMode
3650 """Update the cache file."""
3651 cache_file = get_cache_file(line_length, mode)
3653 if not CACHE_DIR.exists():
3654 CACHE_DIR.mkdir(parents=True)
3655 new_cache = {**cache, **{src.resolve(): get_cache_info(src) for src in sources}}
3656 with cache_file.open("wb") as fobj:
3657 pickle.dump(new_cache, fobj, protocol=pickle.HIGHEST_PROTOCOL)
3662 def patch_click() -> None:
3663 """Make Click not crash.
3665 On certain misconfigured environments, Python 3 selects the ASCII encoding as the
3666 default which restricts paths that it can access during the lifetime of the
3667 application. Click refuses to work in this scenario by raising a RuntimeError.
3669 In case of Black the likelihood that non-ASCII characters are going to be used in
3670 file paths is minimal since it's Python source code. Moreover, this crash was
3671 spurious on Python 3.7 thanks to PEP 538 and PEP 540.
3674 from click import core
3675 from click import _unicodefun # type: ignore
3676 except ModuleNotFoundError:
3679 for module in (core, _unicodefun):
3680 if hasattr(module, "_verify_python3_env"):
3681 module._verify_python3_env = lambda: None
3684 def patched_main() -> None:
3690 if __name__ == "__main__":