python-jsonpath
Advanced tools
| # SPDX-FileCopyrightText: 2023-present James Prior <jamesgr.prior@gmail.com> | ||
| # | ||
| # SPDX-License-Identifier: MIT | ||
| __version__ = "2.0.0" | ||
| __version__ = "2.0.1" |
@@ -163,3 +163,3 @@ """JSONPath exceptions.""" | ||
| def __str__(self) -> str: | ||
| return f"pointer index error {super().__str__()}" | ||
| return f"pointer index error: {super().__str__()}" | ||
@@ -171,3 +171,3 @@ | ||
| def __str__(self) -> str: | ||
| return f"pointer key error {super().__str__()}" | ||
| return f"pointer key error: {super().__str__()}" | ||
@@ -179,3 +179,3 @@ | ||
| def __str__(self) -> str: | ||
| return f"pointer type error {super().__str__()}" | ||
| return f"pointer type error: {super().__str__()}" | ||
@@ -182,0 +182,0 @@ |
@@ -10,2 +10,3 @@ """JSON Patch, as per RFC 6902.""" | ||
| from io import IOBase | ||
| from typing import Any | ||
| from typing import Dict | ||
@@ -74,3 +75,7 @@ from typing import Iterable | ||
| else: | ||
| raise JSONPatchError("index out of range") | ||
| index = self.path._index(target) # noqa: SLF001 | ||
| if index == len(parent): | ||
| parent.append(self.value) | ||
| else: | ||
| raise JSONPatchError("index out of range") | ||
| else: | ||
@@ -633,3 +638,3 @@ parent.insert(int(target), self.value) | ||
| self, | ||
| data: Union[str, IOBase, MutableSequence[object], MutableMapping[str, object]], | ||
| data: Union[str, IOBase, MutableSequence[Any], MutableMapping[str, Any]], | ||
| ) -> object: | ||
@@ -682,3 +687,3 @@ """Apply all operations from this patch to _data_. | ||
| patch: Union[str, IOBase, Iterable[Mapping[str, object]], None], | ||
| data: Union[str, IOBase, MutableSequence[object], MutableMapping[str, object]], | ||
| data: Union[str, IOBase, MutableSequence[Any], MutableMapping[str, Any]], | ||
| *, | ||
@@ -685,0 +690,0 @@ unicode_escape: bool = True, |
+52
-55
@@ -13,2 +13,3 @@ """JSON Pointer. See https://datatracker.ietf.org/doc/html/rfc6901.""" | ||
| from typing import Mapping | ||
| from typing import Optional | ||
| from typing import Sequence | ||
@@ -62,3 +63,3 @@ from typing import Tuple | ||
| min_int_index (int): The minimum integer allowed when resolving array | ||
| items by index. Defaults to `-(2**53) + 1`. | ||
| items by index. Defaults to `0`. | ||
| """ | ||
@@ -70,3 +71,3 @@ | ||
| max_int_index = (2**53) - 1 | ||
| min_int_index = -(2**53) + 1 | ||
| min_int_index = 0 | ||
@@ -81,7 +82,11 @@ def __init__( | ||
| ) -> None: | ||
| self.parts = parts or self._parse( | ||
| pointer, | ||
| unicode_escape=unicode_escape, | ||
| uri_decode=uri_decode, | ||
| ) | ||
| if parts: | ||
| self.parts = tuple(str(part) for part in parts) | ||
| else: | ||
| self.parts = self._parse( | ||
| pointer, | ||
| unicode_escape=unicode_escape, | ||
| uri_decode=uri_decode, | ||
| ) | ||
| self._s = self._encode(self.parts) | ||
@@ -98,3 +103,3 @@ | ||
| uri_decode: bool, | ||
| ) -> Tuple[Union[int, str], ...]: | ||
| ) -> Tuple[str, ...]: | ||
| if uri_decode: | ||
@@ -111,26 +116,34 @@ s = unquote(s) | ||
| return tuple( | ||
| self._index(p.replace("~1", "/").replace("~0", "~")) for p in s.split("/") | ||
| )[1:] | ||
| return tuple(p.replace("~1", "/").replace("~0", "~") for p in s.split("/"))[1:] | ||
| def _index(self, s: str) -> Union[str, int]: | ||
| # Reject non-zero ints that start with a zero. | ||
| if len(s) > 1 and s.startswith("0"): | ||
| return s | ||
| def _index(self, key: str) -> Optional[int]: | ||
| """Return an array index for `key`. | ||
| Return `None` if key can't be converted to an index. | ||
| """ | ||
| # Reject indexes that start with a zero. | ||
| if len(key) > 1 and key.startswith("0"): | ||
| return None | ||
| try: | ||
| index = int(s) | ||
| if index < self.min_int_index or index > self.max_int_index: | ||
| raise JSONPointerError("index out of range") | ||
| return index | ||
| index = int(key) | ||
| except ValueError: | ||
| return s | ||
| return None | ||
| def _getitem(self, obj: Any, key: Any) -> Any: | ||
| if index < self.min_int_index or index > self.max_int_index: | ||
| raise JSONPointerIndexError( | ||
| f"array indices must be between {self.min_int_index}" | ||
| f" and {self.max_int_index}" | ||
| ) | ||
| return index | ||
| def _getitem(self, obj: Any, key: str) -> Any: | ||
| try: | ||
| # Handle the most common cases. A mapping with a string key, or a sequence | ||
| # with an integer index. | ||
| # | ||
| # Note that `obj` does not have to be a Mapping or Sequence here. Any object | ||
| # implementing `__getitem__` will do. | ||
| if isinstance(obj, Sequence) and not isinstance(obj, str): | ||
| index = self._index(key) | ||
| if isinstance(index, int): | ||
| return getitem(obj, index) | ||
| return getitem(obj, key) | ||
@@ -142,9 +155,7 @@ except KeyError as err: | ||
| except IndexError as err: | ||
| raise JSONPointerIndexError(f"index out of range: {key}") from err | ||
| if not isinstance(err, JSONPointerIndexError): | ||
| raise JSONPointerIndexError(f"index out of range: {key}") from err | ||
| raise | ||
| def _handle_key_error(self, obj: Any, key: Any, err: Exception) -> object: | ||
| if isinstance(key, int): | ||
| # Try a string repr of the index-like item as a mapping key. | ||
| return self._getitem(obj, str(key)) | ||
| def _handle_key_error(self, obj: Any, key: str, err: Exception) -> object: | ||
| # Handle non-standard key/property selector/pointer. | ||
@@ -159,4 +170,3 @@ # | ||
| if ( | ||
| isinstance(key, str) | ||
| and isinstance(obj, Mapping) | ||
| isinstance(obj, Mapping) | ||
| and key.startswith((self.keys_selector, "#")) | ||
@@ -169,13 +179,6 @@ and key[1:] in obj | ||
| def _handle_type_error(self, obj: Any, key: Any, err: Exception) -> object: | ||
| if ( | ||
| isinstance(obj, str) | ||
| or not isinstance(obj, Sequence) | ||
| or not isinstance(key, str) | ||
| ): | ||
| def _handle_type_error(self, obj: Any, key: str, err: Exception) -> object: | ||
| if not isinstance(obj, Sequence) or not isinstance(key, str): | ||
| raise JSONPointerTypeError(f"{key}: {err}") from err | ||
| # `obj` is array-like | ||
| # `key` is a string | ||
| if key == "-": | ||
@@ -197,7 +200,2 @@ # "-" is a valid index when appending to a JSON array with JSON Patch, but | ||
| # Try int index. Reject non-zero ints that start with a zero. | ||
| index = self._index(key) | ||
| if isinstance(index, int): | ||
| return self._getitem(obj, index) | ||
| raise JSONPointerTypeError(f"{key}: {err}") from err | ||
@@ -362,9 +360,9 @@ | ||
| def __eq__(self, other: object) -> bool: | ||
| return isinstance(other, JSONPointer) and self.parts == other.parts | ||
| return isinstance(other, self.__class__) and self.parts == other.parts | ||
| def __hash__(self) -> int: | ||
| return hash(self.parts) # pragma: no cover | ||
| return hash((self.__class__, self.parts)) # pragma: no cover | ||
| def __repr__(self) -> str: | ||
| return f"JSONPointer({self._s!r})" # pragma: no cover | ||
| return f"{self.__class__.__name__}({self._s!r})" # pragma: no cover | ||
@@ -405,3 +403,3 @@ def exists( | ||
| parent_parts = self.parts[:-1] | ||
| return JSONPointer( | ||
| return self.__class__( | ||
| self._encode(parent_parts), | ||
@@ -430,10 +428,9 @@ parts=parent_parts, | ||
| if other.startswith("/"): | ||
| return JSONPointer(other, unicode_escape=False, uri_decode=False) | ||
| return self.__class__(other, unicode_escape=False, uri_decode=False) | ||
| parts = self.parts + tuple( | ||
| self._index(p.replace("~1", "/").replace("~0", "~")) | ||
| for p in other.split("/") | ||
| p.replace("~1", "/").replace("~0", "~") for p in other.split("/") | ||
| ) | ||
| return JSONPointer( | ||
| return self.__class__( | ||
| self._encode(parts), parts=parts, unicode_escape=False, uri_decode=False | ||
@@ -628,3 +625,3 @@ ) | ||
| ) | ||
| parts[-1] = int(parts[-1]) + self.index | ||
| parts[-1] = str(int(parts[-1]) + self.index) | ||
@@ -631,0 +628,0 @@ # Pointer or index/property |
+3
-3
| Metadata-Version: 2.4 | ||
| Name: python-jsonpath | ||
| Version: 2.0.0 | ||
| Version: 2.0.1 | ||
| Summary: JSONPath, JSON Pointer and JSON Patch for Python. | ||
@@ -98,5 +98,5 @@ Project-URL: Documentation, https://jg-rp.github.io/python-jsonpath/ | ||
| - [JSONPath RFC 9535](https://github.com/jg-rp/python-jsonpath-rfc9535) - A Python implementation of JSONPath that follows RFC 9535 much more strictly. If you require maximum interoperability with JSONPath implemented in other languages - at the expense of extra features - choose [jsonpath-rfc9535](https://pypi.org/project/jsonpath-rfc9535/) over [python-jsonpath](https://pypi.org/project/python-jsonpath/). | ||
| - [JSONPath RFC 9535](https://github.com/jg-rp/python-jsonpath-rfc9535) - A minimal, slightly cleanr Python implementation of RFC 9535. If you're not interested JSONPath sytax beyond that defined in RFC 9535, you might choose [jsonpath-rfc9535](https://pypi.org/project/jsonpath-rfc9535/) over [python-jsonpath](https://pypi.org/project/python-jsonpath/). | ||
| jsonpath-rfc9535 matches RFC 9535's JSONPath model internally and is careful to use the spec's terminology. It also includes utilities for verifying and testing the [JSONPath Compliance Test Suite](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite). Most notably the nondeterministic behavior of some JSONPath selectors. | ||
| jsonpath-rfc9535 also includes utilities for verifying and testing the [JSONPath Compliance Test Suite](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite). Most notably the nondeterministic behavior of some JSONPath selectors. | ||
@@ -103,0 +103,0 @@ - [JSON P3](https://github.com/jg-rp/json-p3) - RFC 9535 implemented in TypeScript. JSON P3 does not include all the non-standard features of Python JSONPath, but does define some optional [extra syntax](https://jg-rp.github.io/json-p3/guides/jsonpath-extra). |
+2
-2
@@ -69,5 +69,5 @@ <h1 align="center">Python JSONPath</h1> | ||
| - [JSONPath RFC 9535](https://github.com/jg-rp/python-jsonpath-rfc9535) - A Python implementation of JSONPath that follows RFC 9535 much more strictly. If you require maximum interoperability with JSONPath implemented in other languages - at the expense of extra features - choose [jsonpath-rfc9535](https://pypi.org/project/jsonpath-rfc9535/) over [python-jsonpath](https://pypi.org/project/python-jsonpath/). | ||
| - [JSONPath RFC 9535](https://github.com/jg-rp/python-jsonpath-rfc9535) - A minimal, slightly cleanr Python implementation of RFC 9535. If you're not interested JSONPath sytax beyond that defined in RFC 9535, you might choose [jsonpath-rfc9535](https://pypi.org/project/jsonpath-rfc9535/) over [python-jsonpath](https://pypi.org/project/python-jsonpath/). | ||
| jsonpath-rfc9535 matches RFC 9535's JSONPath model internally and is careful to use the spec's terminology. It also includes utilities for verifying and testing the [JSONPath Compliance Test Suite](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite). Most notably the nondeterministic behavior of some JSONPath selectors. | ||
| jsonpath-rfc9535 also includes utilities for verifying and testing the [JSONPath Compliance Test Suite](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite). Most notably the nondeterministic behavior of some JSONPath selectors. | ||
@@ -74,0 +74,0 @@ - [JSON P3](https://github.com/jg-rp/json-p3) - RFC 9535 implemented in TypeScript. JSON P3 does not include all the non-standard features of Python JSONPath, but does define some optional [extra syntax](https://jg-rp.github.io/json-p3/guides/jsonpath-extra). |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
6328
0.02%274107
-0.06%