Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

python-jsonpath

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

python-jsonpath - pypi Package Compare versions

Comparing version
1.2.2
to
1.3.0
+13
jsonpath/serialize.py
"""Helper functions for serializing compiled JSONPath queries."""
import json
def canonical_string(value: str) -> str:
"""Return _value_ as a canonically formatted string literal."""
single_quoted = (
json.dumps(value, ensure_ascii=False)[1:-1]
.replace('\\"', '"')
.replace("'", "\\'")
)
return f"'{single_quoted}'"
+1
-1
# SPDX-FileCopyrightText: 2023-present James Prior <jamesgr.prior@gmail.com>
#
# SPDX-License-Identifier: MIT
__version__ = "1.2.2"
__version__ = "1.3.0"

@@ -27,2 +27,3 @@ # SPDX-FileCopyrightText: 2023-present James Prior <jamesgr.prior@gmail.com>

from .match import JSONPathMatch
from .match import NodeList
from .parse import Parser

@@ -62,2 +63,3 @@ from .patch import JSONPatch

"Lexer",
"NodeList",
"match",

@@ -64,0 +66,0 @@ "Parser",

@@ -6,3 +6,2 @@ """Filter expression nodes."""

import copy
import json
import re

@@ -29,2 +28,3 @@ from abc import ABC

from .selectors import ListSelector
from .serialize import canonical_string

@@ -213,3 +213,3 @@ if TYPE_CHECKING:

def __str__(self) -> str:
return json.dumps(self.value)
return canonical_string(self.value)

@@ -381,2 +381,8 @@

PRECEDENCE_LOWEST = 1
PRECEDENCE_LOGICAL_OR = 3
PRECEDENCE_LOGICAL_AND = 4
PRECEDENCE_PREFIX = 7
class BooleanExpression(FilterExpression):

@@ -415,3 +421,3 @@ """An expression that always evaluates to `True` or `False`."""

def __str__(self) -> str:
return str(self.expression)
return self._canonical_string(self.expression, PRECEDENCE_LOWEST)

@@ -423,2 +429,29 @@ def __eq__(self, other: object) -> bool:

def _canonical_string(
self, expression: FilterExpression, parent_precedence: int
) -> str:
if isinstance(expression, InfixExpression):
if expression.operator == "&&":
left = self._canonical_string(expression.left, PRECEDENCE_LOGICAL_AND)
right = self._canonical_string(expression.right, PRECEDENCE_LOGICAL_AND)
expr = f"{left} && {right}"
return (
f"({expr})" if parent_precedence >= PRECEDENCE_LOGICAL_AND else expr
)
if expression.operator == "||":
left = self._canonical_string(expression.left, PRECEDENCE_LOGICAL_OR)
right = self._canonical_string(expression.right, PRECEDENCE_LOGICAL_OR)
expr = f"{left} || {right}"
return (
f"({expr})" if parent_precedence >= PRECEDENCE_LOGICAL_OR else expr
)
if isinstance(expression, PrefixExpression):
operand = self._canonical_string(expression.right, PRECEDENCE_PREFIX)
expr = f"!{operand}"
return f"({expr})" if parent_precedence > PRECEDENCE_PREFIX else expr
return str(expression)
def evaluate(self, context: FilterContext) -> bool:

@@ -425,0 +458,0 @@ return context.env.is_truthy(self.expression.evaluate(context))

"""The JSONPath match object, as returned from `JSONPath.finditer()`."""
from __future__ import annotations

@@ -107,2 +108,6 @@

def paths(self) -> List[str]:
"""Return a normalized path for each node in this node list."""
return [match.path for match in self]
def empty(self) -> bool:

@@ -109,0 +114,0 @@ """Return `True` if this node list is empty."""

"""JSONPath segments and selectors, as returned from `Parser.parse`."""
from __future__ import annotations

@@ -20,2 +21,3 @@

from .exceptions import JSONPathTypeError
from .serialize import canonical_string

@@ -79,3 +81,7 @@ if TYPE_CHECKING:

def __str__(self) -> str:
return f"['{self.name}']" if self.shorthand else f"'{self.name}'"
return (
f"[{canonical_string(self.name)}]"
if self.shorthand
else f"{canonical_string(self.name)}"
)

@@ -103,3 +109,3 @@ def __eq__(self, __value: object) -> bool:

parts=match.parts + (self.name,),
path=match.path + f"['{self.name}']",
path=match.path + f"[{canonical_string(self.name)}]",
root=match.root,

@@ -123,3 +129,3 @@ )

parts=match.parts + (self.name,),
path=match.path + f"['{self.name}']",
path=match.path + f"[{canonical_string(self.name)}]",
root=match.root,

@@ -328,7 +334,2 @@ )

def _normalized_index(self, obj: Sequence[object], index: int) -> int:
if index < 0 and len(obj) >= abs(index):
return len(obj) + index
return index
def resolve(self, matches: Iterable[JSONPathMatch]) -> Iterable[JSONPathMatch]:

@@ -339,6 +340,6 @@ for match in matches:

idx = self.slice.start or 0
step = self.slice.step or 1
for obj in self.env.getitem(match.obj, self.slice):
norm_index = self._normalized_index(match.obj, idx)
for norm_index, obj in zip( # noqa: B905
range(*self.slice.indices(len(match.obj))),
self.env.getitem(match.obj, self.slice),
):
_match = self.env.match_class(

@@ -354,3 +355,2 @@ filter_context=match.filter_context(),

yield _match
idx += step

@@ -364,6 +364,6 @@ async def resolve_async(

idx = self.slice.start or 0
step = self.slice.step or 1
for obj in await self.env.getitem_async(match.obj, self.slice):
norm_index = self._normalized_index(match.obj, idx)
for norm_index, obj in zip( # noqa: B905
range(*self.slice.indices(len(match.obj))),
await self.env.getitem_async(match.obj, self.slice),
):
_match = self.env.match_class(

@@ -379,3 +379,2 @@ filter_context=match.filter_context(),

yield _match
idx += step

@@ -414,3 +413,3 @@

parts=match.parts + (key,),
path=match.path + f"['{key}']",
path=match.path + f"[{canonical_string(key)}]",
root=match.root,

@@ -444,3 +443,3 @@ )

parts=match.parts + (key,),
path=match.path + f"['{key}']",
path=match.path + f"[{canonical_string(key)}]",
root=match.root,

@@ -493,3 +492,3 @@ )

parts=match.parts + (key,),
path=match.path + f"['{key}']",
path=match.path + f"[{canonical_string(key)}]",
root=match.root,

@@ -648,3 +647,3 @@ )

parts=match.parts + (key,),
path=match.path + f"['{key}']",
path=match.path + f"[{canonical_string(key)}]",
root=match.root,

@@ -717,3 +716,3 @@ )

parts=match.parts + (key,),
path=match.path + f"['{key}']",
path=match.path + f"[{canonical_string(key)}]",
root=match.root,

@@ -720,0 +719,0 @@ )

@@ -1,4 +0,4 @@

Metadata-Version: 2.3
Metadata-Version: 2.4
Name: python-jsonpath
Version: 1.2.2
Version: 1.3.0
Summary: JSONPath, JSON Pointer and JSON Patch for Python.

@@ -9,3 +9,4 @@ Project-URL: Documentation, https://jg-rp.github.io/python-jsonpath/

Author-email: James Prior <jamesgr.prior@gmail.com>
License: MIT
License-Expression: MIT
License-File: LICENSE.txt
Classifier: Development Status :: 5 - Production/Stable

@@ -12,0 +13,0 @@ Classifier: Intended Audience :: Developers

@@ -170,3 +170,3 @@ [build-system]

ignore = ["S105", "S101", "D107", "D105", "PLR0913", "SIM108", "PT001"]
ignore = ["S105", "S101", "D107", "D105", "PLR0913", "SIM108", "PT001", "A005"]

@@ -173,0 +173,0 @@ fixable = ["I"]