Skip to content

Commit 54ebdb5

Browse files
committed
Include type info and change the "unknown" value for flat rows to
something that is friendly for Postgres enums
1 parent 4c337cf commit 54ebdb5

File tree

4 files changed

+93
-62
lines changed

4 files changed

+93
-62
lines changed

deepdiff/delta.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ def to_dict(self):
878878
return dict(self.diff)
879879

880880
@staticmethod
881-
def _get_flat_row(action, info, _parse_path, keys_and_funcs):
881+
def _get_flat_row(action, info, _parse_path, keys_and_funcs, report_type_changes=True):
882882
for path, details in info.items():
883883
row = {'path': _parse_path(path), 'action': action}
884884
for key, new_key, func in keys_and_funcs:
@@ -887,6 +887,11 @@ def _get_flat_row(action, info, _parse_path, keys_and_funcs):
887887
row[new_key] = func(details[key])
888888
else:
889889
row[new_key] = details[key]
890+
if report_type_changes:
891+
if 'value' in row and 'type' not in row:
892+
row['type'] = type(row['value'])
893+
if 'old_value' in row and 'old_type' not in row:
894+
row['old_type'] = type(row['old_value'])
890895
yield FlatDeltaRow(**row)
891896

892897
@staticmethod
@@ -1060,6 +1065,9 @@ def to_flat_rows(self, include_action_in_path=False, report_type_changes=True) -
10601065
'iterable_items_removed_at_indexes': 'unordered_iterable_item_removed',
10611066
}
10621067
for action, info in self.diff.items():
1068+
if action == '_iterable_opcodes':
1069+
result.extend(self._flatten_iterable_opcodes())
1070+
continue
10631071
if action.startswith('_'):
10641072
continue
10651073
if action in FLATTENING_NEW_ACTION_MAP:
@@ -1072,12 +1080,20 @@ def to_flat_rows(self, include_action_in_path=False, report_type_changes=True) -
10721080
path2.append((index, 'GET'))
10731081
else:
10741082
path2.append(index)
1075-
result.append(FlatDeltaRow(path=path2, value=value, action=new_action))
1083+
if report_type_changes:
1084+
row = FlatDeltaRow(path=path2, value=value, action=new_action, type=type(value))
1085+
else:
1086+
row = FlatDeltaRow(path=path2, value=value, action=new_action)
1087+
result.append(row)
10761088
elif action in {'set_item_added', 'set_item_removed'}:
10771089
for path, values in info.items():
10781090
path = _parse_path(path)
10791091
for value in values:
1080-
result.append(FlatDeltaRow(path=path, value=value, action=action))
1092+
if report_type_changes:
1093+
row = FlatDeltaRow(path=path, value=value, action=action, type=type(value))
1094+
else:
1095+
row = FlatDeltaRow(path=path, value=value, action=action)
1096+
result.append(row)
10811097
elif action == 'dictionary_item_added':
10821098
for path, value in info.items():
10831099
path = _parse_path(path)
@@ -1092,14 +1108,22 @@ def to_flat_rows(self, include_action_in_path=False, report_type_changes=True) -
10921108
elif isinstance(value, set) and len(value) == 1:
10931109
value = value.pop()
10941110
action = 'set_item_added'
1095-
result.append(FlatDeltaRow(path=path, value=value, action=action))
1111+
if report_type_changes:
1112+
row = FlatDeltaRow(path=path, value=value, action=action, type=type(value))
1113+
else:
1114+
row = FlatDeltaRow(path=path, value=value, action=action)
1115+
result.append(row)
10961116
elif action in {
10971117
'dictionary_item_removed', 'iterable_item_added',
10981118
'iterable_item_removed', 'attribute_removed', 'attribute_added'
10991119
}:
11001120
for path, value in info.items():
11011121
path = _parse_path(path)
1102-
result.append(FlatDeltaRow(path=path, value=value, action=action))
1122+
if report_type_changes:
1123+
row = FlatDeltaRow(path=path, value=value, action=action, type=type(value))
1124+
else:
1125+
row = FlatDeltaRow(path=path, value=value, action=action)
1126+
result.append(row)
11031127
elif action == 'type_changes':
11041128
if not report_type_changes:
11051129
action = 'values_changed'
@@ -1109,16 +1133,16 @@ def to_flat_rows(self, include_action_in_path=False, report_type_changes=True) -
11091133
info=info,
11101134
_parse_path=_parse_path,
11111135
keys_and_funcs=keys_and_funcs,
1136+
report_type_changes=report_type_changes,
11121137
):
11131138
result.append(row)
1114-
elif action == '_iterable_opcodes':
1115-
result.extend(self._flatten_iterable_opcodes())
11161139
else:
11171140
for row in self._get_flat_row(
11181141
action=action,
11191142
info=info,
11201143
_parse_path=_parse_path,
11211144
keys_and_funcs=keys_and_funcs,
1145+
report_type_changes=report_type_changes,
11221146
):
11231147
result.append(row)
11241148
return result

deepdiff/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ class FlatDataAction(str, enum.Enum):
771771
unordered_iterable_item_removed = 'unordered_iterable_item_removed'
772772

773773

774-
UnkownValueCode = '*-UNKNOWN-*'
774+
UnkownValueCode = 'unknown___'
775775

776776

777777
class FlatDeltaRow(NamedTuple):

docs/serialization.rst

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ Flat Row Specs:
181181
unordered_iterable_item_removed = 'unordered_iterable_item_removed'
182182

183183

184-
UnkownValueCode = '*-UNKNOWN-*'
184+
UnkownValueCode = 'unknown___'
185185

186186

187187
class FlatDeltaRow(NamedTuple):
@@ -205,7 +205,7 @@ Delta Serialize To Flat Dictionaries
205205

206206
Sometimes, it is desired to serialize a :ref:`delta_label` object to a list of flat dictionaries. For example, to store them in relation databases. In that case, you can use the Delta.to_flat_dicts to achieve the desired outcome.
207207

208-
Since None is a valid value, we use a special hard-coded string to signify "unkown": '*-UNKNOWN-*'
208+
Since None is a valid value, we use a special hard-coded string to signify "unkown": 'unknown___'
209209

210210
.. note::
211211
Many new keys are added to the flat dicts in DeepDiff 7.0.0
@@ -226,25 +226,25 @@ For example:
226226
>>> pprint(flat_dicts, indent=2)
227227
[ { 'action': 'dictionary_item_added',
228228
'new_path': None,
229-
'old_type': '*-UNKNOWN-*',
230-
'old_value': '*-UNKNOWN-*',
229+
'old_type': 'unknown___',
230+
'old_value': 'unknown___',
231231
'path': ['field2', 'key2'],
232232
't1_from_index': None,
233233
't1_to_index': None,
234234
't2_from_index': None,
235235
't2_to_index': None,
236-
'type': '*-UNKNOWN-*',
236+
'type': 'unknown___',
237237
'value': 'value2'},
238238
{ 'action': 'dictionary_item_removed',
239239
'new_path': None,
240-
'old_type': '*-UNKNOWN-*',
241-
'old_value': '*-UNKNOWN-*',
240+
'old_type': 'unknown___',
241+
'old_value': 'unknown___',
242242
'path': ['key1'],
243243
't1_from_index': None,
244244
't1_to_index': None,
245245
't2_from_index': None,
246246
't2_to_index': None,
247-
'type': '*-UNKNOWN-*',
247+
'type': 'unknown___',
248248
'value': 'value1'}]
249249

250250

@@ -261,25 +261,25 @@ Example 2:
261261
>>> pprint(flat_dicts, indent=2)
262262
[ { 'action': 'iterable_item_added',
263263
'new_path': None,
264-
'old_type': '*-UNKNOWN-*',
265-
'old_value': '*-UNKNOWN-*',
264+
'old_type': 'unknown___',
265+
'old_value': 'unknown___',
266266
'path': [2],
267267
't1_from_index': None,
268268
't1_to_index': None,
269269
't2_from_index': None,
270270
't2_to_index': None,
271-
'type': '*-UNKNOWN-*',
271+
'type': 'unknown___',
272272
'value': 'C'},
273273
{ 'action': 'iterable_item_added',
274274
'new_path': None,
275-
'old_type': '*-UNKNOWN-*',
276-
'old_value': '*-UNKNOWN-*',
275+
'old_type': 'unknown___',
276+
'old_value': 'unknown___',
277277
'path': [3],
278278
't1_from_index': None,
279279
't1_to_index': None,
280280
't2_from_index': None,
281281
't2_to_index': None,
282-
'type': '*-UNKNOWN-*',
282+
'type': 'unknown___',
283283
'value': 'D'}]
284284

285285

tests/test_delta.py

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ def test_list_difference_add_delta(self):
7373

7474
flat_result1 = delta.to_flat_rows()
7575
flat_expected1 = [
76-
FlatDeltaRow(path=[3], value=5, action='iterable_item_added'),
77-
FlatDeltaRow(path=[2], value=3, action='iterable_item_added'),
76+
FlatDeltaRow(path=[3], value=5, action='iterable_item_added', type=int),
77+
FlatDeltaRow(path=[2], value=3, action='iterable_item_added', type=int),
7878
]
7979

8080
assert flat_expected1 == flat_result1
@@ -291,9 +291,9 @@ def test_list_difference3_delta(self):
291291

292292
flat_result1 = delta.to_flat_rows()
293293
flat_expected1 = [
294-
FlatDeltaRow(path=[4, 'b', 2], action='values_changed', value=2, old_value=5),
295-
FlatDeltaRow(path=[4, 'b', 1], action='values_changed', value=3, old_value=2),
296-
FlatDeltaRow(path=[4, 'b', 3], value=5, action='iterable_item_added'),
294+
FlatDeltaRow(path=[4, 'b', 2], action='values_changed', value=2, old_value=5, type=int, old_type=int),
295+
FlatDeltaRow(path=[4, 'b', 1], action='values_changed', value=3, old_value=2, type=int, old_type=int),
296+
FlatDeltaRow(path=[4, 'b', 3], value=5, action='iterable_item_added', type=int),
297297
]
298298

299299
assert flat_expected1 == flat_result1
@@ -332,9 +332,9 @@ def test_list_difference_delta_raises_error_if_prev_value_does_not_match(self):
332332

333333
flat_result2 = delta2.to_flat_rows()
334334
flat_expected2 = [
335-
FlatDeltaRow(path=[2], action='values_changed', value=2, old_value=5),
336-
FlatDeltaRow(path=[1], action='values_changed', value=3, old_value=2),
337-
FlatDeltaRow(path=[3], value=5, action='iterable_item_added'),
335+
FlatDeltaRow(path=[2], action='values_changed', value=2, old_value=5, type=int, old_type=int),
336+
FlatDeltaRow(path=[1], action='values_changed', value=3, old_value=2, type=int, old_type=int),
337+
FlatDeltaRow(path=[3], value=5, action='iterable_item_added', type=int),
338338
]
339339

340340
assert flat_expected2 == flat_result2
@@ -363,8 +363,8 @@ def test_list_difference_delta1(self):
363363

364364
flat_result = delta.to_flat_rows()
365365
flat_expected = [
366-
FlatDeltaRow(path=[4, 'b', 2], value='to_be_removed', action='iterable_item_removed'),
367-
FlatDeltaRow(path=[4, 'b', 3], value='to_be_removed2', action='iterable_item_removed'),
366+
FlatDeltaRow(path=[4, 'b', 2], value='to_be_removed', action='iterable_item_removed', type=str),
367+
FlatDeltaRow(path=[4, 'b', 3], value='to_be_removed2', action='iterable_item_removed', type=str),
368368
]
369369

370370
assert flat_expected == flat_result
@@ -567,7 +567,8 @@ def compare_func(item1, item2, level=None):
567567
'professionalDesignation': '',
568568
'suffix': 'SR',
569569
'nameIdentifier': '00003'},
570-
action='unordered_iterable_item_added'),
570+
action='unordered_iterable_item_added',
571+
type=dict),
571572
FlatDeltaRow(path=['individualNames', 1],
572573
value={'firstName': 'John',
573574
'lastName': 'Doe',
@@ -577,7 +578,9 @@ def compare_func(item1, item2, level=None):
577578
'professionalDesignation': '',
578579
'suffix': 'SR',
579580
'nameIdentifier': '00002'},
580-
action='unordered_iterable_item_removed')]
581+
action='unordered_iterable_item_removed',
582+
type=dict),
583+
]
581584

582585
preserved_flat_dict_list = copy.deepcopy(flat_rows_list) # Use this later for assert comparison
583586

@@ -1405,13 +1408,13 @@ def test_list_ignore_order_various_deltas2(self):
14051408

14061409
flat_result1 = delta1.to_flat_rows()
14071410
flat_expected1 = [
1408-
{'path': [0], 'value': 7, 'action': 'unordered_iterable_item_added'},
1409-
{'path': [6], 'value': 8, 'action': 'unordered_iterable_item_added'},
1410-
{'path': [1], 'value': 4, 'action': 'unordered_iterable_item_added'},
1411-
{'path': [2], 'value': 4, 'action': 'unordered_iterable_item_added'},
1412-
{'path': [5], 'value': 4, 'action': 'unordered_iterable_item_added'},
1413-
{'path': [6], 'value': 6, 'action': 'unordered_iterable_item_removed'},
1414-
{'path': [0], 'value': 5, 'action': 'unordered_iterable_item_removed'},
1411+
{'path': [0], 'value': 7, 'action': 'unordered_iterable_item_added', 'type': int},
1412+
{'path': [6], 'value': 8, 'action': 'unordered_iterable_item_added', 'type': int},
1413+
{'path': [1], 'value': 4, 'action': 'unordered_iterable_item_added', 'type': int},
1414+
{'path': [2], 'value': 4, 'action': 'unordered_iterable_item_added', 'type': int},
1415+
{'path': [5], 'value': 4, 'action': 'unordered_iterable_item_added', 'type': int},
1416+
{'path': [6], 'value': 6, 'action': 'unordered_iterable_item_removed', 'type': int},
1417+
{'path': [0], 'value': 5, 'action': 'unordered_iterable_item_removed', 'type': int},
14151418
]
14161419
flat_expected1 = [FlatDeltaRow(**i) for i in flat_expected1]
14171420
assert flat_expected1 == flat_result1
@@ -1422,11 +1425,11 @@ def test_list_ignore_order_various_deltas2(self):
14221425

14231426
flat_result2 = delta2.to_flat_rows()
14241427
flat_expected2 = [
1425-
{'path': [1], 'value': 4, 'action': 'unordered_iterable_item_added'},
1426-
{'path': [2], 'value': 4, 'action': 'unordered_iterable_item_added'},
1427-
{'path': [5], 'value': 4, 'action': 'unordered_iterable_item_added'},
1428-
{'path': [6], 'action': 'values_changed', 'value': 7},
1429-
{'path': [0], 'action': 'values_changed', 'value': 8},
1428+
{'path': [1], 'value': 4, 'action': 'unordered_iterable_item_added', 'type': int},
1429+
{'path': [2], 'value': 4, 'action': 'unordered_iterable_item_added', 'type': int},
1430+
{'path': [5], 'value': 4, 'action': 'unordered_iterable_item_added', 'type': int},
1431+
{'path': [6], 'action': 'values_changed', 'value': 7, 'type': int},
1432+
{'path': [0], 'action': 'values_changed', 'value': 8, 'type': int},
14301433
]
14311434
flat_expected2 = [FlatDeltaRow(**i) for i in flat_expected2]
14321435
assert flat_expected2 == flat_result2
@@ -1565,7 +1568,7 @@ def test_apply_delta_to_incompatible_object6_value_change(self):
15651568
assert [] == t4
15661569

15671570
flat_result2 = delta2.to_flat_rows()
1568-
flat_expected2 = [{'path': [1, 2, 0], 'action': 'values_changed', 'value': 5}]
1571+
flat_expected2 = [{'path': [1, 2, 0], 'action': 'values_changed', 'value': 5, 'type': int}]
15691572
flat_expected2 = [FlatDeltaRow(**i) for i in flat_expected2]
15701573

15711574
assert flat_expected2 == flat_result2
@@ -1575,7 +1578,7 @@ def test_apply_delta_to_incompatible_object6_value_change(self):
15751578

15761579
delta3 = Delta(diff, raise_errors=False, bidirectional=True)
15771580
flat_result3 = delta3.to_flat_rows()
1578-
flat_expected3 = [{'path': [1, 2, 0], 'action': 'values_changed', 'value': 5, 'old_value': 4}]
1581+
flat_expected3 = [{'path': [1, 2, 0], 'action': 'values_changed', 'value': 5, 'old_value': 4, 'type': int, 'old_type': int}]
15791582
flat_expected3 = [FlatDeltaRow(**i) for i in flat_expected3]
15801583

15811584
assert flat_expected3 == flat_result3
@@ -1685,7 +1688,7 @@ def test_delta_to_dict(self):
16851688
assert expected == result
16861689

16871690
flat_result = delta.to_flat_rows()
1688-
flat_expected = [{'action': 'unordered_iterable_item_removed', 'path': [2], 'value': 'B'}]
1691+
flat_expected = [{'action': 'unordered_iterable_item_removed', 'path': [2], 'value': 'B', 'type': str}]
16891692
flat_expected = [FlatDeltaRow(**i) for i in flat_expected]
16901693

16911694
assert flat_expected == flat_result
@@ -1766,10 +1769,10 @@ def test_delta_set_in_objects(self):
17661769
delta = Delta(DeepDiff(t1, t2))
17671770
flat_result = delta.to_flat_rows()
17681771
flat_expected = [
1769-
{'path': [0, 1], 'value': 10, 'action': 'set_item_added'},
1770-
{'path': [0, 0], 'action': 'values_changed', 'value': 2},
1771-
{'path': [0, 1], 'value': 'A', 'action': 'set_item_removed'},
1772-
{'path': [0, 1], 'value': 'C', 'action': 'set_item_added'},
1772+
{'path': [0, 1], 'value': 10, 'action': 'set_item_added', 'type': int},
1773+
{'path': [0, 0], 'action': 'values_changed', 'value': 2, 'type': int},
1774+
{'path': [0, 1], 'value': 'A', 'action': 'set_item_removed', 'type': str},
1775+
{'path': [0, 1], 'value': 'C', 'action': 'set_item_added', 'type': str},
17731776
]
17741777
flat_expected = [FlatDeltaRow(**i) for i in flat_expected]
17751778

@@ -1885,11 +1888,11 @@ def test_compare_func_with_duplicates_removed(self):
18851888

18861889
flat_result = delta.to_flat_rows()
18871890
flat_expected = [
1888-
{'path': [2], 'value': {'id': 1, 'val': 3}, 'action': 'iterable_item_removed'},
1889-
{'path': [0], 'value': {'id': 1, 'val': 3}, 'action': 'iterable_item_removed'},
1890-
{'path': [3], 'value': {'id': 3, 'val': 3}, 'action': 'iterable_item_removed'},
1891-
{'path': [0], 'action': 'iterable_item_moved', 'value': {'id': 1, 'val': 3}, 'new_path': [2]},
1892-
{'path': [3], 'action': 'iterable_item_moved', 'value': {'id': 3, 'val': 3}, 'new_path': [0]},
1891+
{'path': [2], 'value': {'id': 1, 'val': 3}, 'action': 'iterable_item_removed', 'type': dict},
1892+
{'path': [0], 'value': {'id': 1, 'val': 3}, 'action': 'iterable_item_removed', 'type': dict},
1893+
{'path': [3], 'value': {'id': 3, 'val': 3}, 'action': 'iterable_item_removed', 'type': dict},
1894+
{'path': [0], 'action': 'iterable_item_moved', 'value': {'id': 1, 'val': 3}, 'new_path': [2], 'type': dict},
1895+
{'path': [3], 'action': 'iterable_item_moved', 'value': {'id': 3, 'val': 3}, 'new_path': [0], 'type': dict},
18931896
]
18941897
flat_expected = [FlatDeltaRow(**i) for i in flat_expected]
18951898

@@ -2289,11 +2292,13 @@ def test_subtract_delta_made_from_flat_dicts1(self):
22892292
expected_flat_dicts = [{
22902293
'path': ['field_name1', 0],
22912294
'value': 'xxx',
2292-
'action': 'iterable_item_removed'
2295+
'action': 'iterable_item_removed',
2296+
'type': str,
22932297
}, {
22942298
'path': ['field_name1', 1],
22952299
'value': 'yyy',
2296-
'action': 'iterable_item_removed'
2300+
'action': 'iterable_item_removed',
2301+
'type': str,
22972302
}]
22982303
expected_flat_dicts = [FlatDeltaRow(**i) for i in expected_flat_dicts]
22992304

@@ -2318,11 +2323,13 @@ def test_subtract_delta_made_from_flat_dicts2(self):
23182323
expected_flat_dicts = [{
23192324
'path': ['field_name1', 0],
23202325
'value': 'xxx',
2321-
'action': 'iterable_item_added'
2326+
'action': 'iterable_item_added',
2327+
'type': str,
23222328
}, {
23232329
'path': ['field_name1', 1],
23242330
'value': 'yyy',
2325-
'action': 'iterable_item_added'
2331+
'action': 'iterable_item_added',
2332+
'type': str,
23262333
}]
23272334
expected_flat_dicts = [FlatDeltaRow(**i) for i in expected_flat_dicts]
23282335

0 commit comments

Comments
 (0)