Login

Comparing two json like python objects

Author:
nmb10
Posted:
October 31, 2010
Language:
Python
Version:
1.2
Tags:
django json piston compare
Score:
-1 (after 1 ratings)

Shows difference between two json like python objects. May help to test json response, piston API powered sites... Shows properties, values from first object that are not in the second.

Example:

import simplejson # or other json serializer

first = simplejson.loads('{"first_name": "Poligraph", "last_name": "Sharikov",}')

second = simplejson.loads('{"first_name": "Poligraphovich", "pet_name": "Sharik"}')

df = Diff(first, second)

df.difference is ["path: last_name"]

Diff(first, second, vice_versa=True) gives you difference from both objects in the one result.

df.difference is ["path: last_name", "path: pet_name"]

Diff(first, second, with_values=True) gives you difference of the values strings.

 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
class Diff(object):
    def __init__(self, first, second, with_values=False, vice_versa=False):
        self.difference = []
        self.check(first, second, with_values=with_values)

        if vice_versa:
            self.check(second, first, with_values=with_values)
        
    def check(self, first, second, path='', with_values=False):
        if second != None:
            if not isinstance(first, type(second)):
                message = '%s- %s, %s' % (path, type(first), type(second))
                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
                    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, %s' % (new_path, type(first), type(second)), 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_):
        message = '%s: %s' % (type_, diff_message)
        if diff_message not in self.difference:
            self.difference.append(message)

More like this

  1. format output as table by bendavis78 6 years ago
  2. Debug middleware for displaying sql queries and template loading info when ?debug=true by SEJeff 4 years, 3 months ago
  3. Validator for data by limodou 8 years, 5 months ago
  4. update_or_create by abhin4v 6 years, 10 months ago
  5. really_equals by zeeg 8 years, 2 months ago

Comments

buriy (on November 1, 2010):

For dicts, you might try to use set(dict1.iteritems()) - set(dict2.iteritems()) which will compute the difference for you. fast and efficient. For lists, you might use set(enumerate(list1)) - set(enumerate(list2)). Now generalize the mapper and use set(mapper(json1)) - set(mapper(json2)). No need for 66 lines, which are completely unrelated to Django.

#

nmb10 (on November 1, 2010):

I think it's good, but not for all cases.

  • We need to check keys only (does the both have "f" key):

`fir = {"f": "foo"}

sec = {"f": "bar"}`

Your method gives us '[('f', 'foo')]' difference, but the both has the same keys.

  • Consider types mismatch.

`fir = {"f": "foo"}

sec = {"f": [1]}`

Your method does not give you proper difference.

  • More deeply objects.

`fir = {"f": {"f": "fir"}}

sec = {"f": {"b": "bar"}}`

#

Please login first before commenting.