-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathjson_equality_check.py
executable file
·116 lines (95 loc) · 3.2 KB
/
json_equality_check.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
#!/usr/bin/python3
"""
This script checks that one or more JSON files are formatted correctly
according to the following structural requirements:
* The root node should be a dictionary.
* Children should be dictionaries containing only boolean values.
* Successive files should contain the same keys.
In case several files are specified, the files are processed sequentially, and
the former file is used as a basis for checking the structure of the next file.
In case the structure is different, an error message is printed accordingly.
Any error will result in a non-zero exit code.
Example of valid JSON:
{
"foo": {
"abc": true,
"def": false
},
"bar": {},
"baz": {
"ghi": false
}
}
"""
import argparse
import json
import sys
class ValidationException(Exception):
pass
class StructuralIntegrityException(Exception):
pass
def hash_only_type(h, t):
"""
Assert that `h` is a dictionary containing values only of type `t`.
"""
assert type(h) == dict
for k, v in h.items():
if type(v) != t:
raise ValidationException("key '%s' should be type '%s', got '%s' instead" % (k, t.__name__, type(v).__name__))
def check_types(tree):
"""
Assert that `tree` is a dictionary, and that it contains only dictionaries with boolean values.
"""
hash_only_type(tree, dict)
try:
for k, h in tree.items():
hash_only_type(h, bool)
except ValidationException as e:
raise ValidationException("in root node '%s': %s" % (k, str(e)))
def dict_from_json_file(filename):
"""
Read a JSON structure from a file and return it as a dictionary object.
"""
with open(filename, 'r') as f:
jsobject = f.read()
return json.loads(jsobject)
def compare_structure(a, b):
"""
Check that two JSON trees have the same key structure.
"""
if type(a) != type(b):
raise StructuralIntegrityException('types differ')
if type(a) == dict:
if len(a) != len(b):
raise StructuralIntegrityException('number of elements differ')
for k in a.keys():
if k not in b:
raise StructuralIntegrityException("key '%s' is missing" % k)
try:
compare_structure(a[k], b[k])
except StructuralIntegrityException as e:
raise StructuralIntegrityException("in '%s': %s" % (k, str(e)))
def main():
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
p.add_argument('file', nargs='+')
args = p.parse_args()
prev = None
errors = 0
for f in args.file:
try:
tree = dict_from_json_file(f)
check_types(tree)
if prev is not None:
compare_structure(prev, tree)
prev = tree
except StructuralIntegrityException as e:
print('%s: structure not equal to previous file: %s' % (f, str(e)))
errors += 1
except Exception as e:
print('%s: error: %s' % (f, str(e)))
errors += 1
else:
print('%s: ok' % f)
return errors
if __name__ == '__main__':
sys.exit(main())