Skip to content

Commit ef515dc

Browse files
committed
fix make_patch where obj keys contain "/", fixes #26
1 parent 44b4ca8 commit ef515dc

File tree

3 files changed

+20
-9
lines changed

3 files changed

+20
-9
lines changed

jsonpatch.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -286,26 +286,29 @@ def compare_values(path, value, other):
286286
for operation in compare_lists(path, value, other):
287287
yield operation
288288
else:
289-
yield {'op': 'replace', 'path': '/'.join(path), 'value': other}
289+
ptr = JsonPointer.from_parts(path)
290+
yield {'op': 'replace', 'path': ptr.path, 'value': other}
290291

291292
def compare_dicts(path, src, dst):
292293
for key in src:
293294
if key not in dst:
294-
yield {'op': 'remove', 'path': '/'.join(path + [key])}
295+
ptr = JsonPointer.from_parts(path + [key])
296+
yield {'op': 'remove', 'path': ptr.path}
295297
continue
296298
current = path + [key]
297299
for operation in compare_values(current, src[key], dst[key]):
298300
yield operation
299301
for key in dst:
300302
if key not in src:
303+
ptr = JsonPointer.from_parts(path + [key])
301304
yield {'op': 'add',
302-
'path': '/'.join(path + [key]),
305+
'path': ptr.path,
303306
'value': dst[key]}
304307

305308
def compare_lists(path, src, dst):
306309
return _compare_lists(path, src, dst)
307310

308-
return cls(list(compare_dicts([''], src, dst)))
311+
return cls(list(compare_dicts([], src, dst)))
309312

310313
def to_string(self):
311314
"""Returns patch set as JSON string."""
@@ -644,14 +647,15 @@ def _compare_left(path, src, left, shift):
644647
end = len(src)
645648
# we need to `remove` elements from list tail to not deal with index shift
646649
for idx in reversed(range(start + shift, end + shift)):
647-
current = path + [str(idx)]
650+
ptr = JsonPointer.from_parts(path + [str(idx)])
648651
yield (
649652
{'op': 'remove',
650653
# yes, there should be any value field, but we'll use it
651654
# to apply `move` optimization a bit later and will remove
652655
# it in _optimize function.
653656
'value': src[idx - shift],
654-
'path': '/'.join(current)},
657+
'path': ptr.path,
658+
},
655659
shift - 1
656660
)
657661
shift -= 1
@@ -664,9 +668,9 @@ def _compare_right(path, dst, right, shift):
664668
if end == -1:
665669
end = len(dst)
666670
for idx in range(start, end):
667-
current = path + [str(idx)]
671+
ptr = JsonPointer.from_parts(path + [str(idx)])
668672
yield (
669-
{'op': 'add', 'path': '/'.join(current), 'value': dst[idx]},
673+
{'op': 'add', 'path': ptr.path, 'value': dst[idx]},
670674
shift + 1
671675
)
672676
shift += 1

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
jsonpointer>=1.2
1+
jsonpointer>=1.3

tests.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,13 @@ def test_use_move_instead_of_add_remove(self):
333333
res = jsonpatch.apply_patch(src, patch)
334334
self.assertEqual(res, dst)
335335

336+
def test_escape(self):
337+
src = {"x/y": 1}
338+
dst = {"x/y": 2}
339+
patch = jsonpatch.make_patch(src, dst)
340+
self.assertEqual("""[{"path": "/x~1y", "value": 2, "op": "replace"}]""", str(patch))
341+
res = patch.apply(src)
342+
self.assertEqual(res, dst)
336343

337344

338345
class InvalidInputTests(unittest.TestCase):

0 commit comments

Comments
 (0)