Skip to content

Commit

Permalink
Merge 37b1b6e into c3eab36
Browse files Browse the repository at this point in the history
  • Loading branch information
jirikuncar committed Aug 25, 2014
2 parents c3eab36 + 37b1b6e commit cc55a0a
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 6 deletions.
31 changes: 26 additions & 5 deletions dictdiffer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import sys
import copy

if sys.version_info[0] == 3: # pragma: no cover (Python 2/3 specific code)
string_types = str,
else: # pragma: no cover (Python 2/3 specific code)
string_types = basestring,

(ADD, REMOVE, CHANGE) = (
'add', 'remove', 'change')

Expand All @@ -14,7 +20,10 @@ def diff(first, second, node=None):
"""
node = node or []
dotted_node = '.'.join(node)
if all(map(lambda x: isinstance(x, string_types), node)):
dotted_node = '.'.join(node)
else:
dotted_node = list(node)

if isinstance(first, dict) and isinstance(second, dict):
# dictionaries are not hashable, we can't use sets
Expand All @@ -36,10 +45,14 @@ def diff_dict_list():
for key in intersection:
# if type is not changed, callees again diff function to compare.
# otherwise, the change will be handled as `change` flag.
node_key = str(key) if all(
[isinstance(key, int), isinstance(first[key], list),
isinstance(second[key], list)]
) else key
recurred = diff(
first[key],
second[key],
node=node + [str(key) if isinstance(key, int) else key])
node=node + [node_key])

for diffed in recurred:
yield diffed
Expand Down Expand Up @@ -86,7 +99,10 @@ def add(node, changes):

def change(node, changes):
dest = dot_lookup(destination, node, parent=True)
last_node = node.split('.')[-1]
if isinstance(node, string_types):
last_node = node.split('.')[-1]
else:
last_node = node[-1]
if isinstance(dest, list):
last_node = int(last_node)
_, value = changes
Expand Down Expand Up @@ -183,11 +199,16 @@ def dot_lookup(source, lookup, parent=False):
{'a': {'b': 'hello'}}
"""
if not lookup:
if lookup is None or lookup == '' or lookup == []:
return source

value = source
keys = lookup.split('.')
if isinstance(lookup, string_types):
keys = lookup.split('.')
elif isinstance(lookup, list):
keys = lookup
else:
raise TypeError('lookup must be string or list')

if parent:
keys = keys[:-1]
Expand Down
25 changes: 24 additions & 1 deletion tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest

from dictdiffer import diff, patch, revert, swap
from dictdiffer import diff, patch, revert, swap, dot_lookup


class DictDifferTests(unittest.TestCase):
Expand Down Expand Up @@ -129,6 +129,19 @@ def test_change_list(self):
assert second == patch(
[('change', 'a.b.c.0.d', ('e', 'f'))], first)

def test_dict_int_key(self):
first = {0: 0}
second = {0: 'a'}
first_patch = [('change', [0], (0, 'a'))]
assert second == patch(first_patch, first)

def test_dict_combined_key_type(self):
first = {0: {'1': {2: 3}}}
second = {0: {'1': {2: '3'}}}
first_patch = [('change', [0, '1', 2], (3, '3'))]
assert second == patch(first_patch, first)
assert first_patch[0] == list(diff(first, second))[0]


class SwapperTests(unittest.TestCase):
def test_addition(self):
Expand All @@ -155,5 +168,15 @@ def test_revert(self):
reverted = revert(diffed, second)
assert reverted == first


class DotLookupTest(unittest.TestCase):
def test_list_lookup(self):
source = {0: '0'}
assert dot_lookup(source, [0]) == '0'

def test_invalit_lookup_type(self):
self.assertRaises(TypeError, dot_lookup, {0: '0'}, 0)


if __name__ == "__main__":
unittest.main()

0 comments on commit cc55a0a

Please sign in to comment.