-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjson_formatting.py
executable file
·105 lines (84 loc) · 2.82 KB
/
json_formatting.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
"""Json formatter.
- No line breaks only when the list is composed of numbers.
- Line has no more than one value(Number, String, list).
- Line has no more than one key.
References:
https://gist.github.com/lwthatcher/cd3f7a0a452147fbaae48730354e9993
:author: ok97465
:Date created: 21.10.29 11:50:31
"""
# %% Import
# Standard library imports
import json
import re
# Third party imports
import _ctypes
class NoIndent(object):
"""."""
def __init__(self, value):
"""."""
self.value = value
def __repr__(self):
"""."""
if not isinstance(self.value, list):
return repr(self.value)
else: # Sort the representation of any dicts in the list.
reps = (
"{{{}}}".format(
", ".join(("{!r}:{}".format(k, v) for k, v in sorted(v.items())))
)
if isinstance(v, dict)
else repr(v)
for v in self.value
)
return "[" + ", ".join(reps) + "]"
def di(obj_id):
"""Reverse of id() function."""
# from https://stackoverflow.com/a/15012814/355230
return _ctypes.PyObj_FromPtr(obj_id)
def check_objs(obj):
"""."""
# base case
if isinstance(obj, list):
for val in obj:
if not(isinstance(val, int) or isinstance(val, float)):
break
else:
# No line breaks only when the list is composed of numbers.
return NoIndent(obj)
if isinstance(obj, dict):
for k, v in obj.items():
obj[k] = check_objs(v)
elif isinstance(obj, list):
for i, l in enumerate(obj):
obj[i] = check_objs(l)
# return changed object
return obj
class PrettyJsonEncoder(json.JSONEncoder):
"""."""
FORMAT_SPEC = "@@{}@@"
regex = re.compile(FORMAT_SPEC.format(r"(\d+)"))
def default(self, obj):
"""."""
return (
self.FORMAT_SPEC.format(id(obj))
if isinstance(obj, NoIndent)
else super().default(obj)
)
def encode(self, obj):
"""."""
# recursively check if should convert to NoIndent object
obj = check_objs(obj)
# start formatting
format_spec = self.FORMAT_SPEC # Local var to expedite access.
json_repr = super().encode(obj) # Default JSON repr.
# Replace any marked-up object ids in the JSON repr with the value
# returned from the repr() of the corresponding Python object.
for match in self.regex.finditer(json_repr):
id = int(match.group(1))
# Replace marked-up id with actual Python object repr().
json_repr = json_repr.replace(
'"{}"'.format(format_spec.format(id)), repr(di(id))
)
json_repr = json_repr.replace("'", '"')
return json_repr