Coverage for gws-app/gws/spec/generator/util.py: 59%
44 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""File, JSON and ini helpers for the generator."""
3import os
4import re
5import json
7from gws.lib.cli import (
8 find_files,
9 find_dirs,
10 read_file,
11 write_file,
12 ensure_dir,
13)
16def _json(x):
17 if isinstance(x, bytes):
18 return x.hex()
19 try:
20 return vars(x)
21 except:
22 return repr(x)
25def write_json(path, obj):
26 """Write an object to a JSON file.
28 Objects are written as their attribute dicts, bytes as hex strings,
29 other values that are not JSON serializable as their ``repr``.
31 Args:
32 path: File path.
33 obj: Object to write.
34 """
36 write_file(path, json.dumps(obj, default=_json, indent=4, sort_keys=True))
39def read_json(path):
40 """Read a JSON file.
42 Args:
43 path: File path.
45 Returns:
46 The parsed JSON value.
47 """
49 return json.loads(read_file(path))
52def parse_ini(text):
53 """Parse an ini-style strings file.
55 Lines starting with ``;``, ``#`` or ``//`` are comments. A line without
56 ``=`` continues the value of the previous key. ``\\n`` in values is
57 converted to a newline.
59 Args:
60 text: File content.
62 Returns:
63 A dict of sections, each a dict of keys and values.
65 Raises:
66 ``ValueError``: If a line cannot be parsed.
67 """
69 dct = {}
70 section = ''
71 key = ''
73 for ln in text.strip().splitlines():
74 ln = ln.strip()
75 if ln.startswith((';', '#', '//')):
76 continue
77 if ln.startswith('['):
78 section = ln[1:-1].strip()
79 continue
80 m = re.match(r'^([a-zA-Z0-9_.]+)\s*=(.*)', ln)
81 if m:
82 key = m.group(1).strip()
83 val = m.group(2)
84 dct.setdefault(section, {})[key] = val.strip().replace('\\n', '\n')
85 elif key:
86 dct[section][key] += '\n' + ln.strip()
87 elif ln:
88 raise ValueError(f'invalid ini string {ln!r}')
90 return dct
93def make_ini(dct):
94 """Create an ini-style text from a dict of sections.
96 Keys are sorted, newlines in values are written as ``\\n``.
98 Args:
99 dct: A dict of sections, each a dict of keys and values.
101 Returns:
102 The ini text.
103 """
105 buf = []
107 for sec, rows in dct.items():
108 buf.append('[' + sec + ']')
109 for k, v in sorted(rows.items()):
110 buf.append(k + '=' + v.replace('\n', '\\n'))
111 buf.append('')
113 return '\n'.join(buf)