blob: 4038ea8203e7377b8bec7d8aa959ccb497c5e659 [file] [log] [blame]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03001__doc__ = "functions for make pretty yaml files"
2__all__ = ['dumps']
3
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03004from typing import Any, Iterable
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03005
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03006
7def dumps_simple(val: Any) -> str:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +03008 bad_symbols = set(" \r\t\n,':{}[]><;")
koder aka kdanilovf4b82c22015-04-11 13:35:25 +03009
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030010 if isinstance(val, str):
11 val = val.encode('utf8')
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030012
koder aka kdanilov7248c7b2015-05-31 22:53:03 +030013 try:
14 float(val)
15 val = repr(val)
16 except ValueError:
17 if len(bad_symbols & set(val)) != 0:
18 val = repr(val)
19
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030020 return val
21 elif val is True:
22 return 'true'
23 elif val is False:
24 return 'false'
25 elif val is None:
26 return 'null'
27
28 return str(val)
29
30
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030031def is_simple(val: Any) -> bool:
32 simple_type = isinstance(val, (str, int, bool, float))
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030033 return simple_type or val is None
34
35
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030036def all_nums(vals: Iterable[Any]) -> bool:
37 return all(isinstance(val, (int, float)) for val in vals)
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030038
39
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030040def dumpv(data: Any, tab_sz: int=4, width: int=160, min_width: int=40) -> str:
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030041 tab = ' ' * tab_sz
42
43 if width < min_width:
44 width = min_width
45
46 res = []
47 if is_simple(data):
48 return [dumps_simple(data)]
49
50 if isinstance(data, (list, tuple)):
51 if all(map(is_simple, data)):
52 if all_nums(data):
koder aka kdanilova047e1b2015-04-21 23:16:59 +030053 one_line = "[{0}]".format(", ".join(map(dumps_simple, data)))
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030054 else:
koder aka kdanilova047e1b2015-04-21 23:16:59 +030055 one_line = "[{0}]".format(",".join(map(dumps_simple, data)))
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030056 elif len(data) == 0:
57 one_line = "[]"
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030058 else:
59 one_line = None
60
61 if one_line is None or len(one_line) > width:
62 pref = "-" + ' ' * (tab_sz - 1)
63
64 for val in data:
65 items = dumpv(val, tab_sz, width - tab_sz, min_width)
66 items = [pref + items[0]] + \
67 [tab + item for item in items[1:]]
68 res.extend(items)
69 else:
70 res.append(one_line)
71 elif isinstance(data, dict):
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030072 if len(data) == 0:
73 res.append("{}")
74 else:
75 assert all(map(is_simple, data.keys()))
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030076
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030077 one_line = None
78 if all(map(is_simple, data.values())):
79 one_line = ", ".join(
80 "{0}: {1}".format(dumps_simple(k), dumps_simple(v))
81 for k, v in sorted(data.items()))
82 one_line = "{" + one_line + "}"
83 if len(one_line) > width:
84 one_line = None
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030085
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030086 if one_line is None:
87 for k, v in data.items():
88 key_str = dumps_simple(k) + ": "
89 val_res = dumpv(v, tab_sz, width - tab_sz, min_width)
90
91 if len(val_res) == 1 and \
92 len(key_str + val_res[0]) < width and \
koder aka kdanilovbb6d6cd2015-06-20 02:55:07 +030093 not isinstance(v, dict) and \
94 not val_res[0].strip().startswith('-'):
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030095 res.append(key_str + val_res[0])
96 else:
97 res.append(key_str)
98 res.extend(tab + i for i in val_res)
koder aka kdanilovf4b82c22015-04-11 13:35:25 +030099 else:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300100 res.append(one_line)
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300101 else:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300102 try:
103 get_yamable = data.get_yamable
104 except AttributeError:
105 raise ValueError("Can't pack {0!r}".format(data))
106 res = dumpv(get_yamable(), tab_sz, width, min_width)
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300107
108 return res
109
110
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300111def dumps(data: Any, tab_sz: int=4, width: int=120, min_width: int=40) -> str:
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300112 return "\n".join(dumpv(data, tab_sz, width, min_width))