h2non / jsonpath-ng

Finally, a JSONPath implementation for Python that aims to be standard compliant. That's all. Enjoy!
Apache License 2.0
579 stars 85 forks source link

Parsing bug in version 1.5.1 on recursive searches for dicts containing a specified key #46

Open josiahjohnston opened 4 years ago

josiahjohnston commented 4 years ago

Steps to reproduce:

from jsonpath_ng.ext import parse
import json
dat = json.loads('[{"specialKey": 5, "value": 8}, {"otherKey": 87}, [{"specialKey": 123, "value": 12}], {"olderStuff": [{"specialKey": 124, "value": 88}]}]')
jsonpath_expr = parse('$..[?(@.specialKey)]')
payloads = jsonpath_expr.find(dat)

Expected

Recursively search for dicts with a key of specialKey & return:

[
  {"specialKey": 5, "value": 8},
  {"specialKey": 123, "value": 12},
  {"specialKey": 124, "value": 88}
]

Observed

Parsing error from parse call:

In [101]: jsonpath_expr = parse('$..[?(@.StreamId)]')                                                                                                  
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-101-a74f026fcfab> in <module>
----> 1 jsonpath_expr = parse('$..[?(@.StreamId)]')

~/tmp/venv/lib/python3.7/site-packages/jsonpath_ng/ext/parser.py in parse(path, debug)
    170 
    171 def parse(path, debug=False):
--> 172     return ExtentedJsonPathParser(debug=debug).parse(path)

~/tmp/venv/lib/python3.7/site-packages/jsonpath_ng/parser.py in parse(self, string, lexer)
     30     def parse(self, string, lexer = None):
     31         lexer = lexer or self.lexer_class()
---> 32         return self.parse_token_stream(lexer.tokenize(string))
     33 
     34     def parse_token_stream(self, token_iterator, start_symbol='jsonpath'):

~/tmp/venv/lib/python3.7/site-packages/jsonpath_ng/parser.py in parse_token_stream(self, token_iterator, start_symbol)
     53                                    errorlog = logger)
     54 
---> 55         return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
     56 
     57     # ===================== PLY Parser specification =====================

~/tmp/venv/lib/python3.7/site-packages/ply/yacc.py in parse(self, input, lexer, debug, tracking, tokenfunc)
    331             return self.parseopt(input, lexer, debug, tracking, tokenfunc)
    332         else:
--> 333             return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
    334 
    335 

~/tmp/venv/lib/python3.7/site-packages/ply/yacc.py in parseopt_notrack(self, input, lexer, debug, tracking, tokenfunc)
   1199                             errtoken.lexer = lexer
   1200                         self.state = state
-> 1201                         tok = call_errorfunc(self.errorfunc, errtoken, self)
   1202                         if self.errorok:
   1203                             # User must have done some kind of panic

~/tmp/venv/lib/python3.7/site-packages/ply/yacc.py in call_errorfunc(errorfunc, token, parser)
    190     _token = parser.token
    191     _restart = parser.restart
--> 192     r = errorfunc(token)
    193     try:
    194         del _errok, _token, _restart

~/tmp/venv/lib/python3.7/site-packages/jsonpath_ng/parser.py in p_error(self, t)
     67 
     68     def p_error(self, t):
---> 69         raise Exception('Parse error at %s:%s near token %s (%s)' % (t.lineno, t.col, t.value, t.type))
     70 
     71     def p_jsonpath_binop(self, p):

Exception: Parse error at 1:4 near token ? (?)

Notes

This jsonpath expression parses and works as expected when I tested on https://jsonpath.com/ I get a similar failure with jsonpath_rw, the next-best jsonpath library for python.

juanluisbaptiste commented 3 years ago

I can confirm this bug too.