Skip to content

Commit 2fe870d

Browse files
authored
Merge pull request #5 from jg-rp/locations
JSONPath Node location representaion
2 parents c36c0af + f37c050 commit 2fe870d

File tree

5 files changed

+27
-64
lines changed

5 files changed

+27
-64
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ coverage.xml
4747
.pytest_cache/
4848
cov.xml
4949

50+
# Profiling data
51+
mprofile*
52+
5053
# Translations
5154
*.mo
5255
*.pot
@@ -81,6 +84,7 @@ ENV/
8184
# Dev utils
8285
dev.py
8386
profile_.py
87+
tests/test_dev.py
8488

8589
# Test fixtures
8690
comparison_regression_suite.yaml

jsonpath_rfc9535/node.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@ def __init__(
3939
def path(self) -> str:
4040
"""Return the normalized path to this node."""
4141
return "$" + "".join(
42-
(f"['{p}']" if isinstance(p, str) else f"[{p}]" for p in self.location)
42+
f"['{p}']" if isinstance(p, str) else f"[{p}]" for p in self.location
43+
)
44+
45+
def new_child(self, value: object, key: Union[int, str]) -> JSONPathNode:
46+
"""Return a new node using this node's location."""
47+
return JSONPathNode(
48+
value=value,
49+
location=self.location + (key,),
50+
root=self.root,
4351
)
4452

4553
def __str__(self) -> str:

jsonpath_rfc9535/segments.py

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
from typing import Tuple
1313

1414
from .exceptions import JSONPathRecursionError
15-
from .node import JSONPathNode
1615

1716
if TYPE_CHECKING:
1817
from .environment import JSONPathEnvironment
18+
from .node import JSONPathNode
1919
from .selectors import JSONPathSelector
2020
from .tokens import Token
2121

@@ -88,20 +88,12 @@ def _visit(self, node: JSONPathNode, depth: int = 1) -> Iterable[JSONPathNode]:
8888
if isinstance(node.value, dict):
8989
for name, val in node.value.items():
9090
if isinstance(val, (dict, list)):
91-
_node = JSONPathNode(
92-
value=val,
93-
location=node.location + (name,),
94-
root=node.root,
95-
)
91+
_node = node.new_child(val, name)
9692
yield from self._visit(_node, depth + 1)
9793
elif isinstance(node.value, list):
9894
for i, element in enumerate(node.value):
9995
if isinstance(element, (dict, list)):
100-
_node = JSONPathNode(
101-
value=element,
102-
location=node.location + (i,),
103-
root=node.root,
104-
)
96+
_node = node.new_child(element, i)
10597
yield from self._visit(_node, depth + 1)
10698

10799
def _nondeterministic_visit(
@@ -175,15 +167,7 @@ def _nondeterministic_children(node: JSONPathNode) -> Iterable[JSONPathNode]:
175167
items = list(node.value.items())
176168
random.shuffle(items)
177169
for name, val in items:
178-
yield JSONPathNode(
179-
value=val,
180-
location=node.location + (name,),
181-
root=node.root,
182-
)
170+
yield node.new_child(val, name)
183171
elif isinstance(node.value, list):
184172
for i, element in enumerate(node.value):
185-
yield JSONPathNode(
186-
value=element,
187-
location=node.location + (i,),
188-
root=node.root,
189-
)
173+
yield node.new_child(element, i)

jsonpath_rfc9535/selectors.py

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
from .exceptions import JSONPathIndexError
1616
from .exceptions import JSONPathTypeError
1717
from .filter_expressions import FilterContext
18-
from .node import JSONPathNode
1918

2019
if TYPE_CHECKING:
2120
from .environment import JSONPathEnvironment
2221
from .filter_expressions import FilterExpression
22+
from .node import JSONPathNode
2323
from .tokens import Token
2424

2525

@@ -76,11 +76,7 @@ def resolve(self, node: JSONPathNode) -> Iterable[JSONPathNode]:
7676
"""Select a value from a dict/object by its property/key."""
7777
if isinstance(node.value, dict):
7878
with suppress(KeyError):
79-
yield JSONPathNode(
80-
value=node.value[self.name],
81-
location=node.location + (self.name,),
82-
root=node.root,
83-
)
79+
yield node.new_child(node.value[self.name], self.name)
8480

8581

8682
class IndexSelector(JSONPathSelector):
@@ -125,12 +121,7 @@ def resolve(self, node: JSONPathNode) -> Iterable[JSONPathNode]:
125121
if isinstance(node.value, list):
126122
norm_index = self._normalized_index(node.value)
127123
with suppress(IndexError):
128-
_node = JSONPathNode(
129-
value=node.value[self.index],
130-
location=node.location + (norm_index,),
131-
root=node.root,
132-
)
133-
yield _node
124+
yield node.new_child(node.value[self.index], norm_index)
134125

135126

136127
class SliceSelector(JSONPathSelector):
@@ -185,13 +176,7 @@ def resolve(self, node: JSONPathNode) -> Iterable[JSONPathNode]:
185176
idx = self.slice.start or 0
186177
step = self.slice.step or 1
187178
for element in node.value[self.slice]:
188-
norm_index = self._normalized_index(node.value, idx)
189-
_node = JSONPathNode(
190-
value=element,
191-
location=node.location + (norm_index,),
192-
root=node.root,
193-
)
194-
yield _node
179+
yield node.new_child(element, self._normalized_index(node.value, idx))
195180
idx += step
196181

197182

@@ -221,21 +206,11 @@ def resolve(self, node: JSONPathNode) -> Iterable[JSONPathNode]:
221206
members = node.value.items()
222207

223208
for name, val in members:
224-
_node = JSONPathNode(
225-
value=val,
226-
location=node.location + (name,),
227-
root=node.root,
228-
)
229-
yield _node
209+
yield node.new_child(val, name)
230210

231211
elif isinstance(node.value, list):
232212
for i, element in enumerate(node.value):
233-
_node = JSONPathNode(
234-
value=element,
235-
location=node.location + (i,),
236-
root=node.root,
237-
)
238-
yield _node
213+
yield node.new_child(element, i)
239214

240215

241216
class Filter(JSONPathSelector):
@@ -284,11 +259,7 @@ def resolve(self, node: JSONPathNode) -> Iterable[JSONPathNode]: # noqa: PLR091
284259
)
285260
try:
286261
if self.expression.evaluate(context):
287-
yield JSONPathNode(
288-
value=val,
289-
location=node.location + (name,),
290-
root=node.root,
291-
)
262+
yield node.new_child(val, name)
292263
except JSONPathTypeError as err:
293264
if not err.token:
294265
err.token = self.token
@@ -303,11 +274,7 @@ def resolve(self, node: JSONPathNode) -> Iterable[JSONPathNode]: # noqa: PLR091
303274
)
304275
try:
305276
if self.expression.evaluate(context):
306-
yield JSONPathNode(
307-
value=element,
308-
location=node.location + (i,),
309-
root=node.root,
310-
)
277+
yield node.new_child(element, i)
311278
except JSONPathTypeError as err:
312279
if not err.token:
313280
err.token = self.token

tests/test_cts_nondeterminism.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def _result_repr(rv: List[object]) -> Tuple[str, ...]:
7272

7373
env = MockEnv()
7474

75-
# Repeat enough times to has high probability that we've covered all
75+
# Repeat enough times so as to have high probability that we've covered all
7676
# valid permutations.
7777
results = {
7878
_result_repr(env.find(case.selector, case.document).values())

0 commit comments

Comments
 (0)