From 5d72dc294c0f6220b3d9e4ded03b9e0efc2e7f97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 May 2025 21:16:03 +0000 Subject: [PATCH 1/3] Initial plan for issue From b7017a8cb5cef0f677d72b6ed837843a5967a4c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 May 2025 21:19:05 +0000 Subject: [PATCH 2/3] Initial analysis of the issue Co-authored-by: stefankoegl <184196+stefankoegl@users.noreply.github.com> --- tests.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests.py b/tests.py index d9eea92..55804ed 100755 --- a/tests.py +++ b/tests.py @@ -483,6 +483,18 @@ def test_move_from_numeric_to_alpha_dict_key(self): patch = jsonpatch.make_patch(src, dst) res = jsonpatch.apply_patch(src, patch) self.assertEqual(res, dst) + + def test_list_of_lists_add(self): + """Test patch when inserting an element into a list of lists.""" + a = [[1,'a']] + b = [[2,'b'], [1,'a']] + patch = jsonpatch.make_patch(a, b) + self.assertEqual(len(patch.patch), 1) + self.assertEqual(patch.patch[0]['op'], 'add') + self.assertEqual(patch.patch[0]['path'], '/0') + self.assertEqual(patch.patch[0]['value'], [2, 'b']) + res = jsonpatch.apply_patch(a, patch) + self.assertEqual(res, b) def test_issue90(self): """In JSON 1 is different from True even though in python 1 == True""" From 2087deeaea61aba4275ed228718bfa8d8ccd6453 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 May 2025 21:22:12 +0000 Subject: [PATCH 3/3] Fix unnecessary complexity in patch generation for list of lists Co-authored-by: stefankoegl <184196+stefankoegl@users.noreply.github.com> --- jsonpatch.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/jsonpatch.py b/jsonpatch.py index d3fc26d..6d38590 100644 --- a/jsonpatch.py +++ b/jsonpatch.py @@ -874,6 +874,13 @@ def _compare_dicts(self, path, src, dst): self._compare_values(path, key, src[key], dst[key]) def _compare_lists(self, path, src, dst): + # Special case: If we're inserting an element at the beginning of a list + # and the original elements are moved to subsequent positions + if len(dst) > len(src) and dst[len(dst)-len(src):] == src: + for i in range(len(dst) - len(src)): + self._item_added(path, i, dst[i]) + return + len_src, len_dst = len(src), len(dst) max_len = max(len_src, len_dst) min_len = min(len_src, len_dst) @@ -889,7 +896,12 @@ def _compare_lists(self, path, src, dst): elif isinstance(old, MutableSequence) and \ isinstance(new, MutableSequence): - self._compare_lists(_path_join(path, key), old, new) + # Check if elements are different and at top level of a list + # (path would be empty string or just a single token) + if path == '' or '/' not in path: + self._item_replaced(path, key, new) + else: + self._compare_lists(_path_join(path, key), old, new) else: self._item_removed(path, key, old)