Skip to content

Nested items that move with iterable_compare_func are not properly tracked or replayed #540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dtorres-sf opened this issue Apr 18, 2025 · 1 comment

Comments

@dtorres-sf
Copy link
Contributor

I will be opening a PR momentarily with a suggested fix.

Describe the bug
If you have nested arrays of objects and they both the top level and nested level move positions, you will not get the correct diff and delta objects.

To Reproduce
Example:

        t1 = [
            {
                'id': 1,
                'val': 1,
                "nested": [
                    {"id": 1, "val": 1},
                    {"id": 2, "val": 2},
                ]
            },
            {
                'id': 2,
                'val': 2
            },
            {
                'id': 1,
                'val': 3
            },
            {
                'id': 3,
                'val': 3
            }
        ]
        t2 = [
            {
                'id': 3,
                'val': 3
            },
            {
                'id': 2,
                'val': 2
            },
            {
                'id': 1,
                'val': 3,
                "nested":[
                    {
                        "id": 2,
                        "val": 3
                    },
                ]
            }
        ]
        ddiff = DeepDiff(t1, t2, iterable_compare_func=self.compare_func, verbose_level=2)

Expected behavior

        expected = {
            "iterable_item_removed": {
                "root[2]": {
                    "id": 1,
                    "val": 3
                },

                "root[2]['nested'][0]": {
                    "id": 1,
                    "val": 1
                }
            },
            "iterable_item_moved": {
                "root[0]": {
                    "new_path": "root[2]",
                    "value": {
                        "id": 1,
                        "val": 3,
                        "nested": [{"id": 2, "val": 3}, ]
                    },
                },
                "root[0]['nested'][1]": {
                    "new_path": "root[2]['nested'][0]",
                    "value": {
                        "id": 2,
                        "val": 3
                    }
                },
                "root[3]": {
                    "new_path": "root[0]",
                    "value": {
                        "id": 3,
                        "val": 3
                    }
                }
            },
            'values_changed': {
                "root[2]['nested'][0]['val']": {
                    'new_path': "root[0]['nested'][1]['val']",
                    'new_value': 3,
                    'old_value': 2
                },
                "root[2]['val']": {
                    'new_value': 3,
                    'old_value': 1,
                    'new_path': "root[0]['val']"
                }
            },
        }

Actual behavior:

{'iterable_item_moved': {'root[0]': {'new_path': 'root[2]',
                                     'value': {'id': 1,
                                               'nested': [{'id': 2, 'val': 3}],
                                               'val': 3}},
                         "root[2]['nested'][1]": {'new_path': "root[0]['nested'][0]",
                                                  'value': {'id': 2, 'val': 3}},
                         'root[3]': {'new_path': 'root[0]',
                                     'value': {'id': 3, 'val': 3}}},
 'iterable_item_removed': {'root[2]': {'id': 1, 'val': 3},
                           "root[2]['nested'][0]": {'id': 1, 'val': 1}},
 'values_changed': {"root[2]['nested'][0]['val']": {'new_path': "root[0]['nested'][1]['val']",
                                                    'new_value': 3,
                                                    'old_value': 2},
                    "root[2]['val']": {'new_path': "root[0]['val']",
                                       'new_value': 3,
                                       'old_value': 1}}}

The nested item path in iterable_item_moved is incorrect.

OS, DeepDiff version and Python version (please complete the following information):

  • DeepDiff Version 8.4.2

Additional context
I already have a fix with PR incoming.

dtorres-sf added a commit to surefyresystems/deepdiff that referenced this issue Apr 18, 2025
This fixes issue seperman#540. Before this change the reference params were being swapped right after there was a move. This is because the move needed to have the original paths, but child changes needed the new paths. The problem was that nested moves swapped the reference parameters again after the move was recorded. This made the paths inaccurate since the parent did not have the params swapped but the child did.

Instead, we are no longer swapping when building the tree, but rather when we request the paths. The paths will not be swapped for the iterable_item_moved but it will be swapped for all other changes if there was a parent with an iterable_item_moved.
@seperman
Copy link
Owner

seperman commented May 9, 2025

Closing because DeepDiff 8.5.0 is released with your fix!
https://zepworks.com/deepdiff/current/

@seperman seperman closed this as completed May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants