McManip
McManip

Reputation: 300

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 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.

Upvotes: 1

Views: 5581

Answers (5)

Nishi Sahlot
Nishi Sahlot

Reputation: 11

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

Upvotes: 0

serv-inc
serv-inc

Reputation: 38177

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

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1121914

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

Upvotes: 5

Jon Surrell
Jon Surrell

Reputation: 9637

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: ".

Upvotes: 0

Kevin
Kevin

Reputation: 30151

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

Upvotes: 0

Related Questions