McManip McManip - 1 month ago 6
JSON Question

Why does json.loads care which type of quotes are used?

In a python script I am parsing the return of

gsettings get org.gnome.system.proxy ignore-hosts


which looks like it should be properly formatted JSON

['localhost', '127.0.0.0/8']


however, when passing this output to json.loads it throws

ValueError: No JSON object could be


I make the call to gsettings via:

import subprocess
proc = subprocess.Popen(["gsettings", "get", "org.gnome.system.proxy", "ignore-hosts"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout,stderr = proc.communicate()


which assigns
"['localhost', '127.0.0.0/8']\n"
to
stdout
.
Then I strip the newline and pass to json.loads:

ignore = json.loads(stdout.strip("\n"))


But, this throws a ValueError.

I've tracked the issue down to the string being defined by single-quotes or double-quotes as shown in the following snippet:

# tested in python 2.7.3

import json

ignore_hosts_works = '["localhost", "127.0.0.0/8"]'
ignore_hosts_fails = "['localhost', '127.0.0.0/8']"

json.loads(ignore_hosts_works) # produces list of unicode strings
json.loads(ignore_hosts_fails) # ValueError: No JSON object could be decoded

import string
table = string.maketrans("\"'", "'\"")

json.loads(string.translate(ignore_hosts_fails, table)) # produces list of unicode strings


Why is
ignore_hosts_fails
not successfully parsed by json.loads without swapping the quote types?

In case it might matter, I'm running Ubuntu 12.04 with Python 2.7.3.

Answer Source

From the JSON RFC 7159:

  string = quotation-mark *char quotation-mark

[...]

  quotation-mark = %x22      ; "

JSON strings must use " quotes.

You can parse that list as a Python literal instead, using ast.literal_eval():

>>> import ast
>>> ast.literal_eval("['localhost', '127.0.0.0/8']")
['localhost', '127.0.0.0/8']