Skip to content

Commit 1d16980

Browse files
authored
Merge pull request #173 from bjerzyna/allow-comma-separated-indices
Support comma separated indices in path
2 parents 80ad504 + cb7dc7c commit 1d16980

File tree

3 files changed

+41
-20
lines changed

3 files changed

+41
-20
lines changed

jsonpath_ng/jsonpath.py

+30-16
Original file line numberDiff line numberDiff line change
@@ -673,8 +673,8 @@ class Index(JSONPath):
673673
NOTE: For the concrete syntax of `[*]`, the abstract syntax is a Slice() with no parameters (equiv to `[:]`
674674
"""
675675

676-
def __init__(self, index):
677-
self.index = index
676+
def __init__(self, *indices):
677+
self.indices = indices
678678

679679
def find(self, datum):
680680
return self._find_base(datum, create=False)
@@ -688,10 +688,12 @@ def _find_base(self, datum, create):
688688
if datum.value == {}:
689689
datum.value = _create_list_key(datum.value)
690690
self._pad_value(datum.value)
691-
if datum.value and len(datum.value) > self.index:
692-
return [DatumInContext(datum.value[self.index], path=self, context=datum)]
693-
else:
694-
return []
691+
rv = []
692+
for index in self.indices:
693+
# invalid indices do not crash, return [] instead
694+
if datum.value and len(datum.value) > index:
695+
rv += [DatumInContext(datum.value[index], path=self, context=datum)]
696+
return rv
695697

696698
def update(self, data, val):
697699
return self._update_base(data, val, create=False)
@@ -705,28 +707,40 @@ def _update_base(self, data, val, create):
705707
data = _create_list_key(data)
706708
self._pad_value(data)
707709
if hasattr(val, '__call__'):
708-
data[self.index] = val.__call__(data[self.index], data, self.index)
709-
elif len(data) > self.index:
710-
data[self.index] = val
710+
for index in self.indices:
711+
val.__call__(data[index], data, index)
712+
else:
713+
for index in self.indices:
714+
if len(data) > index:
715+
try:
716+
if isinstance(val, list):
717+
# allows somelist[5,1,2] = [some_value, another_value, third_value]
718+
data[index] = val.pop(0)
719+
else:
720+
data[index] = val
721+
except Exception as e:
722+
raise e
711723
return data
712724

713725
def filter(self, fn, data):
714-
if fn(data[self.index]):
715-
data.pop(self.index) # relies on mutation :(
726+
for index in self.indices:
727+
if fn(data[index]):
728+
data.pop(index) # relies on mutation :(
716729
return data
717730

718731
def __eq__(self, other):
719-
return isinstance(other, Index) and self.index == other.index
732+
return isinstance(other, Index) and sorted(self.indices) == sorted(other.indices)
720733

721734
def __str__(self):
722-
return '[%i]' % self.index
735+
return '[%i]' % self.indices
723736

724737
def __repr__(self):
725-
return '%s(index=%r)' % (self.__class__.__name__, self.index)
738+
return '%s(indices=%r)' % (self.__class__.__name__, self.indices)
726739

727740
def _pad_value(self, value):
728-
if len(value) <= self.index:
729-
pad = self.index - len(value) + 1
741+
_max = max(self.indices)
742+
if len(value) <= _max:
743+
pad = _max - len(value) + 1
730744
value += [{} for __ in range(pad)]
731745

732746
def __hash__(self):

jsonpath_ng/parser.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def p_jsonpath_root(self, p):
120120

121121
def p_jsonpath_idx(self, p):
122122
"jsonpath : '[' idx ']'"
123-
p[0] = p[2]
123+
p[0] = Index(*p[2])
124124

125125
def p_jsonpath_slice(self, p):
126126
"jsonpath : '[' slice ']'"
@@ -136,7 +136,7 @@ def p_jsonpath_child_fieldbrackets(self, p):
136136

137137
def p_jsonpath_child_idxbrackets(self, p):
138138
"jsonpath : jsonpath '[' idx ']'"
139-
p[0] = Child(p[1], p[3])
139+
p[0] = Child(p[1], Index(*p[3]))
140140

141141
def p_jsonpath_child_slicebrackets(self, p):
142142
"jsonpath : jsonpath '[' slice ']'"
@@ -168,7 +168,11 @@ def p_fields_comma(self, p):
168168

169169
def p_idx(self, p):
170170
"idx : NUMBER"
171-
p[0] = Index(p[1])
171+
p[0] = [p[1]]
172+
173+
def p_idx_comma(self, p):
174+
"idx : idx ',' idx "
175+
p[0] = p[1] + p[3]
172176

173177
def p_slice_any(self, p):
174178
"slice : '*'"

tests/test_jsonpath.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def test_datumincontext_in_context_nested():
7272
# -------
7373
#
7474
("[0]", ["foo", "bar", "baz"], "test", ["test", "bar", "baz"]),
75+
("[0, 1]", ["foo", "bar", "baz"], "test", ["test", "test", "baz"]),
76+
("[0, 1]", ["foo", "bar", "baz"], ["test", "test 1"], ["test", "test 1", "baz"]),
7577
#
7678
# Slices
7779
# ------
@@ -166,7 +168,8 @@ def test_datumincontext_in_context_nested():
166168
@parsers
167169
def test_update(parse, expression, data, update_value, expected_value):
168170
data_copy = copy.deepcopy(data)
169-
result = parse(expression).update(data_copy, update_value)
171+
update_value_copy = copy.deepcopy(update_value)
172+
result = parse(expression).update(data_copy, update_value_copy)
170173
assert result == expected_value
171174

172175

0 commit comments

Comments
 (0)