diff --git a/deepdiff/diff.py b/deepdiff/diff.py index e65fd4a..b01e599 100644 --- a/deepdiff/diff.py +++ b/deepdiff/diff.py @@ -753,13 +753,16 @@ class DeepDiff(ResultDict, SerializationMixin, DistanceMixin, DeepDiffProtocol, t_keys_removed = t1_keys - t_keys_intersect if self.threshold_to_diff_deeper: - if self.exclude_paths or self.exclude_glob_paths: + if self.exclude_paths or self.exclude_glob_paths or self.exclude_regex_paths: t_keys_union = {f"{level.path()}[{repr(key)}]" for key in (t2_keys | t1_keys)} if self.exclude_paths: t_keys_union -= self.exclude_paths if self.exclude_glob_paths: t_keys_union = {k for k in t_keys_union if not any(gp.match(k) for gp in self.exclude_glob_paths)} + if self.exclude_regex_paths: + t_keys_union = {k for k in t_keys_union + if not any(rp.search(k) for rp in self.exclude_regex_paths)} t_keys_union_len = len(t_keys_union) else: t_keys_union_len = len(t2_keys | t1_keys) diff --git a/tests/test_diff_text.py b/tests/test_diff_text.py index fb0087b..4fdf2f7 100644 --- a/tests/test_diff_text.py +++ b/tests/test_diff_text.py @@ -1710,6 +1710,31 @@ class TestDeepDiffText: result = {} assert result == ddiff + def test_skip_regexp_with_default_threshold_to_diff_deeper(self): + t1 = {'a': [1, 2, [3, {'foo1': 'bar'}]]} + t2 = {'a': [1, 2, [3, {'foo2': 'bar'}]]} + exclude_regex_paths = [r"\['foo.'\]"] + equivalent_exclude_paths = ["root['a'][2][1]['foo1']", "root['a'][2][1]['foo2']"] + + # The excluded keys must not count towards threshold_to_diff_deeper, otherwise the + # whole dictionary is reported as a single change and the excluded keys leak into + # old_value and new_value. + assert {} == DeepDiff(t1, t2, exclude_regex_paths=exclude_regex_paths) + assert DeepDiff(t1, t2, exclude_paths=equivalent_exclude_paths) == DeepDiff( + t1, t2, exclude_regex_paths=exclude_regex_paths) + assert DeepDiff(t1, t2, exclude_regex_paths=exclude_regex_paths, threshold_to_diff_deeper=0) == DeepDiff( + t1, t2, exclude_regex_paths=exclude_regex_paths) + + def test_skip_regexp_with_default_threshold_to_diff_deeper_reports_remaining_keys(self): + t1 = {'foo1': 'bar', 'foo2': 'x', 'foo3': 'y', 'keep': 1} + t2 = {'foo4': 'bar', 'foo5': 'x', 'foo6': 'y', 'keep': 2} + + # Only 'keep' is shared, so the excluded keys alone would drag the ratio of shared + # keys under threshold_to_diff_deeper and hide the change on 'keep'. + ddiff = DeepDiff(t1, t2, exclude_regex_paths=[r"root\['foo.'\]"]) + result = {'values_changed': {"root['keep']": {'new_value': 2, 'old_value': 1}}} + assert result == ddiff + def test_include_obj_callback(self): def include_obj_callback(obj, path): return True if "include" in path or isinstance(obj, int) else False