diff --git a/dictdiffer/utils.py b/dictdiffer/utils.py index 3194f9f..034eecd 100644 --- a/dictdiffer/utils.py +++ b/dictdiffer/utils.py @@ -201,9 +201,10 @@ def nested_hash(obj): if isinstance(obj, (list, tuple)): return hash(tuple(map(nested_hash, obj))) elif isinstance(obj, set): - return hash(tuple(map(nested_hash, sorted(obj)))) + return hash(frozenset(obj)) elif isinstance(obj, dict): - return hash(tuple(map(nested_hash, sorted(obj.items())))) + return hash(frozenset((key, nested_hash(value)) + for key, value in obj.items())) def dot_lookup(source, lookup, parent=False): diff --git a/tests/test_utils.py b/tests/test_utils.py index fd2cbd9..fc84e76 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -146,3 +146,14 @@ def test_nested_hash(self): nested_hash((1, 2, 3)) nested_hash(set([1, 2, 3])) nested_hash({'foo': 'bar'}) + + + def test_nested_hash_mixed_set(self): + first = {1, 'one', (2, 3)} + second = {(2, 3), 'one', 1} + self.assertEqual(nested_hash(first), nested_hash(second)) + + def test_nested_hash_mixed_dict_keys(self): + first = {1: ['one'], 'two': {3, 'three'}} + second = {'two': {'three', 3}, 1: ['one']} + self.assertEqual(nested_hash(first), nested_hash(second))