Skip to content

Commit cb7dc7c

Browse files
committed
Apply changes to allow comma separated indices. e.g some_field[0, 1, 2]. Originally proposed by https://github.com/elrandira
1 parent 8a62341 commit cb7dc7c

File tree

3 files changed

+41
-20
lines changed

3 files changed

+41
-20
lines changed

jsonpath_ng/jsonpath.py

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,8 @@ class Index(JSONPath):
643643
NOTE: For the concrete syntax of `[*]`, the abstract syntax is a Slice() with no parameters (equiv to `[:]`
644644
"""
645645

646-
def __init__(self, index):
647-
self.index = index
646+
def __init__(self, *indices):
647+
self.indices = indices
648648

649649
def find(self, datum):
650650
return self._find_base(datum, create=False)
@@ -658,10 +658,12 @@ def _find_base(self, datum, create):
658658
if datum.value == {}:
659659
datum.value = _create_list_key(datum.value)
660660
self._pad_value(datum.value)
661-
if datum.value and len(datum.value) > self.index:
662-
return [DatumInContext(datum.value[self.index], path=self, context=datum)]
663-
else:
664-
return []
661+
rv = []
662+
for index in self.indices:
663+
# invalid indices do not crash, return [] instead
664+
if datum.value and len(datum.value) > index:
665+
rv += [DatumInContext(datum.value[index], path=self, context=datum)]
666+
return rv
665667

666668
def update(self, data, val):
667669
return self._update_base(data, val, create=False)
@@ -675,28 +677,40 @@ def _update_base(self, data, val, create):
675677
data = _create_list_key(data)
676678
self._pad_value(data)
677679
if hasattr(val, '__call__'):
678-
data[self.index] = val.__call__(data[self.index], data, self.index)
679-
elif len(data) > self.index:
680-
data[self.index] = val
680+
for index in self.indices:
681+
val.__call__(data[index], data, index)
682+
else:
683+
for index in self.indices:
684+
if len(data) > index:
685+
try:
686+
if isinstance(val, list):
687+
# allows somelist[5,1,2] = [some_value, another_value, third_value]
688+
data[index] = val.pop(0)
689+
else:
690+
data[index] = val
691+
except Exception as e:
692+
raise e
681693
return data
682694

683695
def filter(self, fn, data):
684-
if fn(data[self.index]):
685-
data.pop(self.index) # relies on mutation :(
696+
for index in self.indices:
697+
if fn(data[index]):
698+
data.pop(index) # relies on mutation :(
686699
return data
687700

688701
def __eq__(self, other):
689-
return isinstance(other, Index) and self.index == other.index
702+
return isinstance(other, Index) and sorted(self.indices) == sorted(other.indices)
690703

691704
def __str__(self):
692-
return '[%i]' % self.index
705+
return '[%i]' % self.indices
693706

694707
def __repr__(self):
695-
return '%s(index=%r)' % (self.__class__.__name__, self.index)
708+
return '%s(indices=%r)' % (self.__class__.__name__, self.indices)
696709

697710
def _pad_value(self, value):
698-
if len(value) <= self.index:
699-
pad = self.index - len(value) + 1
711+
_max = max(self.indices)
712+
if len(value) <= _max:
713+
pad = _max - len(value) + 1
700714
value += [{} for __ in range(pad)]
701715

702716
def __hash__(self):

jsonpath_ng/parser.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def p_jsonpath_root(self, p):
116116

117117
def p_jsonpath_idx(self, p):
118118
"jsonpath : '[' idx ']'"
119-
p[0] = p[2]
119+
p[0] = Index(*p[2])
120120

121121
def p_jsonpath_slice(self, p):
122122
"jsonpath : '[' slice ']'"
@@ -132,7 +132,7 @@ def p_jsonpath_child_fieldbrackets(self, p):
132132

133133
def p_jsonpath_child_idxbrackets(self, p):
134134
"jsonpath : jsonpath '[' idx ']'"
135-
p[0] = Child(p[1], p[3])
135+
p[0] = Child(p[1], Index(*p[3]))
136136

137137
def p_jsonpath_child_slicebrackets(self, p):
138138
"jsonpath : jsonpath '[' slice ']'"
@@ -161,7 +161,11 @@ def p_fields_comma(self, p):
161161

162162
def p_idx(self, p):
163163
"idx : NUMBER"
164-
p[0] = Index(p[1])
164+
p[0] = [p[1]]
165+
166+
def p_idx_comma(self, p):
167+
"idx : idx ',' idx "
168+
p[0] = p[1] + p[3]
165169

166170
def p_slice_any(self, p):
167171
"slice : '*'"

tests/test_jsonpath.py

Lines changed: 4 additions & 1 deletion
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
# ------
@@ -156,7 +158,8 @@ def test_datumincontext_in_context_nested():
156158
@parsers
157159
def test_update(parse, expression, data, update_value, expected_value):
158160
data_copy = copy.deepcopy(data)
159-
result = parse(expression).update(data_copy, update_value)
161+
update_value_copy = copy.deepcopy(update_value)
162+
result = parse(expression).update(data_copy, update_value_copy)
160163
assert result == expected_value
161164

162165

0 commit comments

Comments
 (0)