jsonpath-rfc9535 2.0.0__tar.gz → 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/CHANGELOG.md +20 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/PKG-INFO +1 -1
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/pyproject.toml +1 -0
- jsonpath_rfc9535-2.0.2/src/jsonpath_rfc9535/__about__.py +1 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_lexer.py +6 -7
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_parser.py +1 -8
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_parser_standard.py +1 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_resolve_standard.py +11 -13
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_resolver.py +3 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_resolver_basic.py +11 -13
- jsonpath_rfc9535-2.0.2/tests/test_issues.py +86 -0
- jsonpath_rfc9535-2.0.0/src/jsonpath_rfc9535/__about__.py +0 -1
- jsonpath_rfc9535-2.0.0/tests/test_issues.py +0 -26
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/.github/FUNDING.yml +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/.github/workflows/lint.yaml +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/.github/workflows/tests.yaml +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/.github/workflows/typing.yaml +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/.gitignore +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/.gitmodules +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/CONTRIBUTING.md +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/LICENSE.txt +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/README.md +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/_static/jsonpath_rfc9535.xcf +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/_static/jsonpath_rfc9535_dark.png +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/_static/jsonpath_rfc9535_light.png +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/api.rst +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/conf.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/functions.rst +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/index.rst +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/quick.rst +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/docs/syntax.rst +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/__init__.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/bench_citylots.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/bench_parse.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/bench_resolve.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/bench_tokenize.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/benchmark.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/micro_bench_types.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/profile_citylots.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/scripts/profile_types_memory.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/__init__.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/__main__.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_ast.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_debug.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_environment.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_lru_cache.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_node.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_nothing.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_serialize.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/_tokens.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/cli.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/exceptions.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/functions.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/py.typed +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/src/jsonpath_rfc9535/query.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/canonical_paths.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/.editorconfig +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/.github/workflows/build_cts_json.yaml +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/.github/workflows/validate_json_schema.yaml +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/CODE_OF_CONDUCT.md +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/CONTRIBUTING.md +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/LICENSE +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/NOTICE +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/README.md +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/build.js +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/build.ps1 +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/build.sh +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/cts.schema.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/basic.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/filter.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/functions/count.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/functions/length.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/functions/match.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/functions/search.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/functions/value.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/index_selector.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/name_selector.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/slice_selector.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/whitespace/filter.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/whitespace/functions.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/whitespace/operators.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/whitespace/selectors.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/tests/whitespace/slice.json +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_api.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_canonical_paths.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_cli.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_compliance.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_env.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_errors.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_ietf_examples.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_ietf_well_typedness.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_iregexp.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_lru_cache.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_node.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_regex_cache.py +0 -0
- {jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/test_tokenize.py +0 -0
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Python JSONPath RFC 9535 Change Log
|
|
2
2
|
|
|
3
|
+
## Version 2.0.2
|
|
4
|
+
|
|
5
|
+
**Fixes**
|
|
6
|
+
|
|
7
|
+
- Restored support for traversing `dict` and `list` subclasses when resolving a JSONPath expression. See [#32](https://github.com/jg-rp/python-jsonpath-rfc9535/issues/32).
|
|
8
|
+
|
|
9
|
+
## Version 2.0.1
|
|
10
|
+
|
|
11
|
+
**Fixes**
|
|
12
|
+
|
|
13
|
+
- Fixed trailing comma detection in bracketed segments. Previously we failed to consume whitespace after a comma and before checking for `]`. See [#26](https://github.com/jg-rp/python-jsonpath-rfc9535/issues/26).
|
|
14
|
+
|
|
15
|
+
- Fixed comparison operators `<`, `>`, `<=` and `>=` when comparing `true` and/or `false` with `1` and `0`. Previously we were leaking Python behavior. See [#27](https://github.com/jg-rp/python-jsonpath-rfc9535/issues/27).
|
|
16
|
+
|
|
17
|
+
- Fixed `\u` escaped sequence decoding. Previously we would not recognize lower case `e` and `f` hex digits due to a typo in a regular expression. See [#24](https://github.com/jg-rp/python-jsonpath-rfc9535/issues/24).
|
|
18
|
+
|
|
19
|
+
- Fixed `\u` escape sequence rejection of code points less than or equal to 0x1F. The spec requires us to reject literals of 0x1F or lower, not escape sequences. See [#24](https://github.com/jg-rp/python-jsonpath-rfc9535/issues/24).
|
|
20
|
+
|
|
21
|
+
- Fixed the shorthand name selector to accept the full range of allow Unicode code points and reject names containing `-`. See [#25](https://github.com/jg-rp/python-jsonpath-rfc9535/issues/25).
|
|
22
|
+
|
|
3
23
|
## Version 2.0.0
|
|
4
24
|
|
|
5
25
|
This release includes performance improvements and some breaking API changes. JSONPath syntax and semantics are unchanged.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: jsonpath-rfc9535
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: RFC 9535 - JSONPath: Query Expressions for JSON in Python
|
|
5
5
|
Project-URL: Documentation, https://jg-rp.github.io/python-jsonpath-rfc9535/
|
|
6
6
|
Project-URL: Issues, https://github.com/jg-rp/python-jsonpath-rfc9535/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.0.2"
|
|
@@ -6,16 +6,14 @@ from .exceptions import JSONPathSyntaxError
|
|
|
6
6
|
RE_FLOAT = re.compile(r"(:?-?[0-9]+\.[0-9]+(?:[eE][+-]?[0-9]+)?)|(-?[0-9]+[eE]-[0-9]+)")
|
|
7
7
|
RE_INT = re.compile(r"-?[0-9]+")
|
|
8
8
|
RE_INT_EXP = re.compile(r"-?[0-9]+[eE]\+?[0-9]+")
|
|
9
|
-
RE_NAME = re.compile(
|
|
9
|
+
RE_NAME = re.compile(
|
|
10
|
+
r"[\u0080-\uD7FF\uE000-\U0010FFFFa-zA-Z_][\u0080-\u10FFFF\uE000-\U0010FFFFa-zA-Z0-9_]*"
|
|
11
|
+
)
|
|
10
12
|
RE_TRIVIA = re.compile(r"[ \n\r\t]+")
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def tokenize(source: str) -> list[Token]:
|
|
14
|
-
"""Transform a JSONPath query source string into a list of tokens.
|
|
15
|
-
|
|
16
|
-
This tokenizer emits some non-standard tokens. The parser is responsible
|
|
17
|
-
for reject non-standard tokens with a syntax error if desired.
|
|
18
|
-
"""
|
|
16
|
+
"""Transform a JSONPath query source string into a list of tokens."""
|
|
19
17
|
tokens: list[Token] = []
|
|
20
18
|
length = len(source)
|
|
21
19
|
pos = 0
|
|
@@ -238,7 +236,8 @@ def _is_name_first_ch(ch: int) -> bool:
|
|
|
238
236
|
(ch >= 65 and ch <= 90)
|
|
239
237
|
or (ch >= 97 and ch <= 122)
|
|
240
238
|
or ch == 95
|
|
241
|
-
or (ch >= 0x80 and ch <=
|
|
239
|
+
or (ch >= 0x80 and ch <= 0xD7FF)
|
|
240
|
+
or (ch >= 0xE000 and ch <= 0x10FFFF)
|
|
242
241
|
)
|
|
243
242
|
|
|
244
243
|
|
|
@@ -20,7 +20,7 @@ from .query import JSONPathQuery
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from ._environment import JSONPathEnvironment
|
|
22
22
|
|
|
23
|
-
_RE_ESCAPE_U = re.compile(r"(\\u[0-9a-
|
|
23
|
+
_RE_ESCAPE_U = re.compile(r"(\\u[0-9a-fA-F]{4}|\\.)")
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class Parser(Protocol):
|
|
@@ -344,13 +344,6 @@ class Parser_(ABC):
|
|
|
344
344
|
((code_point & 0x03FF) << 10) | (low_surrogate & 0x03FF)
|
|
345
345
|
)
|
|
346
346
|
|
|
347
|
-
if code_point <= 0x1F:
|
|
348
|
-
raise JSONPathSyntaxError(
|
|
349
|
-
"invalid escape sequence",
|
|
350
|
-
token,
|
|
351
|
-
self.source,
|
|
352
|
-
)
|
|
353
|
-
|
|
354
347
|
unescaped.append(chr(code_point))
|
|
355
348
|
else:
|
|
356
349
|
raise JSONPathSyntaxError(
|
|
@@ -66,37 +66,37 @@ class StandardResolver(Resolver_):
|
|
|
66
66
|
|
|
67
67
|
match selector:
|
|
68
68
|
case (_ast.NAME_SELECTOR, _, name):
|
|
69
|
-
if
|
|
69
|
+
if isinstance(obj, dict) and name in obj:
|
|
70
70
|
yield self.new_child(node, name, obj[name])
|
|
71
71
|
|
|
72
72
|
case (_ast.INDEX_SELECTOR, _, index):
|
|
73
|
-
if
|
|
73
|
+
if isinstance(obj, list) and len(obj) >= abs(index) + int(index >= 0):
|
|
74
74
|
if index < 0 and len(obj) >= abs(index):
|
|
75
75
|
index = len(obj) + index
|
|
76
76
|
|
|
77
77
|
yield self.new_child(node, index, obj[index])
|
|
78
78
|
|
|
79
79
|
case (_ast.SLICE_SELECTOR, _, slice_):
|
|
80
|
-
if
|
|
80
|
+
if isinstance(obj, list) and slice_.step != 0:
|
|
81
81
|
for i, elem in zip(range(*slice_.indices(len(obj))), obj[slice_]):
|
|
82
82
|
yield self.new_child(node, i, elem)
|
|
83
83
|
|
|
84
84
|
case (_ast.WILDCARD_SELECTOR, _):
|
|
85
|
-
if
|
|
85
|
+
if isinstance(obj, dict):
|
|
86
86
|
for k, v in obj.items():
|
|
87
87
|
yield self.new_child(node, k, v)
|
|
88
88
|
|
|
89
|
-
elif
|
|
89
|
+
elif isinstance(obj, list):
|
|
90
90
|
for i, elem in enumerate(obj):
|
|
91
91
|
yield self.new_child(node, i, elem)
|
|
92
92
|
|
|
93
93
|
case (_ast.FILTER_SELECTOR, _, expr):
|
|
94
|
-
if
|
|
94
|
+
if isinstance(obj, dict):
|
|
95
95
|
for k, v in obj.items():
|
|
96
96
|
if self.truthy(self._evaluate_expression(expr, k, v)):
|
|
97
97
|
yield self.new_child(node, k, v)
|
|
98
98
|
|
|
99
|
-
elif
|
|
99
|
+
elif isinstance(obj, list):
|
|
100
100
|
for i, elem in enumerate(obj):
|
|
101
101
|
if self.truthy(self._evaluate_expression(expr, i, elem)):
|
|
102
102
|
yield self.new_child(node, i, elem)
|
|
@@ -210,16 +210,14 @@ class StandardResolver(Resolver_):
|
|
|
210
210
|
yield node
|
|
211
211
|
obj = node[0]
|
|
212
212
|
|
|
213
|
-
if
|
|
213
|
+
if isinstance(obj, dict):
|
|
214
214
|
for k, v in obj.items():
|
|
215
|
-
|
|
216
|
-
if isinstance(k, str) and (vt is list or vt is dict):
|
|
215
|
+
if isinstance(k, str) and isinstance(v, (dict, list)):
|
|
217
216
|
yield from visit_(self.new_child(node, k, v), depth + 1)
|
|
218
217
|
|
|
219
|
-
elif
|
|
218
|
+
elif isinstance(obj, list):
|
|
220
219
|
for i, elem in enumerate(obj):
|
|
221
|
-
|
|
222
|
-
if et is list or et is dict:
|
|
220
|
+
if isinstance(elem, (dict, list)):
|
|
223
221
|
yield from visit_(self.new_child(node, i, elem), depth + 1)
|
|
224
222
|
|
|
225
223
|
return visit_(node, 1)
|
|
@@ -64,37 +64,37 @@ class BasicResolver(Resolver_):
|
|
|
64
64
|
def _resolve_selector(self, selector: Selector, obj: object) -> Iterable[object]:
|
|
65
65
|
match selector:
|
|
66
66
|
case (_ast.NAME_SELECTOR, _, name):
|
|
67
|
-
if
|
|
67
|
+
if isinstance(obj, dict) and name in obj:
|
|
68
68
|
yield obj[name]
|
|
69
69
|
|
|
70
70
|
case (_ast.INDEX_SELECTOR, _, index):
|
|
71
|
-
if
|
|
71
|
+
if isinstance(obj, list) and len(obj) >= abs(index) + int(index >= 0):
|
|
72
72
|
if index < 0 and len(obj) >= abs(index):
|
|
73
73
|
index = len(obj) + index
|
|
74
74
|
|
|
75
75
|
yield obj[index]
|
|
76
76
|
|
|
77
77
|
case (_ast.SLICE_SELECTOR, _, slice_):
|
|
78
|
-
if
|
|
78
|
+
if isinstance(obj, list) and slice_.step != 0:
|
|
79
79
|
for i, elem in zip(range(*slice_.indices(len(obj))), obj[slice_]):
|
|
80
80
|
yield elem
|
|
81
81
|
|
|
82
82
|
case (_ast.WILDCARD_SELECTOR, _):
|
|
83
|
-
if
|
|
83
|
+
if isinstance(obj, dict):
|
|
84
84
|
for k, v in obj.items():
|
|
85
85
|
yield v
|
|
86
86
|
|
|
87
|
-
elif
|
|
87
|
+
elif isinstance(obj, list):
|
|
88
88
|
for i, elem in enumerate(obj):
|
|
89
89
|
yield elem
|
|
90
90
|
|
|
91
91
|
case (_ast.FILTER_SELECTOR, _, expr):
|
|
92
|
-
if
|
|
92
|
+
if isinstance(obj, dict):
|
|
93
93
|
for k, v in obj.items():
|
|
94
94
|
if self.truthy(self._evaluate_expression(expr, k, v)):
|
|
95
95
|
yield v
|
|
96
96
|
|
|
97
|
-
elif
|
|
97
|
+
elif isinstance(obj, list):
|
|
98
98
|
for i, elem in enumerate(obj):
|
|
99
99
|
if self.truthy(self._evaluate_expression(expr, i, elem)):
|
|
100
100
|
yield elem
|
|
@@ -210,16 +210,14 @@ class BasicResolver(Resolver_):
|
|
|
210
210
|
|
|
211
211
|
yield obj
|
|
212
212
|
|
|
213
|
-
if
|
|
213
|
+
if isinstance(obj, dict):
|
|
214
214
|
for k, v in obj.items():
|
|
215
|
-
|
|
216
|
-
if isinstance(k, str) and (vt is list or vt is dict):
|
|
215
|
+
if isinstance(k, str) and isinstance(v, (list, dict)):
|
|
217
216
|
yield from visit_(v, depth + 1)
|
|
218
217
|
|
|
219
|
-
elif
|
|
218
|
+
elif isinstance(obj, list):
|
|
220
219
|
for elem in obj:
|
|
221
|
-
|
|
222
|
-
if et is list or et is dict:
|
|
220
|
+
if isinstance(elem, (dict, list)):
|
|
223
221
|
yield from visit_(elem, depth + 1)
|
|
224
222
|
|
|
225
223
|
return visit_(node, 1)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import jsonpath_rfc9535 as jsonpath
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_issue_13() -> None:
|
|
7
|
+
# This was failing with "unbalanced parentheses".
|
|
8
|
+
_q = jsonpath.compile("$[? count(@.likes[? @.location]) > 3]")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_issue_21() -> None:
|
|
12
|
+
data = {"foo": {"bar": {"baz": 42}}}
|
|
13
|
+
node = jsonpath.find_one("$.foo.bar.baz", data)
|
|
14
|
+
|
|
15
|
+
expected = 42
|
|
16
|
+
assert node is not None
|
|
17
|
+
assert node.value == expected
|
|
18
|
+
assert data["foo"]["bar"]["baz"] == expected
|
|
19
|
+
|
|
20
|
+
new_value = 99
|
|
21
|
+
node.value = new_value
|
|
22
|
+
assert node.value == new_value
|
|
23
|
+
assert data["foo"]["bar"]["baz"] == new_value
|
|
24
|
+
|
|
25
|
+
parent = node.parent()
|
|
26
|
+
assert parent is not None
|
|
27
|
+
assert parent.value == {"baz": new_value}
|
|
28
|
+
assert parent.value["baz"] == new_value # type: ignore
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_issue_24() -> None:
|
|
32
|
+
data = {"\u001f": 1, "é": 2}
|
|
33
|
+
|
|
34
|
+
assert jsonpath.findall("$['\\u001f']", data) == [1]
|
|
35
|
+
assert jsonpath.findall("$['\\u00e9']", data) == [2]
|
|
36
|
+
assert jsonpath.findall("$['\\u00E9']", data) == [2]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_issue_25() -> None:
|
|
40
|
+
with pytest.raises(jsonpath.JSONPathSyntaxError):
|
|
41
|
+
assert jsonpath.compile("$.a-b")
|
|
42
|
+
|
|
43
|
+
assert jsonpath.findall("$.😀", {"😀": 1}) == [1]
|
|
44
|
+
assert jsonpath.findall("$['😀']", {"😀": 1}) == [1]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_issue_26() -> None:
|
|
48
|
+
with pytest.raises(jsonpath.JSONPathSyntaxError):
|
|
49
|
+
jsonpath.compile("$[1,]")
|
|
50
|
+
|
|
51
|
+
with pytest.raises(jsonpath.JSONPathSyntaxError):
|
|
52
|
+
jsonpath.compile("$[1, ]")
|
|
53
|
+
|
|
54
|
+
with pytest.raises(jsonpath.JSONPathSyntaxError):
|
|
55
|
+
jsonpath.compile("$[ 1, ]")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_issue_27() -> None:
|
|
59
|
+
assert jsonpath.findall("$[?@ > false]", [0, 1, True, False]) == []
|
|
60
|
+
assert jsonpath.findall("$[?@ < true]", [0, 1, True]) == []
|
|
61
|
+
assert jsonpath.findall("$[?@ >= 0]", [True, False, 0]) == [0]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_issue_32() -> None:
|
|
65
|
+
class MyDict(dict[str, object]):
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
class MyList(list[object]):
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
data = MyDict(
|
|
72
|
+
{
|
|
73
|
+
"users": MyList(
|
|
74
|
+
[
|
|
75
|
+
{"id": "usr_101", "name": "Alice", "status": "pending"},
|
|
76
|
+
{"id": "usr_102", "name": "Bob", "status": "active"},
|
|
77
|
+
{"id": "usr_103", "name": "Charlie", "status": "pending"},
|
|
78
|
+
]
|
|
79
|
+
),
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
expr = "$.users[?@.status == 'pending'].name"
|
|
84
|
+
|
|
85
|
+
assert jsonpath.findall(expr, data) == ["Alice", "Charlie"]
|
|
86
|
+
assert jsonpath.find(expr, data).values() == ["Alice", "Charlie"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.0.0"
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import jsonpath_rfc9535 as jsonpath
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def test_issue_13() -> None:
|
|
5
|
-
# This was failing with "unbalanced parentheses".
|
|
6
|
-
_q = jsonpath.compile("$[? count(@.likes[? @.location]) > 3]")
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def test_issue_21() -> None:
|
|
10
|
-
data = {"foo": {"bar": {"baz": 42}}}
|
|
11
|
-
node = jsonpath.find_one("$.foo.bar.baz", data)
|
|
12
|
-
|
|
13
|
-
expected = 42
|
|
14
|
-
assert node is not None
|
|
15
|
-
assert node.value == expected
|
|
16
|
-
assert data["foo"]["bar"]["baz"] == expected
|
|
17
|
-
|
|
18
|
-
new_value = 99
|
|
19
|
-
node.value = new_value
|
|
20
|
-
assert node.value == new_value
|
|
21
|
-
assert data["foo"]["bar"]["baz"] == new_value
|
|
22
|
-
|
|
23
|
-
parent = node.parent()
|
|
24
|
-
assert parent is not None
|
|
25
|
-
assert parent.value == {"baz": new_value}
|
|
26
|
-
assert parent.value["baz"] == new_value # type: ignore
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jsonpath_rfc9535-2.0.0 → jsonpath_rfc9535-2.0.2}/tests/cts/.github/workflows/build_cts_json.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|