jmespath / jmespath.py

JMESPath is a query language for JSON.
http://jmespath.org
MIT License
2.19k stars 181 forks source link

Literals which are unquoted strings not being verified for JSON syntax #229

Open diazona opened 3 years ago

diazona commented 3 years ago

My understanding based on the specification is that the content of a literal expression, i.e. the text between backticks, is supposed to be a valid JSON expression, otherwise it should be reported as a syntax error. The Python implementation seems to be treating them as strings instead, though. For example, this is accepted as a valid JMESPath expression:

thing == `wat`

even though I would think it should cause an error. Is this an actual bug in the Python implementation, or have I been misunderstanding the spec? (In the latter case I'd argue that the spec is misleading about this to the point of it being a documentation bug, but that's a separate issue.)

Here's a short script that demonstrates the error:

import jmespath, json, sys

literal_json = 'wat'
expression = f"thing == `{literal_json}`"
document = {"thing": "wat"}

try:
    r = json.loads(literal_json)
except Exception as e:
    print(f"json: parse error: {e.__class__.__name__}")
else:
    print("json: no parse error")
    print(f"  result: {r!r}")

try:
    r = jmespath.search(expression, document)
except Exception as e:
    print(f"jmespath: parse error: {e.__class__.__name__}")
else:
    print("jmespath: no parse error")
    print(f"  result: {r!r}")

It prints out the following:

$ python test-jmespath.py 
json: parse error: JSONDecodeError
jmespath: no parse error
  result: True

I would expect to see the jmespath part of the output be the same as the json part of the output, i.e. some kind of parsing error. And if I try other kinds of values, I do indeed get consistent results. For example, replacing the literal_json assignment line with literal_json = '3' gives

$ python test-jmespath.py 
json: no parse error
result: 3
jmespath: no parse error
result: False

and if I replace it with literal_json = '{"foo": bar}' I get

$ python test-jmespath.py 
json: parse error: JSONDecodeError
jmespath: parse error: LexerError