Skip to content

Commit

Permalink
Merge pull request #499 from jlaba/master
Browse files Browse the repository at this point in the history
Fixed #493 include_paths, when only certain keys are included
  • Loading branch information
seperman authored Nov 14, 2024
2 parents 5d30b3a + fc8baaa commit 32d60a9
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 4 deletions.
34 changes: 30 additions & 4 deletions deepdiff/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,32 @@ def _skip_this(self, level):

return skip

def _skip_this_key(self, level, key):
# if include_paths is not set, than treet every path as included
if self.include_paths is None:
return False
if "{}['{}']".format(level.path(), key) in self.include_paths:
return False
if level.path() in self.include_paths:
# matches e.g. level+key root['foo']['bar']['veg'] include_paths ["root['foo']['bar']"]
return False
for prefix in self.include_paths:
if "{}['{}']".format(level.path(), key) in prefix:
# matches as long the prefix is longer than this object key
# eg.: level+key root['foo']['bar'] matches prefix root['foo']['bar'] from include paths
# level+key root['foo'] matches prefix root['foo']['bar'] from include_paths
# level+key root['foo']['bar'] DOES NOT match root['foo'] from include_paths This needs to be handled afterwards
return False
# check if a higher level is included as a whole (=without any sublevels specified)
# matches e.g. level+key root['foo']['bar']['veg'] include_paths ["root['foo']"]
# but does not match, if it is level+key root['foo']['bar']['veg'] include_paths ["root['foo']['bar']['fruits']"]
up = level.up
while up is not None:
if up.path() in self.include_paths:
return False
up = up.up
return True

def _get_clean_to_keys_mapping(self, keys, level):
"""
Get a dictionary of cleaned value of keys to the keys themselves.
Expand Down Expand Up @@ -570,11 +596,11 @@ def _diff_dict(
rel_class = DictRelationship

if self.ignore_private_variables:
t1_keys = SetOrdered([key for key in t1 if not(isinstance(key, str) and key.startswith('__'))])
t2_keys = SetOrdered([key for key in t2 if not(isinstance(key, str) and key.startswith('__'))])
t1_keys = SetOrdered([key for key in t1 if not(isinstance(key, str) and key.startswith('__')) and not self._skip_this_key(level, key)])
t2_keys = SetOrdered([key for key in t2 if not(isinstance(key, str) and key.startswith('__')) and not self._skip_this_key(level, key)])
else:
t1_keys = SetOrdered(t1.keys())
t2_keys = SetOrdered(t2.keys())
t1_keys = SetOrdered([key for key in t1 if not self._skip_this_key(level, key)])
t2_keys = SetOrdered([key for key in t2 if not self._skip_this_key(level, key)])
if self.ignore_string_type_changes or self.ignore_numeric_type_changes or self.ignore_string_case:
t1_clean_to_keys = self._get_clean_to_keys_mapping(keys=t1_keys, level=level)
t2_clean_to_keys = self._get_clean_to_keys_mapping(keys=t2_keys, level=level)
Expand Down
File renamed without changes.
160 changes: 160 additions & 0 deletions tests/test_diff_include_paths_count.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import pytest
from deepdiff import DeepDiff

@pytest.mark.parametrize(
"data, result",
[
(
{
"old": {
'name': 'Testname Old',
'desciption': 'Desc Old',
'sub_path': {
'name': 'Testname Subpath old',
'desciption': 'Desc Subpath old',
},
},
"new": {
'name': 'Testname New',
'desciption': 'Desc New',
'new_attribute': 'New Value',
'sub_path': {
'name': 'Testname Subpath old',
'desciption': 'Desc Subpath old',
},
},
"include_paths": "root['sub_path']",
},
{}
),
(
{
"old": {
'name': 'Testname Old',
'desciption': 'Desc Old',
'sub_path': {
'name': 'Testname Subpath old',
'desciption': 'Desc Subpath old',
},
},
"new": {
'name': 'Testname New',
'desciption': 'Desc New',
'new_attribute': 'New Value',
'sub_path': {
'name': 'Testname Subpath New',
'desciption': 'Desc Subpath old',
},
},
"include_paths": "root['sub_path']",
},
{"values_changed": {"root['sub_path']['name']": {"old_value": "Testname Subpath old", "new_value": "Testname Subpath New"}}}
),
(
{
"old": {
'name': 'Testname Old',
'desciption': 'Desc Old',
'sub_path': {
'name': 'Testname Subpath old',
'desciption': 'Desc Subpath old',
'old_attr': 'old attr value',
},
},
"new": {
'name': 'Testname New',
'desciption': 'Desc New',
'new_attribute': 'New Value',
'sub_path': {
'name': 'Testname Subpath old',
'desciption': 'Desc Subpath New',
'new_sub_path_attr': 'new sub path attr value',
},
},
"include_paths": "root['sub_path']['name']",
},
{}
),
(
{
"old": {
'name': 'Testname old',
'desciption': 'Desc old',
'new_attribute': 'old Value',
'sub_path': {
'name': 'Testname',
'removed_attr': 'revemod attr value',
},
},
"new": {
'name': 'Testname new',
'desciption': 'Desc new',
'new_attribute': 'new Value',
'sub_path': {
'added_attr': 'Added Attr Value',
'name': 'Testname',
},
},
"include_paths": "root['sub_path']['name']",
},
{}
),
(
{
"old": {
'name': 'Testname',
'removed_attr': 'revemod attr value',
},
"new": {
'added_attr': 'Added Attr Value',
'name': 'Testname',
},
"include_paths": "root['name']",
},
{}
),
(
{
"old": {
'name': 'Testname',
'removed_attr': 'revemod attr value',
'removed_attr_2': 'revemod attr value',
},
"new": {
'added_attr': 'Added Attr Value',
'name': 'Testname',
},
"include_paths": "root['name']",
},
{}
),
(
{
"old": {
'name': 'Testname old',
'desciption': 'Desc old',
'new_attribute': 'old Value',
'sub_path': {
'name': 'Testname',
'removed_attr': 'revemod attr value',
'removed_attr_2': 'blu',
},
},
"new": {
'name': 'Testname new',
'desciption': 'Desc new',
'new_attribute': 'new Value',
'sub_path': {
'added_attr': 'Added Attr Value',
'name': 'Testname',
},
},
"include_paths": "root['sub_path']['name']",
},
{}
),
]
)
def test_diff_include_paths_root(data, result):
diff = DeepDiff(data["old"], data["new"], include_paths=data["include_paths"])
assert diff == result

0 comments on commit 32d60a9

Please sign in to comment.