Skip to content

Commit 7403046

Browse files
authored
Merge pull request #142 from seperman/dev
v4.0.5
2 parents b6afc83 + 2ec492d commit 7403046

File tree

15 files changed

+410
-146
lines changed

15 files changed

+410
-146
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# DeepDiff v 4.0.4
1+
# DeepDiff v 4.0.5
22

33
<!-- ![Downloads](https://img.shields.io/pypi/dm/deepdiff.svg?style=flat) -->
44
![Python Versions](https://img.shields.io/pypi/pyversions/deepdiff.svg?style=flat)

deepdiff/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""This module offers the DeepDiff, DeepSearch, grep and DeepHash classes."""
22
# flake8: noqa
3-
__version__ = '4.0.4'
3+
__version__ = '4.0.5'
44
import logging
55

66
if __name__ == '__main__':

deepdiff/base.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22
from deepdiff.helper import strings, numbers
33

44

5-
DEFAULT_SIGNIFICANT_DIGITS_WHEN_IGNORE_NUMERIC_TYPES = 55
5+
DEFAULT_SIGNIFICANT_DIGITS_WHEN_IGNORE_NUMERIC_TYPES = 12
66

77

88
class Base:
99
numbers = numbers
1010
strings = strings
1111

1212
def get_significant_digits(self, significant_digits, ignore_numeric_type_changes):
13-
if ignore_numeric_type_changes and not significant_digits:
14-
significant_digits = DEFAULT_SIGNIFICANT_DIGITS_WHEN_IGNORE_NUMERIC_TYPES
1513
if significant_digits is not None and significant_digits < 0:
1614
raise ValueError(
1715
"significant_digits must be None or a non-negative integer")
16+
if significant_digits is None:
17+
if ignore_numeric_type_changes:
18+
significant_digits = DEFAULT_SIGNIFICANT_DIGITS_WHEN_IGNORE_NUMERIC_TYPES
1819
return significant_digits
1920

2021
def get_ignore_types_in_groups(self, ignore_type_in_groups,

deepdiff/deephash.py

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33
import logging
4-
from collections import Iterable
5-
from collections import MutableMapping
4+
from collections.abc import Iterable, MutableMapping
65
from collections import defaultdict
7-
from decimal import Decimal
86
from hashlib import sha1, sha256
97

108
from deepdiff.helper import (strings, numbers, unprocessed, not_hashed, add_to_frozen_set,
119
convert_item_or_items_into_set_else_none, get_doc,
1210
convert_item_or_items_into_compiled_regexes_else_none,
13-
get_id, type_is_subclass_of_type_group, type_in_type_group)
11+
get_id, type_is_subclass_of_type_group, type_in_type_group,
12+
number_to_string, KEY_TO_VAL_STR)
1413
from deepdiff.base import Base
1514
logger = logging.getLogger(__name__)
1615

1716
try:
1817
import mmh3
19-
except ImportError:
20-
mmh3 = False
18+
except ImportError: # pragma: no cover
19+
mmh3 = False # pragma: no cover
2120

2221
UNPROCESSED = 'unprocessed'
2322
MURMUR_SEED = 1203
@@ -27,10 +26,6 @@
2726

2827
INDEX_VS_ATTRIBUTE = ('[%s]', '.%s')
2928

30-
KEY_TO_VAL_STR = "{}:{}"
31-
32-
ZERO_DECIMAL_CHARACTERS = set("-0.")
33-
3429

3530
def prepare_string_for_hashing(obj, ignore_string_type_changes=False, ignore_string_case=False):
3631
"""
@@ -62,20 +57,23 @@ def __init__(self,
6257
hasher=None,
6358
ignore_repetition=True,
6459
significant_digits=None,
60+
number_format_notation="f",
6561
apply_hash=True,
6662
ignore_type_in_groups=None,
6763
ignore_string_type_changes=False,
6864
ignore_numeric_type_changes=False,
6965
ignore_type_subclasses=False,
7066
ignore_string_case=False,
67+
number_to_string_func=None,
7168
**kwargs):
7269
if kwargs:
7370
raise ValueError(
7471
("The following parameter(s) are not valid: %s\n"
75-
"The valid parameters are obj, hashes, exclude_types,"
76-
"exclude_paths, exclude_regex_paths, hasher, ignore_repetition,"
77-
"significant_digits, apply_hash, ignore_type_in_groups, ignore_string_type_changes,"
78-
"ignore_numeric_type_changes, ignore_type_subclasses, ignore_string_case") % ', '.join(kwargs.keys()))
72+
"The valid parameters are obj, hashes, exclude_types, significant_digits, "
73+
"exclude_paths, exclude_regex_paths, hasher, ignore_repetition, "
74+
"number_format_notation, apply_hash, ignore_type_in_groups, ignore_string_type_changes, "
75+
"ignore_numeric_type_changes, ignore_type_subclasses, ignore_string_case "
76+
"number_to_string_func") % ', '.join(kwargs.keys()))
7977
self.obj = obj
8078
exclude_types = set() if exclude_types is None else set(exclude_types)
8179
self.exclude_types_tuple = tuple(exclude_types) # we need tuple for checking isinstance
@@ -89,6 +87,7 @@ def __init__(self,
8987
self[UNPROCESSED] = []
9088

9189
self.significant_digits = self.get_significant_digits(significant_digits, ignore_numeric_type_changes)
90+
self.number_format_notation = number_format_notation
9291
self.ignore_type_in_groups = self.get_ignore_types_in_groups(
9392
ignore_type_in_groups=ignore_type_in_groups,
9493
ignore_string_type_changes=ignore_string_type_changes,
@@ -102,6 +101,7 @@ def __init__(self,
102101
# testing the individual hash functions for different types of objects.
103102
self.apply_hash = apply_hash
104103
self.type_check_func = type_is_subclass_of_type_group if ignore_type_subclasses else type_in_type_group
104+
self.number_to_string = number_to_string_func or number_to_string
105105

106106
self._hash(obj, parent="root", parents_ids=frozenset({get_id(obj)}))
107107

@@ -143,7 +143,6 @@ def murmur3_128bit(obj):
143143
return mmh3.hash128(obj, MURMUR_SEED)
144144

145145
def __getitem__(self, obj):
146-
# changed_to_id = False
147146
key = obj
148147
result = None
149148

@@ -230,9 +229,6 @@ def _prep_dict(self, obj, parent, parents_ids=EMPTY_FROZENSET, print_as_attribut
230229
type_str = 'dict'
231230
return "%s:{%s}" % (type_str, result)
232231

233-
def _prep_set(self, obj, parent, parents_ids=EMPTY_FROZENSET):
234-
return "set:{}".format(self._prep_iterable(obj=obj, parent=parent, parents_ids=parents_ids))
235-
236232
def _prep_iterable(self, obj, parent, parents_ids=EMPTY_FROZENSET):
237233

238234
result = defaultdict(int)
@@ -264,17 +260,11 @@ def _prep_iterable(self, obj, parent, parents_ids=EMPTY_FROZENSET):
264260
return result
265261

266262
def _prep_number(self, obj):
267-
if self.significant_digits is not None and (
268-
self.ignore_numeric_type_changes or isinstance(obj, (float, complex, Decimal))):
269-
obj_s = ("{:.%sf}" % self.significant_digits).format(obj)
270-
271-
# Special case for 0: "-0.00" should compare equal to "0.00"
272-
if set(obj_s) <= ZERO_DECIMAL_CHARACTERS:
273-
obj_s = "0.00"
274-
result = "number:{}".format(obj_s)
275-
else:
276-
result = KEY_TO_VAL_STR.format(type(obj).__name__, obj)
277-
return result
263+
type_ = "number" if self.ignore_numeric_type_changes else obj.__class__.__name__
264+
if self.significant_digits is not None:
265+
obj = self.number_to_string(obj, significant_digits=self.significant_digits,
266+
number_format_notation=self.number_format_notation)
267+
return KEY_TO_VAL_STR.format(type_, obj)
278268

279269
def _prep_tuple(self, obj, parent, parents_ids):
280270
# Checking to see if it has _fields. Which probably means it is a named
@@ -321,9 +311,6 @@ def _hash(self, obj, parent, parents_ids=EMPTY_FROZENSET):
321311
elif isinstance(obj, tuple):
322312
result = self._prep_tuple(obj=obj, parent=parent, parents_ids=parents_ids)
323313

324-
elif isinstance(obj, (set, frozenset)):
325-
result = self._prep_set(obj=obj, parent=parent, parents_ids=parents_ids)
326-
327314
elif isinstance(obj, Iterable):
328315
result = self._prep_iterable(obj=obj, parent=parent, parents_ids=parents_ids)
329316

0 commit comments

Comments
 (0)