import sys
-def object_hook(obj):
+def strip_object_hook(obj):
if '__class__' in obj:
return None
for name in obj.keys():
def __init__(self, stream = sys.stdout):
self.stream = stream
- self.level = 0;
+ self.level = 0
def _write(self, s):
self.stream.write(s)
value = node[name]
self.enter_member(name)
self.visit(value)
- if i:
- self._write(',')
- self.leave_member()
+ self.leave_member(i == len(members) - 1)
self.leave_object()
def enter_object(self):
self._indent()
self._write('%s: ' % name)
- def leave_member(self):
+ def leave_member(self, last):
+ if not last:
+ self._write(',')
self._newline()
def leave_object(self):
self.level -= 1
self._indent()
self._write('}')
+ if self.level <= 0:
+ self._newline()
def visit_array(self, node):
self.enter_array()
value = node[i]
self._indent()
self.visit(value)
- if i:
+ if i != len(node) - 1:
self._write(',')
self._newline()
self.leave_array()
self._write(']')
def visit_value(self, node):
- self._write(repr(node))
+ self._write(json.dumps(node))
class Comparer(Visitor):
+ def __init__(self, ignore_added = False):
+ self.ignore_added = ignore_added
+
def visit_object(self, a, b):
if not isinstance(b, dict):
return False
- if len(a) != len(b):
+ if len(a) != len(b) and not self.ignore_added:
return False
ak = a.keys()
bk = b.keys()
ak.sort()
bk.sort()
- if ak != bk:
+ if ak != bk and not self.ignore_added:
return False
for k in ak:
- if not self.visit(a[k], b[k]):
+ ae = a[k]
+ try:
+ be = b[k]
+ except KeyError:
+ return False
+ if not self.visit(ae, be):
return False
return True
def visit_value(self, a, b):
return a == b
-comparer = Comparer()
class Differ(Visitor):
- def __init__(self, stream = sys.stdout):
+ def __init__(self, stream = sys.stdout, ignore_added = False):
self.dumper = Dumper(stream)
+ self.comparer = Comparer(ignore_added = ignore_added)
def visit(self, a, b):
- if comparer.visit(a, b):
+ if self.comparer.visit(a, b):
return
Visitor.visit(self, a, b)
else:
self.dumper.enter_object()
names = set(a.keys())
- names.update(b.keys())
+ if not self.comparer.ignore_added:
+ names.update(b.keys())
names = list(names)
names.sort()
- for name in names:
+ for i in range(len(names)):
+ name = names[i]
ae = a.get(name, None)
be = b.get(name, None)
- if not comparer.visit(ae, be):
+ if not self.comparer.visit(ae, be):
self.dumper.enter_member(name)
self.visit(ae, be)
- self.dumper.leave_member()
+ self.dumper.leave_member(i == len(names) - 1)
self.dumper.leave_object()
self.replace(a, b)
else:
self.dumper.enter_array()
- for i in range(max(len(a), len(b))):
+ max_len = max(len(a), len(b))
+ for i in range(max_len):
try:
ae = a[i]
except IndexError:
except IndexError:
be = None
self.dumper._indent()
- if comparer.visit(ae, be):
+ if self.comparer.visit(ae, be):
self.dumper.visit(ae)
else:
self.visit(ae, be)
+ if i != max_len - 1:
+ self.dumper._write(',')
self.dumper._newline()
self.dumper.leave_array()
self.dumper.visit(b)
-def load(stream):
+def load(stream, strip = True):
+ if strip:
+ object_hook = strip_object_hook
+ else:
+ object_hook = None
return json.load(stream, strict=False, object_hook = object_hook)
a = load(open(sys.argv[1], 'rt'))
b = load(open(sys.argv[2], 'rt'))
- #dumper = Dumper()
- #dumper.visit(a)
+ if False:
+ dumper = Dumper()
+ dumper.visit(a)
differ = Differ()
differ.visit(a, b)