From c50501cc89a145d47b1f80aecd19153ce7e76bd7 Mon Sep 17 00:00:00 2001 From: Bryan Strassner Date: Mon, 2 Apr 2018 14:34:23 -0500 Subject: [PATCH] [fix] Updates to use cached jsonpath Layering code was not using a parse cache for jsonpath This change adds use of the cache around all calls to jsonpath_ng.parse Change-Id: I800eb397badf19ed2ea47b88fa7c91e4a09225ef --- deckhand/common/utils.py | 45 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/deckhand/common/utils.py b/deckhand/common/utils.py index 2a3d1b29..19a3a5eb 100644 --- a/deckhand/common/utils.py +++ b/deckhand/common/utils.py @@ -26,7 +26,9 @@ from deckhand import errors LOG = logging.getLogger(__name__) -path_cache = dict() +# Cache for JSON paths computed from path strings because jsonpath_ng +# is computationally expensive. +_PATH_CACHE = dict() def to_camel_case(s): @@ -41,6 +43,28 @@ def to_snake_case(name): return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() +def _normalize_jsonpath(jsonpath): + """Changes jsonpath starting with a `.` character with a `$`""" + if jsonpath == '.': + jsonpath = '$' + elif jsonpath.startswith('.'): + jsonpath = '$' + jsonpath + return jsonpath + + +def _jsonpath_parse_cache(jsonpath): + """Retrieve the parsed jsonpath path + + Utilizes a cache of parsed values to eliminate re-parsing + """ + if jsonpath not in _PATH_CACHE: + p = jsonpath_ng.parse(jsonpath) + _PATH_CACHE[jsonpath] = p + else: + p = _PATH_CACHE[jsonpath] + return p + + def jsonpath_parse(data, jsonpath, match_all=False): """Parse value in the data for the given ``jsonpath``. @@ -69,16 +93,8 @@ def jsonpath_parse(data, jsonpath, match_all=False): src_secret = utils.jsonpath_parse(src_doc['data'], src_path) # Do something with the extracted secret from the source document. """ - if jsonpath == '.': - jsonpath = '$' - elif jsonpath.startswith('.'): - jsonpath = '$' + jsonpath - - if jsonpath not in path_cache: - p = jsonpath_ng.parse(jsonpath) - path_cache[jsonpath] = p - else: - p = path_cache[jsonpath] + jsonpath = _normalize_jsonpath(jsonpath) + p = _jsonpath_parse_cache(jsonpath) matches = p.find(data) if matches: @@ -152,10 +168,7 @@ def jsonpath_replace(data, value, jsonpath, pattern=None): data = copy.copy(data) value = copy.copy(value) - if jsonpath == '.': - jsonpath = '$' - elif jsonpath.startswith('.'): - jsonpath = '$' + jsonpath + jsonpath = _normalize_jsonpath(jsonpath) if not jsonpath == '$' and not jsonpath.startswith('$.'): LOG.error('The provided jsonpath %s does not begin with "." or "$"', @@ -164,7 +177,7 @@ def jsonpath_replace(data, value, jsonpath, pattern=None): 'or "$"' % jsonpath) def _do_replace(): - p = jsonpath_ng.parse(jsonpath) + p = _jsonpath_parse_cache(jsonpath) p_to_change = p.find(data) if p_to_change: