blob: 63aa557cba48728d9ff41c63231d9d19819bcff0 [file] [log] [blame]
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import re
from recipe_engine import recipe_api
class JsonUtilApi(recipe_api.RecipeApi):
"""JsonUtilApi contains JSON-related utilities."""
def permissive_loads(self, text):
"""Extracts JSON from supplied text.
The parsing is somewhat more permissive than the actual JSON spec; for
example, commas are allowed after the last elements of arrays and
objects.
Args:
text (str): Text containing a JSON string.
Returns:
A JSON object representing the extracted JSON string from the text.
"""
# Strip any comma after the last element of an object or array.
text = re.sub(r",(?=\s*[}\]])", "", text)
try:
return self.m.json.loads(text)
except ValueError as e:
raise self.m.step.StepFailure("failed to load JSON: %s" % str(e))
def retrieve_nested_field(self, json_data, field):
"""Retrieve a field from a nested dict.
Returns the first found value if it exists. Otherwise return None.
For example, given the following data:
data = {
"list": [
{"foo": "bar"}
]
}
`retrieve_nested_field(data, "foo")` will return "bar".
Args:
json_data (Any): The JSON value (list, dict, etc.) to read from.
field (str): The name of the field.
"""
if isinstance(json_data, dict):
if field in json_data:
return json_data[field]
for val in json_data.values():
return_val = self.retrieve_nested_field(val, field)
if return_val is not None:
return return_val
if isinstance(json_data, list):
for item in json_data:
return_val = self.retrieve_nested_field(item, field)
if return_val is not None:
return return_val
return None