deepdiff icon indicating copy to clipboard operation
deepdiff copied to clipboard

ValueError: valid range for prec is [1, MAX_PREC]

Open epou opened this issue 3 years ago • 0 comments

Describe the bug ValueError is raised when using "0.x" Decimal as value and significant_digits is lower than the number of decimal digits used as input.

To Reproduce

Python 3.8.13 (default, Jun  8 2022, 12:42:16) 
[GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from deepdiff import DeepDiff
>>> from decimal import Decimal
>>> dict1 = {'key': Decimal('0.000')}
>>> dict2 = {'key': Decimal('0.0001')}
>>> 
>>> DeepDiff(dict1, dict2) # OK
{'values_changed': {"root['key']": {'new_value': Decimal('0.0001'), 'old_value': Decimal('0.000')}}}
>>> 
>>> DeepDiff(dict1, dict2, significant_digits=2) # Should return {}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 296, in __init__
    self._diff(root, parents_ids=frozenset({id(t1)}), _original_type=_original_type)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 1339, in _diff
    self._diff_dict(level, parents_ids)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 547, in _diff_dict
    self._diff(next_level, parents_ids_added)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 1336, in _diff
    self._diff_numbers(level)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 1145, in _diff_numbers
    t1_s = self.number_to_string(level.t1,
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/helper.py", line 327, in number_to_string
    ctx.prec = len(tup.digits) + tup.exponent + significant_digits
ValueError: valid range for prec is [1, MAX_PREC] 
>>> 
>>> DeepDiff(dict1, dict2, significant_digits=3) # Should return {}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 296, in __init__
    self._diff(root, parents_ids=frozenset({id(t1)}), _original_type=_original_type)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 1339, in _diff
    self._diff_dict(level, parents_ids)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 547, in _diff_dict
    self._diff(next_level, parents_ids_added)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 1336, in _diff
    self._diff_numbers(level)
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/diff.py", line 1148, in _diff_numbers
    t2_s = self.number_to_string(level.t2,
  File "/home/user/Development/project/venv/lib/python3.8/site-packages/deepdiff/helper.py", line 327, in number_to_string
    ctx.prec = len(tup.digits) + tup.exponent + significant_digits
ValueError: valid range for prec is [1, MAX_PREC]
>>> 
>>> 
>>> DeepDiff(dict1, dict2, significant_digits=4) # OK
{'values_changed': {"root['key']": {'new_value': Decimal('0.0001'), 'old_value': Decimal('0.000')}}}

Expected behavior

  • DeepDiff(dict1, dict2, significant_digits=2) -> Should return {}, not raise ValueError.
  • DeepDiff(dict1, dict2, significant_digits=3) -> Should return {}, not raise ValueError.

OS, DeepDiff version and Python version (please complete the following information):

  • OS: Ubuntu
  • Version: 22.04 LTS
  • Python Version: 3.8.13
  • DeepDiff Version: 5.8.1

Additional context

>>> from decimal import Decimal
>>> Decimal('0.000').as_tuple()
DecimalTuple(sign=0, digits=(0,), exponent=-3)

In helper.py, method number_to_string:

[...]
if isinstance(number, Decimal):
        tup = number.as_tuple()
        with localcontext() as ctx:
            ctx.prec = len(tup.digits) + tup.exponent + significant_digits
            number = number.quantize(Decimal('0.' + '0' * significant_digits))
[...]

ctx.prec should be equal to the number of integer digits + significant_digits. len(tup.digits) + tup.exponent is not a good way to get the number of integer digits (it fails for 0.x Decimal)

epou avatar Aug 17 '22 10:08 epou