-
Notifications
You must be signed in to change notification settings - Fork 27
/
jsoncompare.py
123 lines (107 loc) · 3.78 KB
/
jsoncompare.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
import httplib2
import json
import sys
import types
TYPE = 'TYPE'
PATH = 'PATH'
VALUE = 'VALUE'
# Borrowed from http://djangosnippets.org/snippets/2247/
# with some modifications.
class Diff(object):
def __init__(self, first, second, with_values=False):
self.difference = []
self.seen = []
not_with_values = not with_values
self.check(first, second, with_values=with_values)
def check(self, first, second, path='', with_values=False):
if with_values and second != None:
if not isinstance(first, type(second)):
message = '%s - %s, %s' % (path, type(first).__name__, type(second).__name__)
self.save_diff(message, TYPE)
if isinstance(first, dict):
for key in first:
# the first part of path must not have trailing dot.
if len(path) == 0:
new_path = key
else:
new_path = "%s.%s" % (path, key)
if isinstance(second, dict):
if second.has_key(key):
sec = second[key]
else:
# there are key in the first, that is not presented in the second
self.save_diff(new_path, PATH)
# prevent further values checking.
sec = None
# recursive call
if sec != None:
self.check(first[key], sec, path=new_path, with_values=with_values)
else:
# second is not dict. every key from first goes to the difference
self.save_diff(new_path, PATH)
self.check(first[key], second, path=new_path, with_values=with_values)
# if object is list, loop over it and check.
elif isinstance(first, list):
for (index, item) in enumerate(first):
new_path = "%s[%s]" % (path, index)
# try to get the same index from second
sec = None
if second != None:
try:
sec = second[index]
except (IndexError, KeyError):
# goes to difference
self.save_diff('%s - %s' % (new_path, type(item).__name__), TYPE)
# recursive call
self.check(first[index], sec, path=new_path, with_values=with_values)
# not list, not dict. check for equality (only if with_values is True) and return.
else:
if with_values and second != None:
if first != second:
self.save_diff('%s - %s | %s' % (path, first, second), VALUE)
return
def save_diff(self, diff_message, type_):
if diff_message not in self.difference:
self.seen.append(diff_message)
self.difference.append((type_, diff_message))
def getContentFromUri(uri):
h = httplib2.Http()
resp, content = h.request(uri, "GET")
return content
def getContentFromFile(filePath):
return open(filePath, 'r').read()
def getContent(location):
content = None
if type(location) is types.DictType:
return location
if location.startswith("http"):
content = getContentFromUri(location)
else:
content = getContentFromFile(location)
if content is None:
raise Error("Could not load content for " + location)
return json.loads(content)
def compare(location1, location2):
json1 = getContent(location1)
json2 = getContent(location2)
diff1 = Diff(json1, json2, True).difference
diff2 = Diff(json2, json1, False).difference
diffs = []
for type, message in diff1:
newType = 'CHANGED'
if type == PATH:
newType = 'REMOVED'
diffs.append({'type': newType, 'message': message})
for type, message in diff2:
diffs.append({'type': 'ADDED', 'message': message})
return diffs
if __name__ == '__main__':
if len(sys.argv) != 3:
sys.exit('Error')
location1 = sys.argv[1]
location2 = sys.argv[2]
diffs = compare(location1, location2)
if len(diffs) > 0:
print '\r\nFound differences comparing ' + location1 + ' and ' + location2
for diff in diffs:
print diff['type'] + ': ' + diff['message']