-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
412 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ dist | |
doc/_build | ||
*.egg-info | ||
.idea | ||
.venv |
File renamed without changes.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# python-json-pointer - An implementation of the JSON Pointer syntax | ||
# https://github.com/stefankoegl/python-json-pointer | ||
# | ||
# Copyright (c) 2011 Stefan Kögl <[email protected]> | ||
# All rights reserved. | ||
# | ||
# Redistribution and use in source and binary forms, with or without | ||
# modification, are permitted provided that the following conditions | ||
# are met: | ||
# | ||
# 1. Redistributions of source code must retain the above copyright | ||
# 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. | ||
# 3. The name of the author may not be used to endorse or promote products | ||
# 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 | ||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
# | ||
|
||
""" Identify specific nodes in a JSON document (RFC 6901) """ | ||
from .jsonpointer import JsonPointerException, JsonPointer, resolve_pointer, set_pointer, EndOfList | ||
|
||
try: | ||
from importlib import metadata | ||
except ImportError: # for Python < 3.8 | ||
import importlib_metadata as metadata # type: ignore | ||
|
||
# Will be parsed by setup.py to determine package metadata | ||
jsonpointer_metadata = metadata.metadata("jsonpointer") | ||
__author__ = jsonpointer_metadata["Author"] | ||
__version__ = metadata.version("jsonpointer") | ||
__website__ = jsonpointer_metadata["Home-page"] | ||
__license__ = jsonpointer_metadata["License"] | ||
|
||
__all__ = [ | ||
"resolve_pointer", | ||
"set_pointer", | ||
"JsonPointerException", | ||
"JsonPointer", | ||
"EndOfList", | ||
"__author__", | ||
"__version__", | ||
"__website__", | ||
"__license__", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,3 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# python-json-pointer - An implementation of the JSON Pointer syntax | ||
# https://github.com/stefankoegl/python-json-pointer | ||
# | ||
# Copyright (c) 2011 Stefan Kögl <[email protected]> | ||
# All rights reserved. | ||
# | ||
# Redistribution and use in source and binary forms, with or without | ||
# modification, are permitted provided that the following conditions | ||
# are met: | ||
# | ||
# 1. Redistributions of source code must retain the above copyright | ||
# 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. | ||
# 3. The name of the author may not be used to endorse or promote products | ||
# 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 | ||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
# | ||
|
||
""" Identify specific nodes in a JSON document (RFC 6901) """ | ||
|
||
# Will be parsed by setup.py to determine package metadata | ||
__author__ = 'Stefan Kögl <[email protected]>' | ||
__version__ = '3.0.0' | ||
__website__ = 'https://github.com/stefankoegl/python-json-pointer' | ||
__license__ = 'Modified BSD License' | ||
|
||
import copy | ||
import re | ||
from collections.abc import Mapping, Sequence | ||
|
@@ -73,7 +33,7 @@ def set_pointer(doc, pointer, value, inplace=True): | |
|
||
|
||
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' }}, 'a%20b': 1, 'c d': 2} | ||
|
@@ -113,7 +73,7 @@ def resolve_pointer(doc, pointer, default=_nothing): | |
|
||
|
||
def pairwise(iterable): | ||
""" Transforms a list to a list of tuples of adjacent items | ||
"""Transforms a list to a list of tuples of adjacent items | ||
s -> (s0,s1), (s1,s2), (s2, s3), ... | ||
|
@@ -143,29 +103,29 @@ def __init__(self, list_): | |
self.list_ = list_ | ||
|
||
def __repr__(self): | ||
return '{cls}({lst})'.format(cls=self.__class__.__name__, | ||
lst=repr(self.list_)) | ||
return "{cls}({lst})".format(cls=self.__class__.__name__, lst=repr(self.list_)) | ||
|
||
|
||
class JsonPointer(object): | ||
"""A JSON Pointer that can reference parts of a 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]|~$)') | ||
_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())) | ||
raise JsonPointerException( | ||
"Found invalid escape {}".format(invalid_escape.group()) | ||
) | ||
|
||
parts = pointer.split('/') | ||
if parts.pop(0) != '': | ||
raise JsonPointerException('Location must start with /') | ||
parts = pointer.split("/") | ||
if parts.pop(0) != "": | ||
raise JsonPointerException("Location must start with /") | ||
|
||
parts = [unescape(part) for part in parts] | ||
self.parts = parts | ||
|
@@ -203,15 +163,15 @@ def set(self, doc, value, inplace=True): | |
|
||
if len(self.parts) == 0: | ||
if inplace: | ||
raise JsonPointerException('Cannot set root in place') | ||
raise JsonPointerException("Cannot set root in place") | ||
return value | ||
|
||
if not inplace: | ||
doc = copy.deepcopy(doc) | ||
|
||
(parent, part) = self.to_last(doc) | ||
|
||
if isinstance(parent, Sequence) and part == '-': | ||
if isinstance(parent, Sequence) and part == "-": | ||
parent.append(value) | ||
else: | ||
parent[part] = value | ||
|
@@ -227,37 +187,39 @@ def get_part(cls, doc, part): | |
|
||
elif isinstance(doc, Sequence): | ||
|
||
if part == '-': | ||
if part == "-": | ||
return part | ||
|
||
if not JsonPointer._RE_ARRAY_INDEX.match(str(part)): | ||
raise JsonPointerException("'%s' is not a valid sequence index" % part) | ||
|
||
return int(part) | ||
|
||
elif hasattr(doc, '__getitem__'): | ||
elif hasattr(doc, "__getitem__"): | ||
# Allow indexing via ducktyping | ||
# if the target has defined __getitem__ | ||
return part | ||
|
||
else: | ||
raise JsonPointerException("Document '%s' does not support indexing, " | ||
"must be mapping/sequence or support __getitem__" % type(doc)) | ||
raise JsonPointerException( | ||
"Document '%s' does not support indexing, " | ||
"must be mapping/sequence or support __getitem__" % type(doc) | ||
) | ||
|
||
def get_parts(self): | ||
"""Returns the list of the parts. For example, JsonPointer('/a/b').get_parts() == ['a', 'b']""" | ||
|
||
return self.parts | ||
|
||
def walk(self, doc, part): | ||
""" Walks one step in doc and returns the referenced part """ | ||
"""Walks one step in doc and returns the referenced part""" | ||
|
||
part = JsonPointer.get_part(doc, part) | ||
|
||
assert hasattr(doc, '__getitem__'), "invalid document type %s" % (type(doc),) | ||
assert hasattr(doc, "__getitem__"), "invalid document type %s" % (type(doc),) | ||
|
||
if isinstance(doc, Sequence): | ||
if part == '-': | ||
if part == "-": | ||
return EndOfList(doc) | ||
|
||
try: | ||
|
@@ -274,15 +236,15 @@ def walk(self, doc, part): | |
raise JsonPointerException("member '%s' not found in %s" % (part, doc)) | ||
|
||
def contains(self, ptr): | ||
""" Returns True if self contains the given ptr """ | ||
return self.parts[:len(ptr.parts)] == ptr.parts | ||
"""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) | ||
|
||
def join(self, suffix): | ||
""" Returns a new JsonPointer with the given suffix append to this ptr """ | ||
"""Returns a new JsonPointer with the given suffix append to this ptr""" | ||
if isinstance(suffix, JsonPointer): | ||
suffix_parts = suffix.parts | ||
elif isinstance(suffix, str): | ||
|
@@ -304,7 +266,7 @@ def path(self): | |
>>> ptr = JsonPointer('/~0/0/~1').path == '/~0/0/~1' | ||
""" | ||
parts = [escape(part) for part in self.parts] | ||
return ''.join('/' + part for part in parts) | ||
return "".join("/" + part for part in parts) | ||
|
||
def __eq__(self, other): | ||
"""Compares a pointer to another object | ||
|
@@ -336,13 +298,13 @@ def from_parts(cls, parts): | |
True | ||
""" | ||
parts = [escape(str(part)) for part in parts] | ||
ptr = cls(''.join('/' + part for part in parts)) | ||
ptr = cls("".join("/" + part for part in parts)) | ||
return ptr | ||
|
||
|
||
def escape(s): | ||
return s.replace('~', '~0').replace('/', '~1') | ||
return s.replace("~", "~0").replace("/", "~1") | ||
|
||
|
||
def unescape(s): | ||
return s.replace('~1', '/').replace('~0', '~') | ||
return s.replace("~1", "/").replace("~0", "~") |
Oops, something went wrong.