summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Kögl <stefan@skoegl.net>2014-03-22 19:02:29 +0100
committerStefan Kögl <stefan@skoegl.net>2014-03-22 19:02:29 +0100
commitef515dc850012384d7ab98dd35968657a34cc227 (patch)
tree4867603e665c40cdbc9940f0b3d4ad98d450129e
parent44b4ca8e60143b6518ecfd9f0fa2832c62e0ce8d (diff)
downloadpython-json-patch-ef515dc850012384d7ab98dd35968657a34cc227.tar.gz
fix make_patch where obj keys contain "/", fixes #26
-rw-r--r--jsonpatch.py20
-rw-r--r--requirements.txt2
-rwxr-xr-xtests.py7
3 files changed, 20 insertions, 9 deletions
diff --git a/jsonpatch.py b/jsonpatch.py
index 5e96f9a..c3e4219 100644
--- a/jsonpatch.py
+++ b/jsonpatch.py
@@ -286,26 +286,29 @@ class JsonPatch(object):
for operation in compare_lists(path, value, other):
yield operation
else:
- yield {'op': 'replace', 'path': '/'.join(path), 'value': other}
+ ptr = JsonPointer.from_parts(path)
+ yield {'op': 'replace', 'path': ptr.path, 'value': other}
def compare_dicts(path, src, dst):
for key in src:
if key not in dst:
- yield {'op': 'remove', 'path': '/'.join(path + [key])}
+ ptr = JsonPointer.from_parts(path + [key])
+ yield {'op': 'remove', 'path': ptr.path}
continue
current = path + [key]
for operation in compare_values(current, src[key], dst[key]):
yield operation
for key in dst:
if key not in src:
+ ptr = JsonPointer.from_parts(path + [key])
yield {'op': 'add',
- 'path': '/'.join(path + [key]),
+ 'path': ptr.path,
'value': dst[key]}
def compare_lists(path, src, dst):
return _compare_lists(path, src, dst)
- return cls(list(compare_dicts([''], src, dst)))
+ return cls(list(compare_dicts([], src, dst)))
def to_string(self):
"""Returns patch set as JSON string."""
@@ -644,14 +647,15 @@ def _compare_left(path, src, left, shift):
end = len(src)
# we need to `remove` elements from list tail to not deal with index shift
for idx in reversed(range(start + shift, end + shift)):
- current = path + [str(idx)]
+ ptr = JsonPointer.from_parts(path + [str(idx)])
yield (
{'op': 'remove',
# yes, there should be any value field, but we'll use it
# to apply `move` optimization a bit later and will remove
# it in _optimize function.
'value': src[idx - shift],
- 'path': '/'.join(current)},
+ 'path': ptr.path,
+ },
shift - 1
)
shift -= 1
@@ -664,9 +668,9 @@ def _compare_right(path, dst, right, shift):
if end == -1:
end = len(dst)
for idx in range(start, end):
- current = path + [str(idx)]
+ ptr = JsonPointer.from_parts(path + [str(idx)])
yield (
- {'op': 'add', 'path': '/'.join(current), 'value': dst[idx]},
+ {'op': 'add', 'path': ptr.path, 'value': dst[idx]},
shift + 1
)
shift += 1
diff --git a/requirements.txt b/requirements.txt
index fa94974..135dc10 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1 @@
-jsonpointer>=1.2
+jsonpointer>=1.3
diff --git a/tests.py b/tests.py
index f60b7c2..ac42a5d 100755
--- a/tests.py
+++ b/tests.py
@@ -333,6 +333,13 @@ class MakePatchTestCase(unittest.TestCase):
res = jsonpatch.apply_patch(src, patch)
self.assertEqual(res, dst)
+ def test_escape(self):
+ src = {"x/y": 1}
+ dst = {"x/y": 2}
+ patch = jsonpatch.make_patch(src, dst)
+ self.assertEqual("""[{"path": "/x~1y", "value": 2, "op": "replace"}]""", str(patch))
+ res = patch.apply(src)
+ self.assertEqual(res, dst)
class InvalidInputTests(unittest.TestCase):