forked from Roman971/OoT-Randomizer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
JSONDump.py
122 lines (90 loc) · 3.21 KB
/
JSONDump.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
import json
from functools import reduce
INDENT = ' '
class CollapseList(list):
pass
class CollapseDict(dict):
pass
class AlignedDict(dict):
def __init__(self, src_dict, depth):
self.depth = depth - 1
super().__init__(src_dict)
class SortedDict(dict):
pass
def is_scalar(value):
return not is_list(value) and not is_dict(value)
def is_list(value):
return isinstance(value, list) or isinstance(value, tuple)
def is_dict(value):
return isinstance(value, dict)
def dump_scalar(obj, ensure_ascii=False):
return json.dumps(obj, ensure_ascii=ensure_ascii)
def dump_list(obj, current_indent='', ensure_ascii=False):
entries = [dump_obj(value, current_indent + INDENT, ensure_ascii=ensure_ascii) for value in obj]
if len(entries) == 0:
return '[]'
if isinstance(obj, CollapseList):
values_format = '{value}'
output_format = '[{values}]'
join_format = ', '
else:
values_format = '{indent}{value}'
output_format = '[\n{values}\n{indent}]'
join_format = ',\n'
output = output_format.format(
indent=current_indent,
values=join_format.join([values_format.format(
value=entry,
indent=current_indent + INDENT
) for entry in entries])
)
return output
def get_keys(obj, depth):
if depth == 0:
yield from obj.keys()
else:
for value in obj.values():
yield from get_keys(value, depth - 1)
def dump_dict(obj, current_indent='', sub_width=None, ensure_ascii=False):
entries = []
key_width = None
if sub_width is not None:
sub_width = (sub_width[0]-1, sub_width[1])
if sub_width[0] == 0:
key_width = sub_width[1]
if isinstance(obj, AlignedDict):
sub_keys = get_keys(obj, obj.depth)
sub_width = (obj.depth, reduce(lambda acc, entry: max(acc, len(entry)), sub_keys, 0))
for key, value in obj.items():
entries.append((dump_scalar(str(key), ensure_ascii), dump_obj(value, current_indent + INDENT, sub_width, ensure_ascii)))
if key_width is None:
key_width = reduce(lambda acc, entry: max(acc, len(entry[0])), entries, 0)
if len(entries) == 0:
return '{}'
if isinstance(obj, SortedDict):
entries.sort(key=lambda item: item[0])
if isinstance(obj, CollapseDict):
values_format = '{key} {value}'
output_format = '{{{values}}}'
join_format = ', '
else:
values_format = '{indent}{key:{padding}}{value}'
output_format = '{{\n{values}\n{indent}}}'
join_format = ',\n'
output = output_format.format(
indent=current_indent,
values=join_format.join([values_format.format(
key='{key}:'.format(key=key),
value=value,
indent=current_indent + INDENT,
padding=key_width + 2,
) for (key, value) in entries])
)
return output
def dump_obj(obj, current_indent='', sub_width=None, ensure_ascii=False):
if is_list(obj):
return dump_list(obj, current_indent, ensure_ascii)
elif is_dict(obj):
return dump_dict(obj, current_indent, sub_width, ensure_ascii)
else:
return dump_scalar(obj, ensure_ascii)