forked from beosro/pygrid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
prettyjson.py
100 lines (82 loc) · 3.68 KB
/
prettyjson.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
import types
def prettyjson(obj, indent=2, maxlinelength=80):
"""Renders JSON content with indentation and line splits/concatenations to fit maxlinelength.
Only dicts, lists and basic types are supported"""
items, _ = getsubitems(obj, itemkey="", islast=True, maxlinelength=maxlinelength)
res = indentitems(items, indent, indentcurrent=0)
return res
def getsubitems(obj, itemkey, islast, maxlinelength):
items = []
can_concat = True # assume we can concatenate inner content unless a child node returns an expanded list
isdict = isinstance(obj, dict)
islist = isinstance(obj, list)
istuple = isinstance(obj, tuple)
# building json content as a list of strings or child lists
if isdict or islist or istuple:
if isdict: opening, closing, keys = ("{", "}", iter(obj.keys()))
elif islist: opening, closing, keys = ("[", "]", range(0, len(obj)))
elif istuple: opening, closing, keys = ("[", "]", range(0, len(obj))) # tuples are converted into json arrays
if itemkey != "": opening = itemkey + ": " + opening
if not islast: closing += ","
# Get list of inner tokens as list
count = 0
subitems = []
itemkey = ""
for k in keys:
count += 1
islast_ = count == len(obj)
itemkey_ = ""
if isdict: itemkey_ = basictype2str(k)
inner, can_concat_ = getsubitems(obj[k], itemkey_, islast_, maxlinelength) # inner = (items, indent)
subitems.extend(inner) # inner can be a string or a list
can_concat = can_concat and can_concat_ # if a child couldn't concat, then we are not able either
# atttempt to concat subitems if all fit within maxlinelength
if (can_concat):
totallength = 0
for item in subitems:
totallength += len(item)
totallength += len(subitems)-1 # spaces between items
if (totallength <= maxlinelength):
str = ""
for item in subitems:
str += item + " " # add space between items, comma is already there
str = str.strip()
subitems = [ str ] # wrap concatenated content in a new list
else:
can_concat = False
# attempt to concat outer brackets + inner items
if (can_concat):
if (len(opening) + totallength + len(closing) <= maxlinelength):
items.append(opening + subitems[0] + closing)
else:
can_concat = False
if (not can_concat):
items.append(opening) # opening brackets
items.append(subitems) # Append children to parent list as a nested list
items.append(closing) # closing brackets
else:
# basic types
strobj = itemkey
if strobj != "": strobj += ": "
strobj += basictype2str(obj)
if not islast: strobj += ","
items.append(strobj)
return items, can_concat
def basictype2str(obj):
if isinstance (obj, str):
strobj = "\"" + str(obj) + "\""
elif isinstance(obj, bool):
strobj = { True: "true", False: "false" }[obj]
else:
strobj = str(obj)
return strobj
def indentitems(items, indent, indentcurrent):
"""Recursively traverses the list of json lines, adds indentation based on the current depth"""
res = ""
indentstr = " " * indentcurrent
for item in items:
if (isinstance(item, list)):
res += indentitems(item, indent, indentcurrent + indent)
else:
res += indentstr + item + "\n"
return res