Skip to content

Commit 32d60a9

Browse files
authored
Merge pull request #499 from jlaba/master
Fixed #493 include_paths, when only certain keys are included
2 parents 5d30b3a + fc8baaa commit 32d60a9

File tree

3 files changed

+190
-4
lines changed

3 files changed

+190
-4
lines changed

deepdiff/diff.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,32 @@ def _skip_this(self, level):
510510

511511
return skip
512512

513+
def _skip_this_key(self, level, key):
514+
# if include_paths is not set, than treet every path as included
515+
if self.include_paths is None:
516+
return False
517+
if "{}['{}']".format(level.path(), key) in self.include_paths:
518+
return False
519+
if level.path() in self.include_paths:
520+
# matches e.g. level+key root['foo']['bar']['veg'] include_paths ["root['foo']['bar']"]
521+
return False
522+
for prefix in self.include_paths:
523+
if "{}['{}']".format(level.path(), key) in prefix:
524+
# matches as long the prefix is longer than this object key
525+
# eg.: level+key root['foo']['bar'] matches prefix root['foo']['bar'] from include paths
526+
# level+key root['foo'] matches prefix root['foo']['bar'] from include_paths
527+
# level+key root['foo']['bar'] DOES NOT match root['foo'] from include_paths This needs to be handled afterwards
528+
return False
529+
# check if a higher level is included as a whole (=without any sublevels specified)
530+
# matches e.g. level+key root['foo']['bar']['veg'] include_paths ["root['foo']"]
531+
# but does not match, if it is level+key root['foo']['bar']['veg'] include_paths ["root['foo']['bar']['fruits']"]
532+
up = level.up
533+
while up is not None:
534+
if up.path() in self.include_paths:
535+
return False
536+
up = up.up
537+
return True
538+
513539
def _get_clean_to_keys_mapping(self, keys, level):
514540
"""
515541
Get a dictionary of cleaned value of keys to the keys themselves.
@@ -570,11 +596,11 @@ def _diff_dict(
570596
rel_class = DictRelationship
571597

572598
if self.ignore_private_variables:
573-
t1_keys = SetOrdered([key for key in t1 if not(isinstance(key, str) and key.startswith('__'))])
574-
t2_keys = SetOrdered([key for key in t2 if not(isinstance(key, str) and key.startswith('__'))])
599+
t1_keys = SetOrdered([key for key in t1 if not(isinstance(key, str) and key.startswith('__')) and not self._skip_this_key(level, key)])
600+
t2_keys = SetOrdered([key for key in t2 if not(isinstance(key, str) and key.startswith('__')) and not self._skip_this_key(level, key)])
575601
else:
576-
t1_keys = SetOrdered(t1.keys())
577-
t2_keys = SetOrdered(t2.keys())
602+
t1_keys = SetOrdered([key for key in t1 if not self._skip_this_key(level, key)])
603+
t2_keys = SetOrdered([key for key in t2 if not self._skip_this_key(level, key)])
578604
if self.ignore_string_type_changes or self.ignore_numeric_type_changes or self.ignore_string_case:
579605
t1_clean_to_keys = self._get_clean_to_keys_mapping(keys=t1_keys, level=level)
580606
t2_clean_to_keys = self._get_clean_to_keys_mapping(keys=t2_keys, level=level)
File renamed without changes.
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import pytest
2+
from deepdiff import DeepDiff
3+
4+
@pytest.mark.parametrize(
5+
"data, result",
6+
[
7+
(
8+
{
9+
"old": {
10+
'name': 'Testname Old',
11+
'desciption': 'Desc Old',
12+
'sub_path': {
13+
'name': 'Testname Subpath old',
14+
'desciption': 'Desc Subpath old',
15+
},
16+
},
17+
"new": {
18+
'name': 'Testname New',
19+
'desciption': 'Desc New',
20+
'new_attribute': 'New Value',
21+
'sub_path': {
22+
'name': 'Testname Subpath old',
23+
'desciption': 'Desc Subpath old',
24+
},
25+
},
26+
"include_paths": "root['sub_path']",
27+
},
28+
{}
29+
),
30+
(
31+
{
32+
"old": {
33+
'name': 'Testname Old',
34+
'desciption': 'Desc Old',
35+
'sub_path': {
36+
'name': 'Testname Subpath old',
37+
'desciption': 'Desc Subpath old',
38+
},
39+
},
40+
"new": {
41+
'name': 'Testname New',
42+
'desciption': 'Desc New',
43+
'new_attribute': 'New Value',
44+
'sub_path': {
45+
'name': 'Testname Subpath New',
46+
'desciption': 'Desc Subpath old',
47+
},
48+
},
49+
"include_paths": "root['sub_path']",
50+
},
51+
{"values_changed": {"root['sub_path']['name']": {"old_value": "Testname Subpath old", "new_value": "Testname Subpath New"}}}
52+
),
53+
(
54+
{
55+
"old": {
56+
'name': 'Testname Old',
57+
'desciption': 'Desc Old',
58+
'sub_path': {
59+
'name': 'Testname Subpath old',
60+
'desciption': 'Desc Subpath old',
61+
'old_attr': 'old attr value',
62+
},
63+
},
64+
"new": {
65+
'name': 'Testname New',
66+
'desciption': 'Desc New',
67+
'new_attribute': 'New Value',
68+
'sub_path': {
69+
'name': 'Testname Subpath old',
70+
'desciption': 'Desc Subpath New',
71+
'new_sub_path_attr': 'new sub path attr value',
72+
},
73+
},
74+
"include_paths": "root['sub_path']['name']",
75+
},
76+
{}
77+
),
78+
(
79+
{
80+
"old": {
81+
'name': 'Testname old',
82+
'desciption': 'Desc old',
83+
'new_attribute': 'old Value',
84+
'sub_path': {
85+
'name': 'Testname',
86+
'removed_attr': 'revemod attr value',
87+
},
88+
},
89+
"new": {
90+
'name': 'Testname new',
91+
'desciption': 'Desc new',
92+
'new_attribute': 'new Value',
93+
'sub_path': {
94+
'added_attr': 'Added Attr Value',
95+
'name': 'Testname',
96+
},
97+
},
98+
"include_paths": "root['sub_path']['name']",
99+
},
100+
{}
101+
),
102+
(
103+
{
104+
"old": {
105+
'name': 'Testname',
106+
'removed_attr': 'revemod attr value',
107+
},
108+
"new": {
109+
'added_attr': 'Added Attr Value',
110+
'name': 'Testname',
111+
},
112+
"include_paths": "root['name']",
113+
},
114+
{}
115+
),
116+
(
117+
{
118+
"old": {
119+
'name': 'Testname',
120+
'removed_attr': 'revemod attr value',
121+
'removed_attr_2': 'revemod attr value',
122+
},
123+
"new": {
124+
'added_attr': 'Added Attr Value',
125+
'name': 'Testname',
126+
},
127+
"include_paths": "root['name']",
128+
},
129+
{}
130+
),
131+
(
132+
{
133+
"old": {
134+
'name': 'Testname old',
135+
'desciption': 'Desc old',
136+
'new_attribute': 'old Value',
137+
'sub_path': {
138+
'name': 'Testname',
139+
'removed_attr': 'revemod attr value',
140+
'removed_attr_2': 'blu',
141+
},
142+
},
143+
"new": {
144+
'name': 'Testname new',
145+
'desciption': 'Desc new',
146+
'new_attribute': 'new Value',
147+
'sub_path': {
148+
'added_attr': 'Added Attr Value',
149+
'name': 'Testname',
150+
},
151+
},
152+
"include_paths": "root['sub_path']['name']",
153+
},
154+
{}
155+
),
156+
]
157+
)
158+
def test_diff_include_paths_root(data, result):
159+
diff = DeepDiff(data["old"], data["new"], include_paths=data["include_paths"])
160+
assert diff == result

0 commit comments

Comments
 (0)