From 1ab58af29cac7f2c31f2cc096c0f8767681537ee Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Wed, 9 Nov 2016 12:22:00 +0100 Subject: [PATCH 1/7] Bugfix for the significant_digits option. Now signed zeros compare equal. i.e.: 0.00 compared equal to -0.00 and 1*10**-12 compares equal to -1*10**-12, if significant_digits is less than 12 --- deepdiff/diff.py | 6 +++++- tests/test_diff_ref.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/deepdiff/diff.py b/deepdiff/diff.py index d4dd6453..ffdffa8f 100644 --- a/deepdiff/diff.py +++ b/deepdiff/diff.py @@ -640,7 +640,11 @@ def __diff_numbers(self, level): # For Decimals, format seems to round 2.5 to 2 and 3.5 to 4 (to closest even number) t1_s = ("{:.%sf}" % self.significant_digits).format(level.t1) t2_s = ("{:.%sf}" % self.significant_digits).format(level.t2) - if t1_s != t2_s: + + # Special case for 0: "-0.00" should compare equal to "0.00" + if set(t1_s)<=set("-0.") and set(t2_s)<=set("-0."): + return + elif t1_s != t2_s: self.__report_result('values_changed', level) else: if level.t1 != level.t2: diff --git a/tests/test_diff_ref.py b/tests/test_diff_ref.py index b260ce49..2ff9e186 100644 --- a/tests/test_diff_ref.py +++ b/tests/test_diff_ref.py @@ -36,6 +36,19 @@ def test_same_objects(self): res = ddiff.tree self.assertEqual(res, {}) + def test_significant_digits_signed_zero(self): + t1 = 0.00001 + t2 = -0.0001 + ddiff = DeepDiff(t1, t2, significant_digits = 2) + res = ddiff.tree + self.assertEqual(res, {}) + t1 = 1*10**-12 + t2 = -1*10**-12 + ddiff = DeepDiff(t1, t2, significant_digits=10) + res = ddiff.tree + self.assertEqual(res, {}) + + def test_item_added_extensive(self): t1 = {'one': 1, 'two': 2, 'three': 3, 'four': 4} t2 = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'new': 1337} From 519675c0aa2ae4cab573d4a6f7a8bf42ccc87ded Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Wed, 9 Nov 2016 12:13:56 +0100 Subject: [PATCH 2/7] `auto_generate_child_rel` compares `self.down.t1` to None instead of calling `if self.down.t1:` This is necessary thanks to numpy breaking convention and rising an error during conversion of an array to a bool. --- deepdiff/model.py | 5 +++-- tests/test_diff_ref.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/deepdiff/model.py b/deepdiff/model.py index 3c1cf1eb..15a0d701 100644 --- a/deepdiff/model.py +++ b/deepdiff/model.py @@ -305,13 +305,14 @@ def auto_generate_child_rel(self, klass, param): :param param: A ChildRelationship subclass-dependent parameter describing how to get from parent to child, e.g. the key in a dict """ - if self.down.t1: + if self.down.t1 is not None: self.t1_child_rel = ChildRelationship.create(klass=klass, parent=self.t1, child=self.down.t1, param=param) - if self.down.t2: + if self.down.t2 is not None: self.t2_child_rel = ChildRelationship.create(klass=klass, parent=self.t2, child=self.down.t2, param=param) + @property def all_up(self): """ diff --git a/tests/test_diff_ref.py b/tests/test_diff_ref.py index 2ff9e186..9cab6314 100644 --- a/tests/test_diff_ref.py +++ b/tests/test_diff_ref.py @@ -121,6 +121,7 @@ def test_non_subscriptable_iterable(self): self.assertIsInstance(change.up.t1_child_rel, NonSubscriptableIterableRelationship) self.assertIsNone(change.up.t2_child_rel) + def test_non_subscriptable_iterable_path(self): t1 = (i for i in [42, 1337, 31337]) t2 = (i for i in [42, 1337, ]) @@ -131,3 +132,26 @@ def test_non_subscriptable_iterable_path(self): self.assertEqual(change.path(), None) self.assertEqual(change.path(force='yes'), 'root(unrepresentable)') self.assertEqual(change.path(force='fake'), 'root[2]') + +class DeepDiffRefWithNumpyTestCase(unittest.TestCase): + + """DeepDiff Tests.""" + def setUp(self): + import numpy as np + a1 = np.array([1.23, 1.66, 1.98]) + a2 = np.array([1.23, 1.66, 1.98]) + self.d1 = { 'np': a1 } + self.d2 = { 'np': a2 } + + def test_diff_with_numpy(self): + ddiff = DeepDiff(self.d1, self.d2) + res = ddiff.tree + self.assertEqual(res, {}) + + def test_diff_with_empty_seq(self): + a1 = {"empty":[]} + a2 = {"empty":[]} + ddiff = DeepDiff(a1, a2) + res = ddiff.tree + self.assertEqual(ddiff, {}) + From 4301ff2ef6fa5fedcca9d25558d06325a96443d2 Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Wed, 9 Nov 2016 11:32:44 +0100 Subject: [PATCH 3/7] Added 2 failing tests for the combination of significant_digits with sets. Sets use hasing for the diff, thus `__diff_numbers` is currently not invoked, which is why the tests currently fail. --- tests/test_diff_ref.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_diff_ref.py b/tests/test_diff_ref.py index 9cab6314..7f8a2d99 100644 --- a/tests/test_diff_ref.py +++ b/tests/test_diff_ref.py @@ -133,6 +133,18 @@ def test_non_subscriptable_iterable_path(self): self.assertEqual(change.path(force='yes'), 'root(unrepresentable)') self.assertEqual(change.path(force='fake'), 'root[2]') + def test_significant_digits(self): + ddiff = DeepDiff([0.012, 0.98], [0.013, 0.99], significant_digits = 1) + self.assertEqual(ddiff, {}) + + def test_significant_digits_with_sets(self): + ddiff = DeepDiff(set([0.012, 0.98]), set([0.013, 0.99]), significant_digits = 1) + self.assertEqual(ddiff, {}) + + def test_significant_digits_with_ignore_order(self): + ddiff = DeepDiff([0.012, 0.98], [0.013, 0.99], significant_digits = 1, ignore_order=True) + self.assertEqual(ddiff, {}) + class DeepDiffRefWithNumpyTestCase(unittest.TestCase): """DeepDiff Tests.""" From 2763629879b9a310df06693dd8e03f539c8f2113 Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Wed, 9 Nov 2016 12:31:34 +0100 Subject: [PATCH 4/7] `__diff_dict` now is used for Mapping instances, not only for MutableMappings. (Adresses issue #49) --- deepdiff/diff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepdiff/diff.py b/deepdiff/diff.py index ffdffa8f..cb9e2ed1 100644 --- a/deepdiff/diff.py +++ b/deepdiff/diff.py @@ -15,7 +15,7 @@ from decimal import Decimal -from collections import MutableMapping +from collections import Mapping from collections import Iterable from deepdiff.helper import py3, strings, numbers, ListItemRemovedOrAdded, IndexedHash, Verbose @@ -672,7 +672,7 @@ def __diff(self, level, parents_ids=frozenset({})): elif isinstance(level.t1, numbers): self.__diff_numbers(level) - elif isinstance(level.t1, MutableMapping): + elif isinstance(level.t1, Mapping): self.__diff_dict(level, parents_ids) elif isinstance(level.t1, tuple): From 541886872dd9a0510bb3c995703e1e9f62f0236e Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Thu, 24 Nov 2016 12:53:53 +0100 Subject: [PATCH 5/7] Marked failing tests with expectedFailure --- tests/test_diff_ref.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_diff_ref.py b/tests/test_diff_ref.py index 7f8a2d99..ad2a4c71 100644 --- a/tests/test_diff_ref.py +++ b/tests/test_diff_ref.py @@ -136,11 +136,13 @@ def test_non_subscriptable_iterable_path(self): def test_significant_digits(self): ddiff = DeepDiff([0.012, 0.98], [0.013, 0.99], significant_digits = 1) self.assertEqual(ddiff, {}) - + + @unittest.expectedFailure def test_significant_digits_with_sets(self): ddiff = DeepDiff(set([0.012, 0.98]), set([0.013, 0.99]), significant_digits = 1) self.assertEqual(ddiff, {}) - + + @unittest.expectedFailure def test_significant_digits_with_ignore_order(self): ddiff = DeepDiff([0.012, 0.98], [0.013, 0.99], significant_digits = 1, ignore_order=True) self.assertEqual(ddiff, {}) From 4c8562625866053aa5cdb2d54444013a30bdc5a5 Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Thu, 24 Nov 2016 13:11:59 +0100 Subject: [PATCH 6/7] Tests with numpy are now skipped on PyPy PyPy uses its own fork of numpy, but its numpy support is not yet complete. --- tests/test_diff_ref.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_diff_ref.py b/tests/test_diff_ref.py index ad2a4c71..263c0406 100644 --- a/tests/test_diff_ref.py +++ b/tests/test_diff_ref.py @@ -18,6 +18,7 @@ python -m unittest tests.test_diff_ref.DeepDiffRefTestCase.test_same_objects """ import unittest +import platform from deepdiff import DeepDiff from deepdiff.model import DictRelationship, NonSubscriptableIterableRelationship @@ -147,6 +148,7 @@ def test_significant_digits_with_ignore_order(self): ddiff = DeepDiff([0.012, 0.98], [0.013, 0.99], significant_digits = 1, ignore_order=True) self.assertEqual(ddiff, {}) +@unittest.skipIf(platform.python_implementation() == "PyPy", "Numpy is not the same under PyPy") class DeepDiffRefWithNumpyTestCase(unittest.TestCase): """DeepDiff Tests.""" From f5fec5e2ea860a71bb4dfe6c16a08870a7911d8e Mon Sep 17 00:00:00 2001 From: Bernhard Thiel Date: Thu, 24 Nov 2016 13:25:02 +0100 Subject: [PATCH 7/7] Revert "Tests with numpy are now skipped on PyPy" This reverts commit 4c8562625866053aa5cdb2d54444013a30bdc5a5. --- tests/test_diff_ref.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_diff_ref.py b/tests/test_diff_ref.py index 263c0406..ad2a4c71 100644 --- a/tests/test_diff_ref.py +++ b/tests/test_diff_ref.py @@ -18,7 +18,6 @@ python -m unittest tests.test_diff_ref.DeepDiffRefTestCase.test_same_objects """ import unittest -import platform from deepdiff import DeepDiff from deepdiff.model import DictRelationship, NonSubscriptableIterableRelationship @@ -148,7 +147,6 @@ def test_significant_digits_with_ignore_order(self): ddiff = DeepDiff([0.012, 0.98], [0.013, 0.99], significant_digits = 1, ignore_order=True) self.assertEqual(ddiff, {}) -@unittest.skipIf(platform.python_implementation() == "PyPy", "Numpy is not the same under PyPy") class DeepDiffRefWithNumpyTestCase(unittest.TestCase): """DeepDiff Tests."""