Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions dictdiffer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ def diff(first, second, node=None, ignore=None, path_limit=None, expand=False,
... path_limit=PathLimit([('a', 'b')])))
[('add', '', [('a', {})]), ('add', 'a', [('b', 'c')])]

>>> from dictdiffer.utils import PathLimit
>>> list(diff({'a': {'b': 'c'}}, {'a': {'b': 'c'}}, path_limit=PathLimit([('a',)])))
>>> from dictdiffer.utils import PathLimit
>>> list(diff({'a': {'b': 'c'}}, {'a': {'b': 'c'}},
... path_limit=PathLimit([('a',)])))
[]

The patch can be expanded to small units e.g. when adding multiple values:
Expand All @@ -102,11 +103,14 @@ def diff(first, second, node=None, ignore=None, path_limit=None, expand=False,
:param path_limit: List of path limit tuples or dictdiffer.utils.Pathlimit
object to limit the diff recursion depth.
A diff is still performed beyond the path_limit,
but individual differences will be aggregated up to the path_limit.
but individual differences will be aggregated up to the
path_limit.
:param expand: Expand the patches.
:param tolerance: Threshold to consider when comparing two float numbers.
:param tolerance: Relative threshold for comparing two floating-point
numbers as equal, expressed as a proportion of the
maximum of the two
:param absolute_tolerance: Absolute threshold to consider when comparing
two float numbers.
two floating-point numbers.
:param dot_notation: Boolean to toggle dot notation on and off.

.. versionchanged:: 0.3
Expand Down
9 changes: 4 additions & 5 deletions dictdiffer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import sys
from itertools import zip_longest

num_types = int, float
EPSILON = sys.float_info.epsilon


Expand Down Expand Up @@ -256,8 +255,8 @@ def dot_lookup(source, lookup, parent=False):
def are_different(first, second, tolerance, absolute_tolerance=None):
"""Check if 2 values are different.

In case of numerical values, the tolerance is used to check if the values
are different.
In case of 2 floating-point values, the tolerance is used to check if the
values are different.
In all other cases, the difference is straight forward.
"""
if first == second:
Expand All @@ -269,8 +268,8 @@ def are_different(first, second, tolerance, absolute_tolerance=None):
if first_is_nan or second_is_nan:
# two 'NaN' values are not different (see issue #114)
return not (first_is_nan and second_is_nan)
elif isinstance(first, num_types) and isinstance(second, num_types):
# two numerical values are compared with tolerance
elif isinstance(first, float) and isinstance(second, float):
# two floating-precision values are compared with tolerance
return not math.isclose(
first,
second,
Expand Down
2 changes: 1 addition & 1 deletion dictdiffer/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# setup.py and docs/conf.py
"""Version information for dictdiffer package."""

__version__ = '0.9.0'
__version__ = '0.1.dev160'
88 changes: 88 additions & 0 deletions tests/test_dictdiffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Copyright (C) 2013 Fatih Erikli.
# Copyright (C) 2013, 2014, 2015, 2016 CERN.
# Copyright (C) 2017-2019 ETH Zurich, Swiss Data Science Center, Jiri Kuncar.
# Copyright (C) 2024 Kohl's.
#
# Dictdiffer is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more
Expand All @@ -13,6 +14,8 @@
import unittest
from collections import OrderedDict
from collections.abc import MutableMapping, MutableSequence
from decimal import Decimal
from fractions import Fraction

import pytest

Expand Down Expand Up @@ -152,6 +155,91 @@ def test_tolerance(self):
))
assert [] == diffed

first = {'a': 22570409781991170591038650551}
second = {'a': 22570409781991170591038650552}
diffed = list(diff(first, second, tolerance=None))
assert [
(
'change',
'a',
(22570409781991170591038650551, 22570409781991170591038650552)
)
] == diffed

diffed = list(diff(first, second, tolerance=0))
assert [
(
'change',
'a',
(22570409781991170591038650551, 22570409781991170591038650552)
)
] == diffed

diffed = list(diff(first, second, tolerance=1e-9))
assert [
(
'change',
'a',
(22570409781991170591038650551, 22570409781991170591038650552)
)
] == diffed

first = {'a': Decimal("1.0e-15")}
second = {'a': Decimal("2.5e-15")}
diffed = list(diff(first, second, tolerance=1e-20))
assert [
('change', 'a', (Decimal("1.0e-15"), Decimal("2.5e-15")))
] == diffed

first = {'a': complex(1.0e-15, 1.0e-15)}
second = {'a': complex(2.5e-15, 2.5e-15)}
diffed = list(
diff(first, second, tolerance=1e-3, absolute_tolerance=1e-3)
)
assert [
(
'change',
'a',
(complex(1.0e-15, 1.0e-15), complex(2.5e-15, 2.5e-15))
)
] == diffed

first = {'a': Fraction(10, 7)}
second = {'a': Fraction(11, 7)}
diffed = list(
diff(first, second, tolerance=1e-3, absolute_tolerance=1e-3)
)
assert [
('change', 'a', (Fraction(10, 7), Fraction(11, 7)))
] == diffed

first = {'a': 2 - 1e-15}
second = {'a': complex(2, 0)}
diffed = list(
diff(first, second, tolerance=1e-3, absolute_tolerance=1e-3)
)
assert [
('change', 'a', (2 - 1e-15, complex(2, 0)))
] == diffed

first = {'a': 2 - 1e-15}
second = {'a': 2}
diffed = list(
diff(first, second, tolerance=1e-3, absolute_tolerance=1e-3)
)
assert [
('change', 'a', (2 - 1e-15, 2))
] == diffed

first = {'a': 2 - 1e-15}
second = {'a': Decimal("2.0")}
diffed = list(
diff(first, second, tolerance=1e-3, absolute_tolerance=1e-3)
)
assert [
('change', 'a', (2 - 1e-15, Decimal("2.0")))
] == diffed

def test_path_limit_as_list(self):
first = {}
second = {'author': {'last_name': 'Doe', 'first_name': 'John'}}
Expand Down