Skip to content

Commit bead1ef

Browse files
authored
Merge pull request #18 from ctomkow/group_param
Group param
2 parents 0f6dd1b + 94fedc5 commit bead1ef

File tree

5 files changed

+62
-11
lines changed

5 files changed

+62
-11
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ parser.find_key(data, 'key')
5555
parser.find_keys(data, ['rope', 'cable'])
5656
[[5, False], [7, True]]
5757

58-
parser.find_keys(data, ['cable', 'rope'])
59-
[[5, False], [7, True]]
58+
parser.find_keys(data, ['rope', 'cable'], group=False)
59+
[5, False, 7, True]
6060

6161

6262
parser.find_key_chain(data, ['my', 'key', 'chain'])
@@ -85,12 +85,14 @@ parser.find_key_value(data, 'chain', 'B')
8585

8686
- Returns a list of values that match the corresponding key.
8787

88-
`find_keys(data: dict | list, keys: list) -> list`
88+
`find_keys(data: dict | list, keys: list, group: bool = True) -> list`
8989

9090
- Provide JSON data as a dictionary or a list. The keys are a list of strings. The order of the keys does not matter.
9191

9292
- Returns a two dimensional list of values matching the keys. The order of values is returned in the same order as the original data.
9393

94+
- To return a one dimensional list, pass the keyword parameter group=False
95+
9496
`find_key_chain(data: dict | list, keys: list) -> list`
9597

9698
- Provide JSON data as a dictionary or a list. The key chain is a list of keys that are all strings. The order of the keys **does** matter.

jsonparse/parser.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,24 +89,33 @@ def find_key(self, data: Union[dict, list], key: str) -> list:
8989

9090
return value_list
9191

92-
def find_keys(self, data: Union[dict, list], keys: list) -> list:
92+
def find_keys(self,
93+
data: Union[dict, list],
94+
keys: list,
95+
group: bool = True) -> list:
9396
"""
9497
Search JSON data that consists of key:value pairs for all instances of
9598
provided keys. The data can have complex nested dictionaries and lists.
9699
If duplicate keys exist in the data (at any layer) all matching key
97100
values will be returned. Each instance of matching keys within a
98101
dictionary will be returned as a list. The final return value is a
99-
two dimensional list.
102+
two dimensional list. If a one dimensional list is needed where
103+
matched key values of the same dictionaries are not returned as a
104+
list, pass the group=False keyword parameter.
100105
101106
Keyword arguments:
102107
103108
data -- The python object representing JSON data with key:value pairs.
104109
This could be a dictionary or a list.
105110
keys -- The keys that will be searched for in the JSON data.
106111
The keys argument is a list of dictionary keys.
112+
group -- Determines whether the found values of the same dictionary
113+
will be returned as a list or not. Default is True which
114+
results in a two dimensional list. Pass False to return
115+
a one dimensional list.
107116
"""
108117

109-
if not self._valid_keys_input(data, keys):
118+
if not self._valid_keys_input(data, keys, group):
110119
raise
111120

112121
self.stack_ref = self._stack_init() # init a new stack every request
@@ -123,8 +132,11 @@ def find_keys(self, data: Union[dict, list], keys: list) -> list:
123132
self._stack_push_list_elem(elem)
124133
elif type(elem) is dict:
125134
value = self._stack_all_keys_values_in_dict(keys, elem)
126-
if value:
135+
if value and group:
127136
value_list.insert(0, value)
137+
elif value and not group:
138+
for e in reversed(value):
139+
value_list.insert(0, e)
128140
else: # according to RFC 7159, valid JSON can also contain a
129141
# string, number, 'false', 'null', 'true'
130142
pass # discard these other values as they don't have a key
@@ -441,14 +453,17 @@ def _valid_key_input(
441453
def _valid_keys_input(
442454
self,
443455
data: Union[dict, list],
444-
keys: list) -> bool:
456+
keys: list,
457+
group: bool) -> bool:
445458

446459
if not isinstance(data, (dict, list)):
447460
raise TypeError
448461
elif not isinstance(keys, list):
449462
raise TypeError
450463
elif not keys: # if keys is an empty list
451464
raise ValueError
465+
elif not isinstance(group, bool):
466+
raise TypeError
452467
return True
453468

454469
def _valid_key_chain_input(

jsonparse/webapi.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ def _find_key(key: str):
2929

3030

3131
# query parameters of keys
32-
# /v1/keys?key=first&key=second&key=third
32+
# /v1/keys?key=first&key=second&key=third&group=False
3333
@app.post('/v1/keys')
3434
def _find_keys():
3535

3636
# validate parameter keys
3737
param_keys = request.args.keys()
38+
if not param_keys:
39+
return (jsonify(error="parameter key incorrect"), 400)
3840
for k in param_keys:
39-
if k != 'key':
41+
if (k != 'key') and (k != 'group'):
4042
return (jsonify(error="parameter key incorrect"), 400)
4143

4244
keys = request.args.getlist('key')
@@ -46,7 +48,15 @@ def _find_keys():
4648
elif not key:
4749
return (jsonify(error="key must not be empty"), 400)
4850

49-
return Parser().find_keys(request.json, keys)
51+
group = request.args.get('group')
52+
if not group:
53+
group_status = True
54+
elif group.lower() == 'false':
55+
group_status = False
56+
else:
57+
group_status = True
58+
59+
return Parser().find_keys(request.json, keys, group_status)
5060

5161

5262
# query parameters of keys

tests/test_parser.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,16 @@ def test_find_keys(self, parser, complex_json):
275275

276276
assert result == [[5, 8], [22, 99], [1, 9], [4, 7]]
277277

278+
def test_find_keys_no_group(self, parser, complex_json):
279+
280+
result = parser.find_keys(
281+
complex_json,
282+
['start', 'end'],
283+
group=False
284+
)
285+
286+
assert result == [5, 8, 22, 99, 1, 9, 4, 7]
287+
278288
def test_find_keys_not_found(self, parser, complex_json):
279289

280290
result = parser.find_keys(

tests/test_webapi.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ def test_keys(client, data):
5050
assert response.status_code == 200
5151

5252

53+
def test_keys_with_group(client, data):
54+
55+
response = client.post(
56+
"/v1/keys?key=exists&key=ppu&group=False",
57+
json=data)
58+
assert response.status_code == 200
59+
60+
5361
def test_keys_empty_param_key(client, data):
5462

5563
response = client.post("/v1/keys?key=", json=data)
@@ -62,6 +70,12 @@ def test_keys_bad_params_key(client, data):
6270
assert response.status_code == 400
6371

6472

73+
def test_keys_no_params(client, data):
74+
75+
response = client.post("/v1/keys?", json=data)
76+
assert response.status_code == 400
77+
78+
6579
def test_keychain(client, data):
6680

6781
response = client.post("/v1/keychain?key=a&key=b", json=data)

0 commit comments

Comments
 (0)