Skip to content

Commit d705a4b

Browse files
committed
Made change to diff near line 1128 to change evaluations for lengths from >1 to >0
1 parent 89c5cc2 commit d705a4b

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

deepdiff/diff.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,9 @@ def defaultdict_orderedset():
11251125
pre_calced_distances = self._precalculate_numpy_arrays_distance(
11261126
hashes_added, hashes_removed, t1_hashtable, t2_hashtable, _original_type)
11271127

1128-
if hashes_added and hashes_removed and self.iterable_compare_func and len(hashes_added) > 1 and len(hashes_removed) > 1:
1128+
if hashes_added and hashes_removed \
1129+
and self.iterable_compare_func \
1130+
and len(hashes_added) > 0 and len(hashes_removed) > 0:
11291131
pre_calced_distances = self._precalculate_distance_by_custom_compare_func(
11301132
hashes_added, hashes_removed, t1_hashtable, t2_hashtable, _original_type)
11311133

tests/test_ignore_order.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,121 @@ def compare_func(x, y, level=None):
10721072
assert expected_with_compare_func == ddiff2
10731073
assert ddiff != ddiff2
10741074

1075+
def test_ignore_order_with_compare_func_with_one_each_hashes_added_hashes_removed(self):
1076+
"""
1077+
Scenario:
1078+
In this example which demonstrates the problem... We have two dictionaries containing lists for
1079+
individualNames. Each list contains exactly 2 elements. The effective change is that we are
1080+
replacing the 2nd element in the list.
1081+
NOTE: This is considered a REPLACEMENT of the second element and not an UPDATE of the element
1082+
because we are providing a custom compare_func which will determine matching elements based on
1083+
the value of the nameIdentifier field. If the custom compare_func is not used, then
1084+
deepdiff.diff will mistakenly treat the difference as being individual field updates for every
1085+
field in the second element of the list.
1086+
1087+
Intent:
1088+
Use our custom compare_func, since we have provided it.
1089+
We need to fall into self._precalculate_distance_by_custom_compare_func
1090+
To do this, we are proposing a change to deepdiff.diff line 1128:
1091+
1092+
Original:
1093+
if hashes_added and hashes_removed and self.iterable_compare_func and len(hashes_added) > 1 and len(hashes_removed) > 1:
1094+
1095+
Proposed/Updated:
1096+
if hashes_added and hashes_removed \
1097+
and self.iterable_compare_func \
1098+
and len(hashes_added) > 0 and len(hashes_removed) > 0:
1099+
1100+
NOTE: It is worth mentioning that deepdiff.diff line 1121, might also benefit by changing the length conditions
1101+
to evaluate for > 0 (rather than > 1).
1102+
"""
1103+
1104+
t1 = {
1105+
"individualNames": [
1106+
{
1107+
"firstName": "Johnathan",
1108+
"lastName": "Doe",
1109+
"prefix": "COLONEL",
1110+
"middleName": "A",
1111+
"primaryIndicator": True,
1112+
"professionalDesignation": "PHD",
1113+
"suffix": "SR",
1114+
"nameIdentifier": "00001"
1115+
},
1116+
{
1117+
"firstName": "John",
1118+
"lastName": "Doe",
1119+
"prefix": "",
1120+
"middleName": "",
1121+
"primaryIndicator": False,
1122+
"professionalDesignation": "",
1123+
"suffix": "SR",
1124+
"nameIdentifier": "00002"
1125+
}
1126+
]
1127+
}
1128+
1129+
t2 = {
1130+
"individualNames": [
1131+
{
1132+
"firstName": "Johnathan",
1133+
"lastName": "Doe",
1134+
"prefix": "COLONEL",
1135+
"middleName": "A",
1136+
"primaryIndicator": True,
1137+
"professionalDesignation": "PHD",
1138+
"suffix": "SR",
1139+
"nameIdentifier": "00001"
1140+
},
1141+
{
1142+
"firstName": "Johnny",
1143+
"lastName": "Doe",
1144+
"prefix": "",
1145+
"middleName": "A",
1146+
"primaryIndicator": False,
1147+
"professionalDesignation": "",
1148+
"suffix": "SR",
1149+
"nameIdentifier": "00003"
1150+
}
1151+
]
1152+
}
1153+
def compare_func(item1, item2, level=None):
1154+
print("*** inside compare ***")
1155+
it1_keys = item1.keys()
1156+
1157+
try:
1158+
1159+
# --- individualNames ---
1160+
if 'nameIdentifier' in it1_keys and 'lastName' in it1_keys:
1161+
match_result = item1['nameIdentifier'] == item2['nameIdentifier']
1162+
print("individualNames - matching result:", match_result)
1163+
return match_result
1164+
else:
1165+
print("Unknown list item...", "matching result:", item1 == item2)
1166+
return item1 == item2
1167+
except Exception:
1168+
raise CannotCompare() from None
1169+
# ---------------------------- End of nested function
1170+
1171+
actual_diff = DeepDiff(t1, t2, report_repetition=True,
1172+
ignore_order=True, iterable_compare_func=compare_func, cutoff_intersection_for_pairs=1)
1173+
1174+
old_invalid_diff = {
1175+
'values_changed': {"root['individualNames'][1]['firstName']": {'new_value': 'Johnny', 'old_value': 'John'},
1176+
"root['individualNames'][1]['middleName']": {'new_value': 'A', 'old_value': ''},
1177+
"root['individualNames'][1]['nameIdentifier']": {'new_value': '00003',
1178+
'old_value': '00002'}}}
1179+
new_expected_diff = {'iterable_item_added': {
1180+
"root['individualNames'][1]": {'firstName': 'Johnny', 'lastName': 'Doe', 'prefix': '', 'middleName': 'A',
1181+
'primaryIndicator': False, 'professionalDesignation': '', 'suffix': 'SR',
1182+
'nameIdentifier': '00003'}}, 'iterable_item_removed': {
1183+
"root['individualNames'][1]": {'firstName': 'John', 'lastName': 'Doe', 'prefix': '', 'middleName': '',
1184+
'primaryIndicator': False, 'professionalDesignation': '', 'suffix': 'SR',
1185+
'nameIdentifier': '00002'}}}
1186+
1187+
assert old_invalid_diff != actual_diff
1188+
assert new_expected_diff == actual_diff
1189+
10751190

10761191
class TestDynamicIgnoreOrder:
10771192
def test_ignore_order_func(self):

0 commit comments

Comments
 (0)