-
Notifications
You must be signed in to change notification settings - Fork 0
/
black_cgx.py
141 lines (106 loc) · 3.7 KB
/
black_cgx.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import logging
from os.path import relpath
from pathlib import Path
import black
try:
import tomllib
except ImportError:
import tomli as tomllib
from collagraph.cgx import cgx
logger = logging.getLogger(__name__)
class BadBlackConfig(ValueError):
"""Bad black TOML configuration file."""
pass
def project_root_config(path):
project_root, _ = black.find_project_root((path,))
pyproject_path = project_root / "pyproject.toml"
return pyproject_path
def load_black_mode_from_config(pyproject_path):
black_config = {}
if pyproject_path.is_file():
try:
with pyproject_path.open(mode="rb") as toml_file:
pyproject_toml = tomllib.load(toml_file)
except ValueError:
raise BadBlackConfig(relpath(pyproject_path))
config = pyproject_toml.get("tool", {}).get("black", {})
black_config = {
k.replace("--", "").replace("-", "_"): v for k, v in config.items()
}
return black.FileMode(
target_versions={
black.TargetVersion[val.upper()]
for val in black_config.get("target_version", [])
},
# cast to int explicitly otherwise line length could be a string
line_length=int(black_config.get("line_length", black.DEFAULT_LINE_LENGTH)),
string_normalization=not black_config.get("skip_string_normalization", False),
magic_trailing_comma=not black_config.get("skip_magic_trailing_comma", False),
preview=bool(black_config.get("preview", False)),
)
def load_black_mode(path, modes=None):
pyproject_path = project_root_config(path)
if pyproject_path not in modes:
modes[pyproject_path] = load_black_mode_from_config(pyproject_path)
return modes[pyproject_path]
def format(path, mode=None, check=False):
"""Format CGX files (the contents of the script tag) with black"""
path = Path(path)
if path.suffix != ".cgx":
return
if mode is None:
mode = load_black_mode(path, {})
parser = cgx.CGXParser()
parser.feed(path.read_text())
# Find beginning and end of script block
script_node = parser.root.child_with_tag("script")
start, end = script_node.location[0], script_node.end[0] - 1
with open(path, mode="r") as fh:
lines = fh.readlines()
source = "".join(lines[start:end])
try:
formatted_source = black.format_file_contents(source, fast=False, mode=mode)
if check:
logger.warning(f"Would change: {path}")
return 1
lines[start:end] = formatted_source
logger.warning(f"Blackened: {path}")
with open(path, mode="w") as fh:
fh.writelines(lines)
except black.report.NothingChanged:
pass
except Exception as e:
logger.exception(e)
return 1
return 0
def main(argv=None):
import argparse
import sys
if argv is None:
argv = sys.argv[1:]
parser = argparse.ArgumentParser(description="Format cgx files with black")
parser.add_argument("--check", action="store_true")
parser.add_argument(
"path",
nargs="*",
type=Path,
default=[Path(".")],
help="path(s) of files and/or folders to format",
)
args = parser.parse_args(argv)
modes = {}
code = 0
for path in args.path:
if not path.exists():
pass
if path.is_file():
code |= format(path, mode=load_black_mode(path, modes), check=args.check)
else:
for file in path.glob("**/*.cgx"):
code |= format(
file, mode=load_black_mode(file, modes), check=args.check
)
if code:
exit(code)
if __name__ == "__main__":
main()