summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Klose <doko@ubuntu.com>2020-01-24 04:25:15 +0100
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2020-01-24 03:46:10 +0000
commit1268af3e20d42ddc47076037055599a9d3b35981 (patch)
tree31163e3fcedfb2a836a6cfd347584899e14ed945
parent7869dcb823f59178c2eb8d38891a4915204d4949 (diff)
parentff618682e949c604bd2e9295a2570adc37b250ec (diff)
Imported using git-ubuntu import.
-rw-r--r--.travis.yml40
-rw-r--r--LICENSE.txt (renamed from COPYING)0
-rw-r--r--MANIFEST.in2
-rw-r--r--README.md12
-rwxr-xr-xbin/jsonpointer29
-rw-r--r--debian/changelog6
-rw-r--r--doc/index.rst2
-rw-r--r--jsonpointer.py216
-rw-r--r--requirements-dev.txt2
-rw-r--r--setup.cfg2
-rw-r--r--setup.py4
-rwxr-xr-xtests.py104
12 files changed, 267 insertions, 152 deletions
diff --git a/.travis.yml b/.travis.yml
index 9065721..f67ebbe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,20 +1,32 @@
language: python
python:
- - "2.6"
- - "2.7"
- - "3.3"
- - "3.4"
- - "3.5"
- - "pypy"
- - "pypy3"
-
+- '2.7'
+- '3.4'
+- '3.5'
+- '3.6'
+- 3.6-dev
+- 3.7-dev
+- nightly
+- pypy
+- pypy3
install:
- - travis_retry pip install coveralls
-
+- travis_retry pip install coveralls
script:
- - coverage run --source=jsonpointer tests.py
-
+- coverage run --source=jsonpointer tests.py
after_script:
- - coveralls
-
+- coveralls
sudo: false
+addons:
+ apt:
+ packages:
+ - pandoc
+before_deploy:
+- pip install -r requirements-dev.txt
+deploy:
+ provider: pypi
+ user: skoegl
+ password:
+ secure: bKET/1sK+uWetPM3opPTt4qHHfZ6bMcjuLGe3Z/EUfNnGazcbDezy9CHJSqofuMXynF3xc8yluEojjfaqos3Ge/Y4o8pdFMY8ABp8KkxMnAJYGtYzbneSHgdgxPKsmdcUMVtIfioqkeNJTJClWUhRikWSlpKZ7TtkK4AmWtKNwc=
+ on:
+ tags: true
+ distributions: sdist bdist_wheel
diff --git a/COPYING b/LICENSE.txt
index 491196d..491196d 100644
--- a/COPYING
+++ b/LICENSE.txt
diff --git a/MANIFEST.in b/MANIFEST.in
index dcb2e4a..0f9b9f6 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
include AUTHORS
-include COPYING
+include LICENSE.txt
include README.md
include tests.py
diff --git a/README.md b/README.md
index cae175d..5248dc8 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,22 @@
-python-json-pointer [![Build Status](https://secure.travis-ci.org/stefankoegl/python-json-pointer.png?branch=master)](https://travis-ci.org/stefankoegl/python-json-pointer) [![Coverage Status](https://coveralls.io/repos/stefankoegl/python-json-pointer/badge.png?branch=master)](https://coveralls.io/r/stefankoegl/python-json-pointer?branch=master) ![Downloads](https://pypip.in/d/jsonpointer/badge.png) ![Version](https://pypip.in/v/jsonpointer/badge.png)
+python-json-pointer
===================
+[![PyPI version](https://img.shields.io/pypi/v/jsonpointer.svg)](https://pypi.python.org/pypi/jsonpointer/)
+[![Supported Python versions](https://img.shields.io/pypi/pyversions/jsonpointer.svg)](https://pypi.python.org/pypi/jsonpointer/)
+[![Build Status](https://travis-ci.org/stefankoegl/python-json-pointer.png?branch=master)](https://travis-ci.org/stefankoegl/python-json-pointer)
+[![Coverage Status](https://coveralls.io/repos/stefankoegl/python-json-pointer/badge.png?branch=master)](https://coveralls.io/r/stefankoegl/python-json-pointer?branch=master)
+
+
Resolve JSON Pointers in Python
-------------------------------
Library to resolve JSON Pointers according to
[RFC 6901](http://tools.ietf.org/html/rfc6901)
-See Sourcecode for Examples
+See source code for examples
* Website: https://github.com/stefankoegl/python-json-pointer
* Repository: https://github.com/stefankoegl/python-json-pointer.git
* Documentation: https://python-json-pointer.readthedocs.org/
* PyPI: https://pypi.python.org/pypi/jsonpointer
-* Travis-CI: https://travis-ci.org/stefankoegl/python-json-pointer
+* Travis CI: https://travis-ci.org/stefankoegl/python-json-pointer
* Coveralls: https://coveralls.io/r/stefankoegl/python-json-pointer
diff --git a/bin/jsonpointer b/bin/jsonpointer
index 1d49fae..d577d01 100755
--- a/bin/jsonpointer
+++ b/bin/jsonpointer
@@ -12,8 +12,17 @@ import argparse
parser = argparse.ArgumentParser(
description='Resolve a JSON pointer on JSON files')
-parser.add_argument('POINTER', type=argparse.FileType('r'),
- help='File containing a JSON pointer expression')
+
+# Accept pointer as argument or as file
+ptr_group = parser.add_mutually_exclusive_group(required=True)
+
+ptr_group.add_argument('-f', '--pointer-file', type=argparse.FileType('r'),
+ nargs='?',
+ help='File containing a JSON pointer expression')
+
+ptr_group.add_argument('POINTER', type=str, nargs='?',
+ help='A JSON pointer expression')
+
parser.add_argument('FILE', type=argparse.FileType('r'), nargs='+',
help='Files for which the pointer should be resolved')
parser.add_argument('--indent', type=int, default=None,
@@ -29,10 +38,24 @@ def main():
sys.exit(1)
+def parse_pointer(args):
+ if args.POINTER:
+ ptr = args.POINTER
+ elif args.pointer_file:
+ ptr = args.pointer_file.read().strip()
+ else:
+ parser.print_usage()
+ sys.exit(1)
+
+ return ptr
+
+
def resolve_files():
""" Resolve a JSON pointer on JSON files """
args = parser.parse_args()
- ptr = json.load(args.POINTER)
+
+ ptr = parse_pointer(args)
+
for f in args.FILE:
doc = json.load(f)
try:
diff --git a/debian/changelog b/debian/changelog
index 28261f8..7e40f22 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-json-pointer (2.0-0ubuntu1) focal; urgency=medium
+
+ * New upstream version.
+
+ -- Matthias Klose <doko@ubuntu.com> Fri, 24 Jan 2020 04:25:15 +0100
+
python-json-pointer (1.10-2) unstable; urgency=medium
[ Ondřej Nový ]
diff --git a/doc/index.rst b/doc/index.rst
index dbdf2c6..53b1dea 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -7,7 +7,7 @@ python-json-pointer
===================
*python-json-pointer* is a Python library for resolving JSON pointers (`RFC
-6901 <http://tools.ietf.org/html/rfc6901>`_). Python 2.6, 2.7, 3.2, 3.3
+6901 <http://tools.ietf.org/html/rfc6901>`_). Python 2.7, 3.4+
and PyPy are supported.
**Contents**
diff --git a/jsonpointer.py b/jsonpointer.py
index eea100c..1ef908a 100644
--- a/jsonpointer.py
+++ b/jsonpointer.py
@@ -11,12 +11,12 @@
# are met:
#
# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
+# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
-# derived from this software without specific prior written permission.
+# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -30,63 +30,66 @@
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
-from __future__ import unicode_literals
-
""" Identify specific nodes in a JSON document (RFC 6901) """
-try:
- from collections.abc import Mapping, Sequence
-except ImportError:
- from collections import Mapping, Sequence
+from __future__ import unicode_literals
# Will be parsed by setup.py to determine package metadata
__author__ = 'Stefan Kögl <stefan@skoegl.net>'
-__version__ = '1.10'
+__version__ = '2.0'
__website__ = 'https://github.com/stefankoegl/python-json-pointer'
__license__ = 'Modified BSD License'
try:
- from urllib import unquote
from itertools import izip
str = unicode
-except ImportError: # Python 3
- from urllib.parse import unquote
+except ImportError: # Python 3
izip = zip
+try:
+ from collections.abc import Mapping, Sequence
+except ImportError: # Python 3
+ from collections import Mapping, Sequence
+
from itertools import tee
import re
import copy
-# array indices must not contain leading zeros, signs, spaces, decimals, etc
-RE_ARRAY_INDEX=re.compile('0|[1-9][0-9]*$')
-
+_nothing = object()
-class JsonPointerException(Exception):
- pass
+def set_pointer(doc, pointer, value, inplace=True):
+ """Resolves pointer against doc and sets the value of the target within doc.
-class EndOfList(object):
- """ Result of accessing element "-" of a list """
+ With inplace set to true, doc is modified as long as pointer is not the
+ root.
- def __init__(self, list_):
- self.list_ = list_
+ >>> obj = {'foo': {'anArray': [ {'prop': 44}], 'another prop': {'baz': 'A string' }}}
+ >>> set_pointer(obj, '/foo/anArray/0/prop', 55) == \
+ {'foo': {'another prop': {'baz': 'A string'}, 'anArray': [{'prop': 55}]}}
+ True
- def __repr__(self):
- return '{cls}({lst})'.format(cls=self.__class__.__name__,
- lst=repr(self.list_))
+ >>> set_pointer(obj, '/foo/yet another prop', 'added prop') == \
+ {'foo': {'another prop': {'baz': 'A string'}, 'yet another prop': 'added prop', 'anArray': [{'prop': 55}]}}
+ True
+ >>> obj = {'foo': {}}
+ >>> set_pointer(obj, '/foo/a%20b', 'x') == \
+ {'foo': {'a%20b': 'x' }}
+ True
+ """
-_nothing = object()
+ pointer = JsonPointer(pointer)
+ return pointer.set(doc, value, inplace)
def resolve_pointer(doc, pointer, default=_nothing):
- """
- Resolves pointer against doc and returns the referenced object
+ """ Resolves pointer against doc and returns the referenced object
- >>> obj = {"foo": {"anArray": [ {"prop": 44}], "another prop": {"baz": "A string" }}}
+ >>> obj = {'foo': {'anArray': [ {'prop': 44}], 'another prop': {'baz': 'A string' }}, 'a%20b': 1, 'c d': 2}
>>> resolve_pointer(obj, '') == obj
True
@@ -94,10 +97,10 @@ def resolve_pointer(doc, pointer, default=_nothing):
>>> resolve_pointer(obj, '/foo') == obj['foo']
True
- >>> resolve_pointer(obj, '/foo/another%20prop') == obj['foo']['another prop']
+ >>> resolve_pointer(obj, '/foo/another prop') == obj['foo']['another prop']
True
- >>> resolve_pointer(obj, '/foo/another%20prop/baz') == obj['foo']['another prop']['baz']
+ >>> resolve_pointer(obj, '/foo/another prop/baz') == obj['foo']['another prop']['baz']
True
>>> resolve_pointer(obj, '/foo/anArray/0') == obj['foo']['anArray'][0]
@@ -106,50 +109,83 @@ def resolve_pointer(doc, pointer, default=_nothing):
>>> resolve_pointer(obj, '/some/path', None) == None
True
+ >>> resolve_pointer(obj, '/a b', None) == None
+ True
+
+ >>> resolve_pointer(obj, '/a%20b') == 1
+ True
+
+ >>> resolve_pointer(obj, '/c d') == 2
+ True
+
+ >>> resolve_pointer(obj, '/c%20d', None) == None
+ True
"""
pointer = JsonPointer(pointer)
return pointer.resolve(doc, default)
-def set_pointer(doc, pointer, value, inplace=True):
- """
- Resolves pointer against doc and sets the value of the target within doc.
- With inplace set to true, doc is modified as long as pointer is not the
- root.
+def pairwise(iterable):
+ """ Transforms a list to a list of tuples of adjacent items
- >>> obj = {"foo": {"anArray": [ {"prop": 44}], "another prop": {"baz": "A string" }}}
+ s -> (s0,s1), (s1,s2), (s2, s3), ...
- >>> set_pointer(obj, '/foo/anArray/0/prop', 55) == \
- {'foo': {'another prop': {'baz': 'A string'}, 'anArray': [{'prop': 55}]}}
- True
+ >>> list(pairwise([]))
+ []
- >>> set_pointer(obj, '/foo/yet%20another%20prop', 'added prop') == \
- {'foo': {'another prop': {'baz': 'A string'}, 'yet another prop': 'added prop', 'anArray': [{'prop': 55}]}}
- True
+ >>> list(pairwise([1]))
+ []
+ >>> list(pairwise([1, 2, 3, 4]))
+ [(1, 2), (2, 3), (3, 4)]
"""
+ a, b = tee(iterable)
+ for _ in b:
+ break
+ return izip(a, b)
- pointer = JsonPointer(pointer)
- return pointer.set(doc, value, inplace)
+
+class JsonPointerException(Exception):
+ pass
+
+
+class EndOfList(object):
+ """Result of accessing element "-" of a list"""
+
+ def __init__(self, list_):
+ self.list_ = list_
+
+ def __repr__(self):
+ return '{cls}({lst})'.format(cls=self.__class__.__name__,
+ lst=repr(self.list_))
class JsonPointer(object):
- """ A JSON Pointer that can reference parts of an JSON document """
+ """A JSON Pointer that can reference parts of an JSON document"""
+
+ # Array indices must not contain:
+ # leading zeros, signs, spaces, decimals, etc
+ _RE_ARRAY_INDEX = re.compile('0|[1-9][0-9]*$')
+ _RE_INVALID_ESCAPE = re.compile('(~[^01]|~$)')
def __init__(self, pointer):
+
+ # validate escapes
+ invalid_escape = self._RE_INVALID_ESCAPE.search(pointer)
+ if invalid_escape:
+ raise JsonPointerException('Found invalid escape {}'.format(
+ invalid_escape.group()))
+
parts = pointer.split('/')
if parts.pop(0) != '':
raise JsonPointerException('location must starts with /')
- parts = map(unquote, parts)
- parts = [part.replace('~1', '/') for part in parts]
- parts = [part.replace('~0', '~') for part in parts]
+ parts = [unescape(part) for part in parts]
self.parts = parts
-
def to_last(self, doc):
- """ Resolves ptr until the last step, returns (sub-doc, last-step) """
+ """Resolves ptr until the last step, returns (sub-doc, last-step)"""
if not self.parts:
return doc, None
@@ -159,7 +195,6 @@ class JsonPointer(object):
return doc, self.get_part(doc, self.parts[-1])
-
def resolve(self, doc, default=_nothing):
"""Resolves the pointer against doc and returns the referenced object"""
@@ -175,11 +210,10 @@ class JsonPointer(object):
return doc
-
get = resolve
def set(self, doc, value, inplace=True):
- """ Resolve the pointer against the doc and replace the target with value. """
+ """Resolve the pointer against the doc and replace the target with value."""
if len(self.parts) == 0:
if inplace:
@@ -195,7 +229,7 @@ class JsonPointer(object):
return doc
def get_part(self, doc, part):
- """ Returns the next step in the correct type """
+ """Returns the next step in the correct type"""
if isinstance(doc, Mapping):
return part
@@ -205,18 +239,19 @@ class JsonPointer(object):
if part == '-':
return part
- if not RE_ARRAY_INDEX.match(str(part)):
- raise JsonPointerException("'%s' is not a valid list index" % (part, ))
+ if not self._RE_ARRAY_INDEX.match(str(part)):
+ raise JsonPointerException("'%s' is not a valid sequence index" % part)
return int(part)
elif hasattr(doc, '__getitem__'):
- # Allow indexing via ducktyping if the target has defined __getitem__
+ # Allow indexing via ducktyping
+ # if the target has defined __getitem__
return part
else:
raise JsonPointerException("Document '%s' does not support indexing, "
- "must be dict/list or support __getitem__" % type(doc))
+ "must be mapping/sequence or support __getitem__" % type(doc))
def walk(self, doc, part):
@@ -224,17 +259,9 @@ class JsonPointer(object):
part = self.get_part(doc, part)
- assert (type(doc) in (dict, list) or hasattr(doc, '__getitem__')), "invalid document type %s" % (type(doc),)
-
- if isinstance(doc, Mapping):
- try:
- return doc[part]
-
- except KeyError:
- raise JsonPointerException("member '%s' not found in %s" % (part, doc))
-
- elif isinstance(doc, Sequence):
+ assert hasattr(doc, '__getitem__'), "invalid document type %s" % (type(doc),)
+ if isinstance(doc, Sequence):
if part == '-':
return EndOfList(doc)
@@ -244,72 +271,61 @@ class JsonPointer(object):
except IndexError:
raise JsonPointerException("index '%s' is out of bounds" % (part, ))
- else:
- # Object supports __getitem__, assume custom indexing
+ # Else the object is a mapping or supports __getitem__(so assume custom indexing)
+ try:
return doc[part]
+ except KeyError:
+ raise JsonPointerException("member '%s' not found in %s" % (part, doc))
+
+
def contains(self, ptr):
- """Returns True if self contains the given ptr"""
+ """ Returns True if self contains the given ptr """
return self.parts[:len(ptr.parts)] == ptr.parts
def __contains__(self, item):
- """Returns True if self contains the given ptr"""
+ """ Returns True if self contains the given ptr """
return self.contains(item)
@property
def path(self):
- """ Returns the string representation of the pointer
+ """Returns the string representation of the pointer
>>> ptr = JsonPointer('/~0/0/~1').path == '/~0/0/~1'
"""
- parts = [part.replace('~', '~0') for part in self.parts]
- parts = [part.replace('/', '~1') for part in parts]
+ parts = [escape(part) for part in self.parts]
return ''.join('/' + part for part in parts)
def __eq__(self, other):
- """ compares a pointer to another object
+ """Compares a pointer to another object
Pointers can be compared by comparing their strings (or splitted
strings), because no two different parts can point to the same
- structure in an object (eg no different number representations) """
+ structure in an object (eg no different number representations)
+ """
if not isinstance(other, JsonPointer):
return False
return self.parts == other.parts
-
def __hash__(self):
return hash(tuple(self.parts))
@classmethod
def from_parts(cls, parts):
- """ Constructs a JsonPointer from a list of (unescaped) paths
+ """Constructs a JsonPointer from a list of (unescaped) paths
>>> JsonPointer.from_parts(['a', '~', '/', 0]).path == '/a/~0/~1/0'
True
"""
- parts = [str(part) for part in parts]
- parts = [part.replace('~', '~0') for part in parts]
- parts = [part.replace('/', '~1') for part in parts]
+ parts = [escape(str(part)) for part in parts]
ptr = cls(''.join('/' + part for part in parts))
return ptr
+def escape(s):
+ return s.replace('~', '~0').replace('/', '~1')
-def pairwise(iterable):
- """ s -> (s0,s1), (s1,s2), (s2, s3), ...
-
- >>> list(pairwise([]))
- []
-
- >>> list(pairwise([1]))
- []
-
- >>> list(pairwise([1, 2, 3, 4]))
- [(1, 2), (2, 3), (3, 4)]
- """
- a, b = tee(iterable)
- for _ in b:
- break
- return izip(a, b)
+def unescape(s):
+ return s.replace('~1', '/').replace('~0', '~')
diff --git a/requirements-dev.txt b/requirements-dev.txt
index fd0fd6c..0dc8f0c 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,2 +1,2 @@
wheel
-pandoc==1.0.0-alpha.3
+pypandoc==1.4
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..2a9acf1
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1
diff --git a/setup.py b/setup.py
index 2c65e44..21660f5 100644
--- a/setup.py
+++ b/setup.py
@@ -42,12 +42,11 @@ CLASSIFIERS = [
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Libraries',
@@ -65,4 +64,5 @@ setup(name=PACKAGE,
py_modules=MODULES,
scripts=['bin/jsonpointer'],
classifiers=CLASSIFIERS,
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
)
diff --git a/tests.py b/tests.py
index cf5c61a..54ca436 100755
--- a/tests.py
+++ b/tests.py
@@ -10,6 +10,7 @@ import copy
from jsonpointer import resolve_pointer, EndOfList, JsonPointerException, \
JsonPointer, set_pointer
+
class SpecificationTests(unittest.TestCase):
""" Tests all examples from the JSON Pointer specification """
@@ -73,6 +74,7 @@ class SpecificationTests(unittest.TestCase):
new_ptr = JsonPointer.from_parts(parts)
self.assertEqual(ptr, new_ptr)
+
class ComparisonTests(unittest.TestCase):
def setUp(self):
@@ -108,7 +110,6 @@ class ComparisonTests(unittest.TestCase):
self.assertTrue(self.ptr1 in self.ptr1)
self.assertFalse(self.ptr3 in self.ptr1)
-
class WrongInputTests(unittest.TestCase):
def test_no_start_slash(self):
@@ -125,6 +126,12 @@ class WrongInputTests(unittest.TestCase):
doc = [0, 1, 2]
self.assertRaises(JsonPointerException, resolve_pointer, doc, '/10')
+ def test_trailing_escape(self):
+ self.assertRaises(JsonPointerException, JsonPointer, '/foo/bar~')
+
+ def test_invalid_escape(self):
+ self.assertRaises(JsonPointerException, JsonPointer, '/foo/bar~2')
+
class ToLastTests(unittest.TestCase):
@@ -192,43 +199,53 @@ class SetTests(unittest.TestCase):
self.assertRaises(JsonPointerException, set_pointer, doc, "", 9)
+
class AltTypesTests(unittest.TestCase):
- def test_alttypes(self):
- JsonPointer.alttypes = True
+ class Node(object):
+ def __init__(self, name, parent=None):
+ self.name = name
+ self.parent = parent
+ self.left = None
+ self.right = None
+
+ def set_left(self, node):
+ node.parent = self
+ self.left = node
- class Node(object):
- def __init__(self, name, parent=None):
- self.name = name
- self.parent = parent
- self.left = None
- self.right = None
+ def set_right(self, node):
+ node.parent = self
+ self.right = node
- def set_left(self, node):
- node.parent = self
- self.left = node
+ def __getitem__(self, key):
+ if key == 'left':
+ return self.left
+ if key == 'right':
+ return self.right
- def set_right(self, node):
- node.parent = self
- self.right = node
+ raise KeyError("Only left and right supported")
- def __getitem__(self, key):
- if key == 'left':
- return self.left
- if key == 'right':
- return self.right
+ def __setitem__(self, key, val):
+ if key == 'left':
+ return self.set_left(val)
+ if key == 'right':
+ return self.set_right(val)
- raise KeyError("Only left and right supported")
+ raise KeyError("Only left and right supported: %s" % key)
- def __setitem__(self, key, val):
- if key == 'left':
- return self.set_left(val)
- if key == 'right':
- return self.set_right(val)
+ class mdict(object):
+ def __init__(self, d):
+ self._d = d
+ def __getitem__(self, item):
+ return self._d[item]
- raise KeyError("Only left and right supported: %s" % key)
+ mdict = mdict({'root': {'1': {'2': '3'}}})
+ Node = Node
+ def test_alttypes(self):
+ Node = self.Node
+
root = Node('root')
root.set_left(Node('a'))
root.left.set_left(Node('aa'))
@@ -249,6 +266,39 @@ class AltTypesTests(unittest.TestCase):
set_pointer(root, '/left/right', Node('AB'))
self.assertEqual(resolve_pointer(root, '/left/right').name, 'AB')
+ def test_mock_dict_sanity(self):
+ doc = self.mdict
+ default = None
+
+ # TODO: Generate this automatically for any given object
+ path_to_expected_value = {
+ '/root/1': {'2': '3'},
+ '/root': {'1': {'2': '3'}},
+ '/root/1/2': '3',
+ }
+
+ for path, expected_value in iter(path_to_expected_value.items()):
+ self.assertEqual(resolve_pointer(doc, path, default), expected_value)
+
+ def test_mock_dict_returns_default(self):
+ doc = self.mdict
+ default = None
+
+ path_to_expected_value = {
+ '/foo': default,
+ '/x/y/z/d': default
+ }
+
+ for path, expected_value in iter(path_to_expected_value.items()):
+ self.assertEqual(resolve_pointer(doc, path, default), expected_value)
+
+ def test_mock_dict_raises_key_error(self):
+ doc = self.mdict
+ self.assertRaises(JsonPointerException, resolve_pointer, doc, '/foo')
+ self.assertRaises(JsonPointerException, resolve_pointer, doc, '/root/1/2/3/4')
+
+
+
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(SpecificationTests))
suite.addTest(unittest.makeSuite(ComparisonTests))