Skip to content

Commit

Permalink
Migrate to pyproject.toml
Browse files Browse the repository at this point in the history
  • Loading branch information
cunla committed Jul 23, 2024
1 parent f3643ad commit 0583986
Show file tree
Hide file tree
Showing 16 changed files with 412 additions and 189 deletions.
53 changes: 37 additions & 16 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,16 @@ jobs:
with:
ref: ${{ github.ref }}

- name: Set up Python 3.12
uses: actions/setup-python@v5
- name: "Setup Python, Poetry and Dependencies"
uses: dsoftwareinc/setup-python-poetry-action@v1
with:
python-version: 3.12
allow-prereleases: true
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8
python-version: "3.12"
poetry-version: "1.8.3"

- name: Run flake8
shell: bash
run: |
flake8
poetry run flake8
test:
needs: [ lint ]
Expand All @@ -40,19 +37,43 @@ jobs:
fail-fast: false
matrix:
python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11", "3.12" ]
poetry-version: [ "1.8.3" ]

exclude:
- python-version: "3.7"
poetry-version: "1.8.3"
include:
- python-version: "3.7"
poetry-version: "1.5.1"

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5

- name: "Setup Python, Poetry and Dependencies"
uses: dsoftwareinc/setup-python-poetry-action@v1
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install dependencies
poetry-version: ${{ matrix.poetry-version }}

- name: Test
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
poetry install --no-interaction
poetry run python -m unittest
test-with-coverage:
needs: [ test ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: "Setup Python, Poetry and Dependencies"
uses: dsoftwareinc/setup-python-poetry-action@v1
with:
python-version: "3.12"
poetry-version: "1.8.3"

- name: Test
run: |
make coverage
poetry install --no-interaction
poetry run coverage run -m unittest
poetry run coverage report -m
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ dist
doc/_build
*.egg-info
.idea
.venv
3 changes: 0 additions & 3 deletions AUTHORS

This file was deleted.

File renamed without changes.
4 changes: 0 additions & 4 deletions MANIFEST.in

This file was deleted.

13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@ python-json-pointer
[![Supported Python versions](https://img.shields.io/pypi/pyversions/jsonpointer.svg)](https://pypi.python.org/pypi/jsonpointer/)
[![Coverage Status](https://coveralls.io/repos/stefankoegl/python-json-pointer/badge.svg?branch=master)](https://coveralls.io/r/stefankoegl/python-json-pointer?branch=master)


Resolve JSON Pointers in Python
-------------------------------
# Resolve JSON Pointers in Python

Library to resolve JSON Pointers according to
[RFC 6901](http://tools.ietf.org/html/rfc6901)

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
* Coveralls: https://coveralls.io/r/stefankoegl/python-json-pointer

# Installation

Using pip:

```bash
pip install jsonpointer
```
58 changes: 58 additions & 0 deletions jsonpointer/__init__.py
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__",
]
98 changes: 30 additions & 68 deletions jsonpointer.py → jsonpointer/jsonpointer.py
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
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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), ...
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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):
Expand All @@ -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
Expand Down Expand Up @@ -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", "~")
Loading

0 comments on commit 0583986

Please sign in to comment.