Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/output.py: 30%

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

69 statements  

1"""Nice output for Black. 

2 

3The double calls are for patching purposes in tests. 

4""" 

5 

6import json 

7import re 

8import tempfile 

9from typing import Any, Optional 

10 

11from click import echo, style 

12from mypy_extensions import mypyc_attr 

13 

14 

15@mypyc_attr(patchable=True) 

16def _out(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: 

17 if message is not None: 

18 if "bold" not in styles: 

19 styles["bold"] = True 

20 message = style(message, **styles) 

21 echo(message, nl=nl, err=True) 

22 

23 

24@mypyc_attr(patchable=True) 

25def _err(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: 

26 if message is not None: 

27 if "fg" not in styles: 

28 styles["fg"] = "red" 

29 message = style(message, **styles) 

30 echo(message, nl=nl, err=True) 

31 

32 

33@mypyc_attr(patchable=True) 

34def out(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: 

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

36 

37 

38def err(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: 

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

40 

41 

42def ipynb_diff(a: str, b: str, a_name: str, b_name: str) -> str: 

43 """Return a unified diff string between each cell in notebooks `a` and `b`.""" 

44 a_nb = json.loads(a) 

45 b_nb = json.loads(b) 

46 diff_lines = [ 

47 diff( 

48 "".join(a_nb["cells"][cell_number]["source"]) + "\n", 

49 "".join(b_nb["cells"][cell_number]["source"]) + "\n", 

50 f"{a_name}:cell_{cell_number}", 

51 f"{b_name}:cell_{cell_number}", 

52 ) 

53 for cell_number, cell in enumerate(a_nb["cells"]) 

54 if cell["cell_type"] == "code" 

55 ] 

56 return "".join(diff_lines) 

57 

58 

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

60 

61 

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

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

64 

65 This mimics how the Python parser splits source code. 

66 

67 A simplified version of the function with the same name in Lib/ast.py 

68 """ 

69 result = [match[0] for match in _line_pattern.finditer(source)] 

70 if result[-1] == "": 

71 result.pop(-1) 

72 return result 

73 

74 

75def diff(a: str, b: str, a_name: str, b_name: str) -> str: 

76 """Return a unified diff string between strings `a` and `b`.""" 

77 import difflib 

78 

79 a_lines = _splitlines_no_ff(a) 

80 b_lines = _splitlines_no_ff(b) 

81 diff_lines = [] 

82 for line in difflib.unified_diff( 

83 a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5 

84 ): 

85 # Work around https://bugs.python.org/issue2142 

86 # See: 

87 # https://www.gnu.org/software/diffutils/manual/html_node/Incomplete-Lines.html 

88 if line[-1] == "\n": 

89 diff_lines.append(line) 

90 else: 

91 diff_lines.append(line + "\n") 

92 diff_lines.append("\\ No newline at end of file\n") 

93 return "".join(diff_lines) 

94 

95 

96def color_diff(contents: str) -> str: 

97 """Inject the ANSI color codes to the diff.""" 

98 lines = contents.split("\n") 

99 for i, line in enumerate(lines): 

100 if line.startswith("+++") or line.startswith("---"): 

101 line = "\033[1m" + line + "\033[0m" # bold, reset 

102 elif line.startswith("@@"): 

103 line = "\033[36m" + line + "\033[0m" # cyan, reset 

104 elif line.startswith("+"): 

105 line = "\033[32m" + line + "\033[0m" # green, reset 

106 elif line.startswith("-"): 

107 line = "\033[31m" + line + "\033[0m" # red, reset 

108 lines[i] = line 

109 return "\n".join(lines) 

110 

111 

112@mypyc_attr(patchable=True) 

113def dump_to_file(*output: str, ensure_final_newline: bool = True) -> str: 

114 """Dump `output` to a temporary file. Return path to the file.""" 

115 with tempfile.NamedTemporaryFile( 

116 mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8" 

117 ) as f: 

118 for lines in output: 

119 f.write(lines) 

120 if ensure_final_newline and lines and lines[-1] != "\n": 

121 f.write("\n") 

122 return f.name