diff --git a/jsonpointer.py b/jsonpointer.py index 7963703..0c1a1e0 100644 --- a/jsonpointer.py +++ b/jsonpointer.py @@ -209,10 +209,15 @@ def set(self, doc, value, inplace=True): (parent, part) = self.to_last(doc) - if isinstance(parent, Sequence) and part == '-': - parent.append(value) - else: - parent[part] = value + try: + if isinstance(parent, Sequence) and part == '-': + parent.append(value) + else: + parent[part] = value + except IndexError: + raise JsonPointerException("index '%s' is out of bounds" % (part,)) + except (TypeError, AttributeError): + raise JsonPointerException("Cannot set token '%s' on type %s" % (part, type(parent))) return doc diff --git a/tests.py b/tests.py index 13c0561..981e2fa 100755 --- a/tests.py +++ b/tests.py @@ -271,6 +271,28 @@ def test_path(self): class SetTests(unittest.TestCase): + def test_invalid_assignment_target(self): + targets = ["abc", b"abc", (1, 2), 42, None] + for target in targets: + for token in ["0", "-"]: + for inplace in [True, False]: + for doc, path in [(target, "/" + token), + ({"foo": target}, "/foo/" + token)]: + with self.subTest(doc=doc, path=path, inplace=inplace): + self.assertRaises(JsonPointerException, set_pointer, + doc, path, 42, inplace=inplace) + + def test_assignment_out_of_bounds(self): + for target, token in [([], "0"), ([1, 2], "2"), ([1, 2], "5")]: + for inplace in [True, False]: + for doc, path in [(target, "/" + token), + ({"foo": target}, "/foo/" + token)]: + original = copy.deepcopy(doc) + with self.subTest(doc=doc, path=path, inplace=inplace): + self.assertRaisesRegex(JsonPointerException, "out of bounds", + JsonPointer(path).set, doc, 42, inplace=inplace) + self.assertEqual(doc, original) + def test_set(self): doc = { "foo": ["bar", "baz"],