Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/output.py: 31%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Nice output for Black.
3The double calls are for patching purposes in tests.
4"""
6import json
7import os
8import re
9import tempfile
10from typing import Any
12from click import echo, style
13from mypy_extensions import mypyc_attr
16@mypyc_attr(patchable=True)
17def _out(message: str | None = None, nl: bool = True, **styles: Any) -> None:
18 if message is not None:
19 if "bold" not in styles:
20 styles["bold"] = True
21 message = style_output(message, **styles)
22 echo(message, nl=nl, err=True)
25@mypyc_attr(patchable=True)
26def _err(message: str | None = None, nl: bool = True, **styles: Any) -> None:
27 if message is not None:
28 if "fg" not in styles:
29 styles["fg"] = "red"
30 message = style_output(message, **styles)
31 echo(message, nl=nl, err=True)
34@mypyc_attr(patchable=True)
35def out(message: str | None = None, nl: bool = True, **styles: Any) -> None:
36 _out(message, nl=nl, **styles)
39def err(message: str | None = None, nl: bool = True, **styles: Any) -> None:
40 _err(message, nl=nl, **styles)
43def ipynb_diff(a: str, b: str, a_name: str, b_name: str) -> str:
44 """Return a unified diff string between each cell in notebooks `a` and `b`."""
45 a_nb = json.loads(a)
46 b_nb = json.loads(b)
47 diff_lines = [
48 diff(
49 "".join(a_nb["cells"][cell_number]["source"]) + "\n",
50 "".join(b_nb["cells"][cell_number]["source"]) + "\n",
51 f"{a_name}:cell_{cell_number}",
52 f"{b_name}:cell_{cell_number}",
53 )
54 for cell_number, cell in enumerate(a_nb["cells"])
55 if cell["cell_type"] == "code"
56 ]
57 return "".join(diff_lines)
60_line_pattern = re.compile(r"(.*?(?:\r\n|\n|\r|$))")
63def _splitlines_no_ff(source: str) -> list[str]:
64 """Split a string into lines ignoring form feed and other chars.
66 This mimics how the Python parser splits source code.
68 A simplified version of the function with the same name in Lib/ast.py
69 """
70 result = [match[0] for match in _line_pattern.finditer(source)]
71 if result[-1] == "":
72 result.pop(-1)
73 return result
76def diff(a: str, b: str, a_name: str, b_name: str) -> str:
77 """Return a unified diff string between strings `a` and `b`."""
78 import difflib
80 a_lines = _splitlines_no_ff(a)
81 b_lines = _splitlines_no_ff(b)
82 diff_lines = []
83 for line in difflib.unified_diff(
84 a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5
85 ):
86 # Work around https://bugs.python.org/issue2142
87 # See:
88 # https://www.gnu.org/software/diffutils/manual/html_node/Incomplete-Lines.html
89 if line[-1] == "\n":
90 diff_lines.append(line)
91 else:
92 diff_lines.append(line + "\n")
93 diff_lines.append("\\ No newline at end of file\n")
94 return "".join(diff_lines)
97def color_diff(contents: str) -> str:
98 """Inject the ANSI color codes to the diff."""
99 if not _color_enabled():
100 return contents
101 lines = contents.split("\n")
102 for i, line in enumerate(lines):
103 if line.startswith("+++") or line.startswith("---"):
104 line = "\033[1m" + line + "\033[0m" # bold, reset
105 elif line.startswith("@@"):
106 line = "\033[36m" + line + "\033[0m" # cyan, reset
107 elif line.startswith("+"):
108 line = "\033[32m" + line + "\033[0m" # green, reset
109 elif line.startswith("-"):
110 line = "\033[31m" + line + "\033[0m" # red, reset
111 lines[i] = line
112 return "\n".join(lines)
115def style_output(message: str, **styles: Any) -> str:
116 if not _color_enabled():
117 return message
118 return style(message, **styles)
121def _color_enabled() -> bool:
122 return "NO_COLOR" not in os.environ
125@mypyc_attr(patchable=True)
126def dump_to_file(*output: str, ensure_final_newline: bool = True) -> str:
127 """Dump `output` to a temporary file. Return path to the file."""
128 with tempfile.NamedTemporaryFile(
129 mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8"
130 ) as f:
131 for lines in output:
132 f.write(lines)
133 if ensure_final_newline and lines and lines[-1] != "\n":
134 f.write("\n")
135 return f.name