Login

Comparing two json like python objects

Author:
nmb10
Posted:
October 31, 2010
Language:
Python
Version:
1.2
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. Template tag - list punctuation for a list of items by shapiromatron 11 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 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.