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

78 statements  

1"""Nice output for Black. 

2 

3The double calls are for patching purposes in tests. 

4""" 

5 

6import json 

7import os 

8import re 

9import tempfile 

10from typing import Any 

11 

12from click import echo, style 

13from mypy_extensions import mypyc_attr 

14 

15 

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) 

23 

24 

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) 

32 

33 

34@mypyc_attr(patchable=True) 

35def out(message: str | None = None, nl: bool = True, **styles: Any) -> None: 

36 _out(message, nl=nl, **styles) 

37 

38 

39def err(message: str | None = None, nl: bool = True, **styles: Any) -> None: 

40 _err(message, nl=nl, **styles) 

41 

42 

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) 

58 

59 

60_line_pattern = re.compile(r"(.*?(?:\r\n|\n|\r|$))") 

61 

62 

63def _splitlines_no_ff(source: str) -> list[str]: 

64 """Split a string into lines ignoring form feed and other chars. 

65 

66 This mimics how the Python parser splits source code. 

67 

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 

74 

75 

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 

79 

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) 

95 

96 

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) 

113 

114 

115def style_output(message: str, **styles: Any) -> str: 

116 if not _color_enabled(): 

117 return message 

118 return style(message, **styles) 

119 

120 

121def _color_enabled() -> bool: 

122 return "NO_COLOR" not in os.environ 

123 

124 

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