diff --git a/deepdiff/delta.py b/deepdiff/delta.py index 0ae20fbc..63cd7edb 100644 --- a/deepdiff/delta.py +++ b/deepdiff/delta.py @@ -963,13 +963,6 @@ def _from_flat_dicts(flat_dict_list): return result - def _flatten_iterable_opcodes(self): - result = [] - for path, opcodes in self.diff['_iterable_opcodes']: - for opcode in opcodes: - if opcode.tag == '': - pass - def to_flat_dicts(self, include_action_in_path=False, report_type_changes=True) -> List[FlatDeltaRow]: """ Returns a flat list of actions that is easily machine readable. diff --git a/deepdiff/diff.py b/deepdiff/diff.py index 4212e309..ed5749d9 100755 --- a/deepdiff/diff.py +++ b/deepdiff/diff.py @@ -839,7 +839,9 @@ def _diff_by_forming_pairs_and_comparing_one_by_one( x, notpresent, child_relationship_class=child_relationship_class, - child_relationship_param=i) + child_relationship_param=i, + child_relationship_param2=j, + ) self._report_result('iterable_item_removed', change_level, local_tree=local_tree) elif x is ListItemRemovedOrAdded: # new item added @@ -847,7 +849,9 @@ def _diff_by_forming_pairs_and_comparing_one_by_one( notpresent, y, child_relationship_class=child_relationship_class, - child_relationship_param=j) + child_relationship_param=i, + child_relationship_param2=j, + ) self._report_result('iterable_item_added', change_level, local_tree=local_tree) else: # check if item value has changed @@ -898,8 +902,8 @@ def _diff_by_forming_pairs_and_comparing_one_by_one( x, y, child_relationship_class=child_relationship_class, - child_relationship_param=i - # child_relationship_param=j # wrong + child_relationship_param=i, + child_relationship_param2=j, ) self._diff(next_level, parents_ids_added, local_tree=local_tree) @@ -1339,11 +1343,14 @@ def get_other_pair(hash_value, in_t1=True): other = get_other_pair(hash_value) item_id = id(other.item) index = t2_hashtable[hash_value].indexes[0] if other.item is notpresent else other.indexes[0] + index2 = t2_hashtable[hash_value].indexes[0] change_level = level.branch_deeper( other.item, t2_hashtable[hash_value].item, child_relationship_class=SubscriptableIterableRelationship, - child_relationship_param=index) + child_relationship_param=index, + child_relationship_param2=index2, + ) if other.item is notpresent: self._report_result('iterable_item_added', change_level, local_tree=local_tree) else: @@ -1355,12 +1362,15 @@ def get_other_pair(hash_value, in_t1=True): return # pragma: no cover. This is already covered for addition. other = get_other_pair(hash_value, in_t1=False) item_id = id(other.item) + index = t1_hashtable[hash_value].indexes[0] + index2 = t1_hashtable[hash_value].indexes[0] if other.item is notpresent else other.indexes[0] change_level = level.branch_deeper( t1_hashtable[hash_value].item, other.item, child_relationship_class=SubscriptableIterableRelationship, - child_relationship_param=t1_hashtable[hash_value].indexes[ - 0]) + child_relationship_param=index, + child_relationship_param2=index2, + ) if other.item is notpresent: self._report_result('iterable_item_removed', change_level, local_tree=local_tree) else: diff --git a/tests/test_delta.py b/tests/test_delta.py index 1234bf93..6044f612 100644 --- a/tests/test_delta.py +++ b/tests/test_delta.py @@ -2394,3 +2394,100 @@ def test_delta_flat_rows(self): # the path to the leaf node. delta2 = Delta(flat_rows_list=flat_rows, bidirectional=True, force=True) assert t1 + delta2 == t2 + + def test_flat_dict_and_deeply_nested_dict(self): + beforeImage = [ + { + "usage": "Mailing", + "standardization": "YES", + "primaryIndicator": True, + "addressIdentifier": "Z8PDWBG42YC", + "addressLines": ["871 PHILLIPS FERRY RD"], + }, + { + "usage": "Residence", + "standardization": "YES", + "primaryIndicator": False, + "addressIdentifier": "Z8PDWBG42YC", + "addressLines": ["871 PHILLIPS FERRY RD"], + }, + { + "usage": "Mailing", + "standardization": None, + "primaryIndicator": False, + "addressIdentifier": "MHPP3BY0BYC", + "addressLines": ["871 PHILLIPS FERRY RD", "APT RV92"], + }, + ] + allAfterImage = [ + { + "usage": "Residence", + "standardization": "NO", + "primaryIndicator": False, + "addressIdentifier": "Z8PDWBG42YC", + "addressLines": ["871 PHILLIPS FERRY RD"], + }, + { + "usage": "Mailing", + "standardization": None, + "primaryIndicator": False, + "addressIdentifier": "MHPP3BY0BYC", + "addressLines": ["871 PHILLIPS FERRY RD", "APT RV92"], + }, + { + "usage": "Mailing", + "standardization": "NO", + "primaryIndicator": True, + "addressIdentifier": "Z8PDWBG42YC", + "addressLines": ["871 PHILLIPS FERRY RD"], + }, + ] + + diff = DeepDiff( + beforeImage, + allAfterImage, + ignore_order=True, + report_repetition=True, + ) + reverse_diff = DeepDiff( + allAfterImage, + beforeImage, + ignore_order=True, + report_repetition=True, + ) + delta = Delta( + diff, always_include_values=True, bidirectional=True + ) + reverse_delta = Delta( + reverse_diff, always_include_values=True, bidirectional=True + ) + allAfterImageAgain = beforeImage + delta + diff2 = DeepDiff(allAfterImage, allAfterImageAgain, ignore_order=True) + assert not diff2 + + from pprint import pprint + print("\ndelta.diff") + pprint(delta.diff) + print("\ndelta._get_reverse_diff()") + pprint(delta._get_reverse_diff()) + print("\nreverse_delta.diff") + pprint(reverse_delta.diff) + # import pytest; pytest.set_trace() + beforeImageAgain = allAfterImage - delta + diff3 = DeepDiff(beforeImage, beforeImageAgain, ignore_order=True) + assert not diff3 + + # ------ now let's recreate the delta from flat dicts ------- + + flat_dict_list = delta.to_flat_dicts() + + delta2 = Delta( + flat_dict_list=flat_dict_list, + always_include_values=True, + bidirectional=True, + raise_errors=False, + force=True, + ) + + assert allAfterImage == beforeImage + delta2 + assert beforeImage == allAfterImage - delta2 diff --git a/tests/test_model.py b/tests/test_model.py index cc5390b6..12130e0c 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -3,6 +3,7 @@ import logging import pytest from tests import CustomClass, CustomClassMisleadingRepr +from deepdiff import DeepDiff from deepdiff.model import (DiffLevel, ChildRelationship, DictRelationship, SubscriptableIterableRelationship, AttributeRelationship) @@ -170,6 +171,76 @@ def test_path_when_both_children_empty(self): assert path == 'root' assert down.path(output_format='list') == [] + def test_t2_path_when_nested(self): + t1 = { + "type": "struct", + "fields": [ + {"name": "Competition", "metadata": {}, "nullable": True, "type": "string"}, + {"name": "TeamName", "metadata": {}, "nullable": True, "type": "string"}, + { + "name": "Contents", + "metadata": {}, + "nullable": True, + "type": { + "type": "struct", + "fields": [ + {"name": "Date", "metadata": {}, "nullable": True, "type": "string"}, + {"name": "Player1", "metadata": {}, "nullable": True, "type": "string"} + ] + } + } + ] + } + + t2 = { + "type": "struct", + "fields": [ + {"name": "Competition", "metadata": {}, "nullable": True, "type": "string"}, + {"name": "GlobalId", "metadata": {}, "nullable": True, "type": "string"}, + {"name": "TeamName", "metadata": {}, "nullable": True, "type": "string"}, + { + "name": "Contents", + "metadata": {}, + "nullable": True, + "type": { + "type": "struct", + "fields": [ + {"name": "Date", "metadata": {}, "nullable": True, "type": "string"}, + {"name": "Player1", "metadata": {}, "nullable": True, "type": "string"}, + {"name": "Player2", "metadata": {}, "nullable": True, "type": "string"} + ] + } + } + ] + } + + diff = DeepDiff(t1=t1, t2=t2, ignore_order=True, verbose_level=2, view='tree') + + expected_diff = { + "iterable_item_added": { + "root['fields'][1]": { + "name": "GlobalId", + "metadata": {}, + "nullable": True, + "type": "string", + }, + "root['fields'][2]['type']['fields'][2]": { + "name": "Player2", + "metadata": {}, + "nullable": True, + "type": "string", + }, + } + } + + path = diff['iterable_item_added'][1].path() + assert "root['fields'][2]['type']['fields'][2]" == path + + path_t2 = diff['iterable_item_added'][1].path(use_t2=True) + assert "root['fields'][3]['type']['fields'][2]" == path_t2 + + + def test_repr_short(self): level = self.lowest.verbose_level try: