Skip to content

Commit

Permalink
Merge cf37e3d into e637f35
Browse files Browse the repository at this point in the history
  • Loading branch information
jirikuncar committed Jun 20, 2016
2 parents e637f35 + cf37e3d commit 43872ca
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 19 deletions.
48 changes: 30 additions & 18 deletions dictdiffer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,35 @@

"""Dictdiffer is a helper module to diff and patch dictionaries."""

import sys
import copy
import sys

from .utils import are_different, EPSILON, dot_lookup, PathLimit
from .version import __version__
from ._compat import MutableMapping, MutableSet, MutableSequence, \
string_types, text_type, PY2
import pkg_resources

from ._compat import (PY2, MutableMapping, MutableSequence, MutableSet,
string_types, text_type)
from .utils import EPSILON, PathLimit, are_different, dot_lookup
from .version import __version__

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

__all__ = ('diff', 'patch', 'swap', 'revert', 'dot_lookup', '__version__')

DICT_TYPE = MutableMapping
LIST_TYPE = MutableSequence
SET_TYPE = MutableSet
DICT_TYPES = (MutableMapping, )
LIST_TYPES = (MutableSequence, )
SET_TYPES = (MutableSet, )

try:
pkg_resources.get_distribution('numpy')
except pkg_resources.DistributionNotFound: # pragma: no cover
HAS_NUMPY = False
else:
HAS_NUMPY = True

import numpy

LIST_TYPES += (numpy.ndarray, )


def diff(first, second, node=None, ignore=None, path_limit=None, expand=False,
Expand Down Expand Up @@ -96,7 +108,7 @@ def diff(first, second, node=None, ignore=None, path_limit=None, expand=False,

differ = False

if isinstance(first, DICT_TYPE) and isinstance(second, DICT_TYPE):
if isinstance(first, DICT_TYPES) and isinstance(second, DICT_TYPES):
# dictionaries are not hashable, we can't use sets
def check(key):
"""Test if key in current node should be ignored."""
Expand All @@ -105,7 +117,7 @@ def check(key):
else:
new_key = key
return ignore is None \
or (node + [key] if isinstance(dotted_node, LIST_TYPE)
or (node + [key] if isinstance(dotted_node, LIST_TYPES)
else '.'.join(node + [str(new_key)])) not in ignore

intersection = [k for k in first if k in second and check(k)]
Expand All @@ -114,7 +126,7 @@ def check(key):

differ = True

elif isinstance(first, LIST_TYPE) and isinstance(second, LIST_TYPE):
elif isinstance(first, LIST_TYPES) and isinstance(second, LIST_TYPES):
len_first = len(first)
len_second = len(second)

Expand All @@ -124,7 +136,7 @@ def check(key):

differ = True

elif isinstance(first, SET_TYPE) and isinstance(second, SET_TYPE):
elif isinstance(first, SET_TYPES) and isinstance(second, SET_TYPES):

intersection = {}
addition = second - first
Expand Down Expand Up @@ -161,8 +173,8 @@ def check(key):
collect = []
collect_recurred = []
for key in addition:
if not isinstance(second[key], (
SET_TYPE, LIST_TYPE, DICT_TYPE)):
if not isinstance(second[key],
SET_TYPES + LIST_TYPES + DICT_TYPES):
collect.append((key, second[key]))
elif path_limit.path_is_limit(node+[key]):
collect.append((key, second[key]))
Expand Down Expand Up @@ -220,9 +232,9 @@ def patch(diff_result, destination):
def add(node, changes):
for key, value in changes:
dest = dot_lookup(destination, node)
if isinstance(dest, LIST_TYPE):
if isinstance(dest, LIST_TYPES):
dest.insert(key, value)
elif isinstance(dest, SET_TYPE):
elif isinstance(dest, SET_TYPES):
dest |= value
else:
dest[key] = value
Expand All @@ -233,15 +245,15 @@ def change(node, changes):
last_node = node.split('.')[-1]
else:
last_node = node[-1]
if isinstance(dest, LIST_TYPE):
if isinstance(dest, LIST_TYPES):
last_node = int(last_node)
_, value = changes
dest[last_node] = value

def remove(node, changes):
for key, value in changes:
dest = dot_lookup(destination, node)
if isinstance(dest, SET_TYPE):
if isinstance(dest, SET_TYPES):
dest -= value
else:
del dest[key]
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
'Sphinx>=1.3',
'sphinx-rtd-theme>=0.1.9',
],
'numpy': [
'numpy>=1.11.0',
],
'tests': tests_require,
}

Expand Down
11 changes: 10 additions & 1 deletion tests/test_dictdiffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import unittest

from dictdiffer import diff, dot_lookup, patch, revert, swap
from dictdiffer import HAS_NUMPY, diff, dot_lookup, patch, revert, swap
from dictdiffer._compat import MutableMapping, MutableSequence, MutableSet
from dictdiffer.utils import PathLimit

Expand Down Expand Up @@ -336,6 +336,15 @@ def test_list_same(self):
first = {1: [1]}
assert len(list(diff(first, first))) == 0

@unittest.skipIf(not HAS_NUMPY, 'NumPy is not installed')
def test_numpy_array(self):
"""Compare NumPy arrays (#68)."""
import numpy as np
first = np.array([1, 2, 3])
second = np.array([1, 2, 4])
result = list(diff(first, second))
assert result == [('change', [2], (3, 4))]

def test_dict_subclasses(self):
class Foo(dict):
pass
Expand Down

0 comments on commit 43872ca

Please sign in to comment.