Skip to content

Commit cfab1ea

Browse files
author
Enric Pou
committed
Bugfix: ValueError when using Decimal 0.x
1 parent a55ed44 commit cfab1ea

File tree

3 files changed

+84
-14
lines changed

3 files changed

+84
-14
lines changed

deepdiff/helper.py

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ class np_type:
6868
np_float32, np_float64, np_float_, np_complex64,
6969
np_complex128, np_complex_,)
7070

71+
numpy_complex_numbers = (
72+
np_complex64, np_complex128, np_complex_,
73+
)
74+
7175
numpy_dtypes = set(numpy_numbers)
7276
numpy_dtypes.add(np_bool_)
7377

@@ -102,6 +106,7 @@ class np_type:
102106
strings = (str, bytes) # which are both basestring
103107
unicode_type = str
104108
bytes_type = bytes
109+
only_complex_number = (complex,) + numpy_complex_numbers
105110
only_numbers = (int, float, complex, Decimal) + numpy_numbers
106111
datetimes = (datetime.datetime, datetime.date, datetime.timedelta, datetime.time)
107112
uuids = (uuid.UUID)
@@ -115,8 +120,6 @@ class np_type:
115120

116121
ID_PREFIX = '!>*id'
117122

118-
ZERO_DECIMAL_CHARACTERS = set("-0.")
119-
120123
KEY_TO_VAL_STR = "{}:{}"
121124

122125
TREE_VIEW = 'tree'
@@ -323,20 +326,51 @@ def number_to_string(number, significant_digits, number_format_notation="f"):
323326
using = number_formatting[number_format_notation]
324327
except KeyError:
325328
raise ValueError("number_format_notation got invalid value of {}. The valid values are 'f' and 'e'".format(number_format_notation)) from None
326-
if isinstance(number, Decimal):
327-
tup = number.as_tuple()
329+
330+
if not isinstance(number, numbers):
331+
return number
332+
elif isinstance(number, Decimal):
328333
with localcontext() as ctx:
329-
ctx.prec = len(tup.digits) + tup.exponent + significant_digits
334+
# Precision = number of integer digits + significant_digits
335+
# Using number//1 to get the integer part of the number
336+
ctx.prec = len(str(abs(number // 1))) + significant_digits
330337
number = number.quantize(Decimal('0.' + '0' * significant_digits))
331-
elif not isinstance(number, numbers):
332-
return number
338+
elif isinstance(number, only_complex_number):
339+
# Case for complex numbers.
340+
number = number.__class__(
341+
"{real}+{imag}j".format(
342+
real=number_to_string(
343+
number=number.real,
344+
significant_digits=significant_digits,
345+
number_format_notation=number_format_notation
346+
),
347+
imag=number_to_string(
348+
number=number.imag,
349+
significant_digits=significant_digits,
350+
number_format_notation=number_format_notation
351+
)
352+
)
353+
)
354+
else:
355+
number = round(number=number, ndigits=significant_digits)
356+
357+
if significant_digits == 0:
358+
number = int(number)
359+
360+
if number == 0.0:
361+
# Special case for 0: "-0.xx" should compare equal to "0.xx"
362+
number = abs(number)
363+
364+
# Cast number to string
333365
result = (using % significant_digits).format(number)
334-
# Special case for 0: "-0.00" should compare equal to "0.00"
335-
if set(result) <= ZERO_DECIMAL_CHARACTERS:
336-
result = "0.00"
337366
# https://bugs.python.org/issue36622
338-
if number_format_notation == 'e' and isinstance(number, float):
339-
result = result.replace('+0', '+')
367+
if number_format_notation == 'e':
368+
# Removing leading 0 for exponential part.
369+
result = re.sub(
370+
pattern=r'(?<=e(\+|\-))0',
371+
repl=r'',
372+
string=result
373+
)
340374
return result
341375

342376

tests/test_hash.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ def test_same_sets_same_hash(self):
357357
assert t1_hash[get_id(t1)] == t2_hash[get_id(t2)]
358358

359359
@pytest.mark.parametrize("t1, t2, significant_digits, number_format_notation, result", [
360-
({0.012, 0.98}, {0.013, 0.99}, 1, "f", 'set:float:0.00,float:1.0'),
361-
(100000, 100021, 3, "e", 'int:1.000e+05'),
360+
({0.012, 0.98}, {0.013, 0.99}, 1, "f", 'set:float:0.0,float:1.0'),
361+
(100000, 100021, 3, "e", 'int:1.000e+5'),
362362
])
363363
def test_similar_significant_hash(self, t1, t2, significant_digits,
364364
number_format_notation, result):

tests/test_helper.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,42 @@ def test_short_repr_when_long(self):
5353
(Decimal('100000.1'), 100000.1, 5, True),
5454
(Decimal('100000'), 100000.1, 0, True),
5555
(Decimal('100000'), 100000.1, 1, ('100000.0', '100000.1')),
56+
(Decimal('-100000'), 100000.1, 1, ('-100000.0', '100000.1')),
57+
(0, 0.0, 5, True),
58+
(0, 0.2, 5, ('0.00000', '0.20000')),
59+
(0, 0.2, 0, True),
60+
(Decimal(0), 0, 0, True),
61+
(Decimal(0), 0, 10, True),
62+
(Decimal(0), 0.0, 0, True),
63+
(Decimal(0), 0.0, 10, True),
64+
(Decimal('0.0'), 0.0, 5, True),
65+
(Decimal('0.01'), 0.01, 1, True),
66+
(Decimal('0.01'), 0.01, 2, True),
67+
(Decimal('0.01'), 0.01, 5, True),
68+
(Decimal('0.01'), 0.01, 8, True),
69+
(Decimal('0.010'), 0.01, 3, True),
70+
(Decimal('0.00002'), 0.00001, 0, True),
71+
(Decimal('0.00002'), 0.00001, 1, True),
72+
(Decimal('0.00002'), 0.00001, 5, ('0.00002', '0.00001')),
73+
(Decimal('0.00002'), 0.00001, 6, ('0.000020', '0.000010')),
74+
(Decimal('0'), 0.1, 0, True),
75+
(Decimal('0'), 0.1, 1, ('0.0', '0.1')),
76+
(-0, 0.0, 5, True),
77+
(-0, 0.2, 5, ('0.00000', '0.20000')),
78+
(-0, 0.2, 0, True),
79+
(Decimal(-0), 0, 0, True),
80+
(Decimal(-0), 0, 10, True),
81+
(Decimal(-0), 0.0, 0, True),
82+
(Decimal(-0), 0.0, 10, True),
83+
(Decimal('-0.0'), 0.0, 5, True),
84+
(Decimal('-0.01'), 0.01, 1, True),
85+
(Decimal('-0.01'), 0.01, 2, ('-0.01', '0.01')),
86+
(Decimal('-0.00002'), 0.00001, 0, True),
87+
(Decimal('-0.00002'), 0.00001, 1, True),
88+
(Decimal('-0.00002'), 0.00001, 5, ('-0.00002', '0.00001')),
89+
(Decimal('-0.00002'), 0.00001, 6, ('-0.000020', '0.000010')),
90+
(Decimal('-0'), 0.1, 0, True),
91+
(Decimal('-0'), 0.1, 1, ('0.0', '0.1')),
5692
])
5793
def test_number_to_string_decimal_digits(self, t1, t2, significant_digits, expected_result):
5894
st1 = number_to_string(t1, significant_digits=significant_digits, number_format_notation="f")

0 commit comments

Comments
 (0)