summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Kögl <stefan@skoegl.net>2022-02-22 10:13:36 +0100
committerGitHub <noreply@github.com>2022-02-22 10:13:36 +0100
commitf8c80b7c0631332c979985f13cc1a803f251c6b7 (patch)
tree8dc471a90a596320a5338638622f6e734f295364
parent896102d605605ec0f48e26bafb54fb591be66ede (diff)
parentd811454192adb18fc3a9aa333fc27e4e48ddd723 (diff)
downloadpython-json-pointer-f8c80b7c0631332c979985f13cc1a803f251c6b7.tar.gz
Merge pull request #49 from benkehoe/master
str/repr, join, and setting - for arrays
-rw-r--r--jsonpointer.py33
-rwxr-xr-xtests.py91
2 files changed, 122 insertions, 2 deletions
diff --git a/jsonpointer.py b/jsonpointer.py
index 53191ef..d9fe0c0 100644
--- a/jsonpointer.py
+++ b/jsonpointer.py
@@ -44,15 +44,17 @@ __license__ = 'Modified BSD License'
try:
from itertools import izip
str = unicode
+ encode_str = lambda u: u.encode("raw_unicode_escape")
except ImportError: # Python 3
izip = zip
+ encode_str = lambda u: u
try:
from collections.abc import Mapping, Sequence
except ImportError: # Python 3
from collections import Mapping, Sequence
-from itertools import tee
+from itertools import tee, chain
import re
import copy
@@ -225,7 +227,11 @@ class JsonPointer(object):
(parent, part) = self.to_last(doc)
- parent[part] = value
+ if isinstance(parent, Sequence) and part == '-':
+ parent.append(value)
+ else:
+ parent[part] = value
+
return doc
@classmethod
@@ -293,6 +299,23 @@ class JsonPointer(object):
""" Returns True if self contains the given ptr """
return self.contains(item)
+ def join(self, suffix):
+ """ Returns a new JsonPointer with the given suffix append to this ptr """
+ if isinstance(suffix, JsonPointer):
+ suffix_parts = suffix.parts
+ elif isinstance(suffix, str):
+ suffix_parts = JsonPointer(suffix).parts
+ else:
+ suffix_parts = suffix
+ try:
+ return JsonPointer.from_parts(chain(self.parts, suffix_parts))
+ except:
+ raise JsonPointerException("Invalid suffix")
+
+ def __truediv__(self, suffix): # Python 3
+ return self.join(suffix)
+ __div__ = __truediv__ # Python 2
+
@property
def path(self):
"""Returns the string representation of the pointer
@@ -318,6 +341,12 @@ class JsonPointer(object):
def __hash__(self):
return hash(tuple(self.parts))
+ def __str__(self):
+ return encode_str(self.path)
+
+ def __repr__(self):
+ return "JsonPointer(" + repr(self.path) + ")"
+
@classmethod
def from_parts(cls, parts):
"""Constructs a JsonPointer from a list of (unescaped) paths
diff --git a/tests.py b/tests.py
index 409990e..dafbe89 100755
--- a/tests.py
+++ b/tests.py
@@ -75,6 +75,50 @@ class SpecificationTests(unittest.TestCase):
new_ptr = JsonPointer.from_parts(parts)
self.assertEqual(ptr, new_ptr)
+ def test_str_and_repr(self):
+ paths = [
+ ("", "", "JsonPointer({u}'')"),
+ ("/foo", "/foo", "JsonPointer({u}'/foo')"),
+ ("/foo/0", "/foo/0", "JsonPointer({u}'/foo/0')"),
+ ("/", "/", "JsonPointer({u}'/')"),
+ ("/a~1b", "/a~1b", "JsonPointer({u}'/a~1b')"),
+ ("/c%d", "/c%d", "JsonPointer({u}'/c%d')"),
+ ("/e^f", "/e^f", "JsonPointer({u}'/e^f')"),
+ ("/g|h", "/g|h", "JsonPointer({u}'/g|h')"),
+ ("/i\\j", "/i\\j", "JsonPointer({u}'/i\\\\j')"),
+ ("/k\"l", "/k\"l", "JsonPointer({u}'/k\"l')"),
+ ("/ ", "/ ", "JsonPointer({u}'/ ')"),
+ ("/m~0n", "/m~0n", "JsonPointer({u}'/m~0n')"),
+ ]
+ for path, ptr_str, ptr_repr in paths:
+ ptr = JsonPointer(path)
+ self.assertEqual(path, ptr.path)
+
+ if sys.version_info[0] == 2:
+ u_str = "u"
+ else:
+ u_str = ""
+ self.assertEqual(ptr_str, str(ptr))
+ self.assertEqual(ptr_repr.format(u=u_str), repr(ptr))
+
+ if sys.version_info[0] == 2:
+ path = "/\xee"
+ ptr_str = b"/\xee"
+ ptr_repr = "JsonPointer(u'/\\xee')"
+ else:
+ path = "/\xee"
+ ptr_str = "/\xee"
+ ptr_repr = "JsonPointer('/\xee')"
+ ptr = JsonPointer(path)
+ self.assertEqual(path, ptr.path)
+
+ self.assertEqual(ptr_str, str(ptr))
+ self.assertEqual(ptr_repr, repr(ptr))
+
+ # should not be unicode in Python 2
+ self.assertIsInstance(str(ptr), str)
+ self.assertIsInstance(repr(ptr), str)
+
def test_parts(self):
paths = [
("", []),
@@ -131,6 +175,42 @@ class ComparisonTests(unittest.TestCase):
self.assertTrue(self.ptr1 in self.ptr1)
self.assertFalse(self.ptr3 in self.ptr1)
+ def test_join(self):
+
+ ptr12a = self.ptr1.join(self.ptr2)
+ self.assertEqual(ptr12a.path, "/a/b/c/a/b")
+
+ ptr12b = self.ptr1.join(self.ptr2.parts)
+ self.assertEqual(ptr12b.path, "/a/b/c/a/b")
+
+ ptr12c = self.ptr1.join(self.ptr2.parts[0:1])
+ self.assertEqual(ptr12c.path, "/a/b/c/a")
+
+ ptr12d = self.ptr1.join("/a/b")
+ self.assertEqual(ptr12d.path, "/a/b/c/a/b")
+
+ ptr12e = self.ptr1.join(["a", "b"])
+ self.assertEqual(ptr12e.path, "/a/b/c/a/b")
+
+ self.assertRaises(JsonPointerException, self.ptr1.join, 0)
+
+ def test_join_magic(self):
+
+ ptr12a = self.ptr1 / self.ptr2
+ self.assertEqual(ptr12a.path, "/a/b/c/a/b")
+
+ ptr12b = self.ptr1 / self.ptr2.parts
+ self.assertEqual(ptr12b.path, "/a/b/c/a/b")
+
+ ptr12c = self.ptr1 / self.ptr2.parts[0:1]
+ self.assertEqual(ptr12c.path, "/a/b/c/a")
+
+ ptr12d = self.ptr1 / "/a/b"
+ self.assertEqual(ptr12d.path, "/a/b/c/a/b")
+
+ ptr12e = self.ptr1 / ["a", "b"]
+ self.assertEqual(ptr12e.path, "/a/b/c/a/b")
+
class WrongInputTests(unittest.TestCase):
def test_no_start_slash(self):
@@ -193,6 +273,12 @@ class SetTests(unittest.TestCase):
newdoc = set_pointer(doc, "/foo/1", "cod", inplace=False)
self.assertEqual(resolve_pointer(newdoc, "/foo/1"), "cod")
+ self.assertEqual(len(doc["foo"]), 2)
+ newdoc = set_pointer(doc, "/foo/-", "xyz", inplace=False)
+ self.assertEqual(resolve_pointer(newdoc, "/foo/2"), "xyz")
+ self.assertEqual(len(doc["foo"]), 2)
+ self.assertEqual(len(newdoc["foo"]), 3)
+
newdoc = set_pointer(doc, "/", 9, inplace=False)
self.assertEqual(resolve_pointer(newdoc, "/"), 9)
@@ -209,6 +295,11 @@ class SetTests(unittest.TestCase):
set_pointer(doc, "/foo/1", "cod")
self.assertEqual(resolve_pointer(doc, "/foo/1"), "cod")
+ self.assertEqual(len(doc["foo"]), 2)
+ set_pointer(doc, "/foo/-", "xyz")
+ self.assertEqual(resolve_pointer(doc, "/foo/2"), "xyz")
+ self.assertEqual(len(doc["foo"]), 3)
+
set_pointer(doc, "/", 9)
self.assertEqual(resolve_pointer(doc, "/"), 9)