diff --git a/gabbi/case.py b/gabbi/case.py index 0d1a326..b557347 100644 --- a/gabbi/case.py +++ b/gabbi/case.py @@ -29,11 +29,11 @@ import unittest from unittest import case -import jsonpath_rw import six from six.moves.urllib import parse as urlparse import wsgi_intercept +from gabbi import json_parser from gabbi import utils REPLACERS = [ @@ -193,7 +193,7 @@ def extract_json_path_value(data, path): The input data is a Python datastructre, not a JSON string. """ - path_expr = jsonpath_rw.parse(path) + path_expr = json_parser.parse(path) matches = [match.value for match in path_expr.find(data)] try: return matches[0] diff --git a/gabbi/gabbits_intercept/data.yaml b/gabbi/gabbits_intercept/data.yaml index 9a63743..53829d1 100644 --- a/gabbi/gabbits_intercept/data.yaml +++ b/gabbi/gabbits_intercept/data.yaml @@ -25,6 +25,7 @@ tests: response_json_paths: $[0]: 1 $[1]: 2 + $.`len`: 2 - name: load json file url: / diff --git a/gabbi/json_parser.py b/gabbi/json_parser.py new file mode 100644 index 0000000..cd4a088 --- /dev/null +++ b/gabbi/json_parser.py @@ -0,0 +1,56 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import jsonpath_rw + + +class Len(jsonpath_rw.JSONPath): + """The JSONPath referring to the len of the current object. + + Concrete syntax is '`len`'. + """ + + def find(self, datum): + datum = jsonpath_rw.DatumInContext.wrap(datum) + try: + value = len(datum.value) + except TypeError: + return [] + else: + return [jsonpath_rw.DatumInContext(value, + context=None, + path=Len())] + + def __eq__(self, other): + return isinstance(other, Len) + + def __str__(self): + return '`len`' + + def __repr__(self): + return 'Len()' + + +class GabbiJsonPathParser(jsonpath_rw.parser.JsonPathParser): + """Custom gabbi LALR-parser for JsonPath""" + + def p_jsonpath_named_operator(self, p): + "jsonpath : NAMED_OPERATOR" + if p[1] == 'len': + p[0] = Len() + else: + super(GabbiJsonPathParser, self).p_jsonpath_named_operator(p) + + +def parse(path): + return GabbiJsonPathParser().parse(path)