Skip to content

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

@epou

Description

@epou

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions