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', '']

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', '']\n"
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", ""]'
ignore_hosts_fails = "['localhost', '']"

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
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', '']")
['localhost', '']