1

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 decoded

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.

serv-inc
  • 35,772
  • 9
  • 166
  • 188
McManip
  • 155
  • 1
  • 9
  • 1
    `['localhost', '127.0.0.0/8']` is not properly formatted JSON. JSON requires that **double** quotes are used. See [chapter 7 of the RFC](http://tools.ietf.org/html/rfc7158#section-7), `quotation-mark` is defined as `"`. – Martijn Pieters Feb 11 '15 at 21:28
  • Ah, thanks. The *double quotes* requirement did not stand out to me when reading http://www.json.org. – McManip Feb 11 '15 at 21:38

5 Answers5

5

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']
Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

Because RFC 7159 says so. Strings in JSON documents are enclosed in double quotes.

Community
  • 1
  • 1
Kevin
  • 28,963
  • 9
  • 62
  • 81
0

JSON is not just JavaScript.

JSON strings are double quoted according to the spec pdf or json.org.

JSON object keys are strings.

You must use double quotes for your strings and keys (to follow the spec). Many JSON parsers will be more permissive.

From object definition:

An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.

A name is a string. A single colon token follows each name, separating the name from the value. A single comma token separates a value from a following name.

From string definition:

A string is a sequence of Unicode code points wrapped with quotation marks (U+0022).

That U+0022 is the (double) quotation mark: ".

Community
  • 1
  • 1
Jon Surrell
  • 9,444
  • 8
  • 48
  • 54
0

As said before, that is invalid JSON. To parse, there are two other possibilities: use either demjson or yaml

>>> demjson.decode(" ['localhost', '127.0.0.0/8']")
[u'localhost', u'127.0.0.0/8']
>>> yaml.load(" ['localhost', '127.0.0.0/8']")
['localhost', '127.0.0.0/8']
serv-inc
  • 35,772
  • 9
  • 166
  • 188
0

Yes it cares for valid json. But you can tweak Simple json code to parse this Unquoted and single quoted json strings.

I have given my answer on this post

Single versus double quotes in json loads in Python