-
Notifications
You must be signed in to change notification settings - Fork 364
/
test_json_compat.py
172 lines (139 loc) · 5.08 KB
/
test_json_compat.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
r"""
Compare cases
python -c "import json as json; print(repr(json.dumps({None: None})))"
python -c "import ujson as json; print(repr(json.dumps({None: None})))"
python -c "import json ; print(repr(json.dumps([1], indent='\x000')))"
python -c "import ujson as json; print(repr(json.dumps([1], indent='\x000')))"
python -c "import json ; print(repr(json.dumps([1, 2], indent='a \x000 b')))"
python -c "import ujson as json; print(repr(json.dumps([1, 2], indent='a \x000 b')))"
python -c "import json ; print(repr(json.dumps([1], indent='\udfff')))"
python -c "import json as json; print(repr(json.dumps([1, 2, 3], indent='\udfff')))"
python -c "import ujson as json; print(repr(json.dumps([1, 2, 3], indent='\udfff')))"
python -c "import ujson as json; print(repr(json.dumps([1, 2, 3], indent='\udfff')))"
python -c "import ujson as json; print(repr(json.encode(json.decode('{\n \"obj\": 31337\n}'), indent=4)))"
python -c "import ujson as json; print(repr(json.encode([1, 2, 3], indent=4)))"
"""
import ujson
import json as pjson
import itertools as it
from collections import defaultdict
JSON_IMPLS = {
'ujson': ujson,
'pjson': pjson,
}
def group_items(items, key):
"""
Groups a list of items by group id. (from ubelt)
"""
pair_list = ((key(item), item) for item in items)
# Initialize a dict of lists
id_to_items = defaultdict(list)
# Insert each item into the correct group
for groupid, item in pair_list:
id_to_items[groupid].append(item)
return id_to_items
def named_product(basis):
# Implementation from ubelt
keys = list(basis.keys())
for vals in it.product(*basis.values()):
kw = dict(zip(keys, vals))
yield kw
def test_dumps_compatability():
"""
Test the difference between Python's json module (pjson) and ultrajson
(ujson) under a grid of different parameters.
"""
# Define the data we will test
# data = {'a': [1, 2, 3, named_product]}
data = {'a': [1, 2, 3]}
# Define the parameters we will test
NULL_CHAR = '\x00'
UTF_SURROGATE0000 = '\udc80'
UTF_SURROGATE1024 = '\udfff'
param_basis = {
'indent': [
-1,
-2,
' ',
' ab ',
4, 0,
None,
'\t',
NULL_CHAR,
UTF_SURROGATE0000,
UTF_SURROGATE1024,
],
# 'ensure_ascii': [False],
'ensure_ascii': [True, False, None],
'sort_keys': [True, False, None],
'default': [None, str],
'module': list(JSON_IMPLS.keys()),
}
kwargs_keys = ['indent', 'default', 'ensure_ascii', 'sort_keys']
kwargs_keys = [k for k in kwargs_keys if k in param_basis]
param_grid = named_product(param_basis)
results = []
for params in param_grid:
params_key = pjson.dumps(params, default=str)
module = JSON_IMPLS[params['module']]
kwargs = {k: params[k] for k in kwargs_keys if k in params}
try:
result = module.dumps(data, **kwargs)
except Exception as ex:
error = ex
result = None
else:
error = 0
row = {
'params_key': params_key,
**params,
'data': data,
'result': result,
'error': error,
}
results.append(row)
print(pjson.dumps(results, indent=' ', default=repr))
def grouper(row):
return tuple([(k, row[k]) for k in kwargs_keys])
grouped_results = group_items(results, key=grouper)
agree_keys = []
diagree_keys = []
for group_key, group in grouped_results.items():
assert len(group) == 2
module_to_row = {r['module']: r for r in group}
assert len(module_to_row) == 2
ujson_row = module_to_row['ujson']
pjson_row = module_to_row['pjson']
if ujson_row['error'] and pjson_row['error']:
# Both implementations errored
agree_keys.append(group_key)
else:
# Check if the results from all implementations are the same
agree_keys.append(group_key)
u_result = ujson_row['result']
p_result = pjson_row['result']
try:
p_val = pjson.loads(p_result)
except Exception as ex:
p_val = repr(ex)
try:
u_val = pjson.loads(u_result)
except Exception as ex:
u_val = repr(ex)
if p_val != u_val:
import difflib
print(f'Disagree on {group_key}')
print(' * p_result = {!r}'.format(p_result))
print(' * u_result = {!r}'.format(u_result))
print(''.join(list(difflib.ndiff([str(p_val)], [str(u_val)]))))
diagree_keys.append(group_key)
else:
agree_keys.append(group_key)
print('Num Agree: {}'.format(len(agree_keys)))
print('Num Disagree: {}'.format(len(diagree_keys)))
if __name__ == '__main__':
"""
CommandLine:
python ~/code/ultrajson/tests/test_json_compat.py
"""
test_dumps_compatability()