The chjson
Python C extension implements a developer friendly JSON codec.
In addition to the machine-centric JSON standard, it accepts developer-pleasing syntax:
- Single-
//
and multi-line/* */
comments. - Trailing commas
,
- Single-quoted
''
object keys (as opposed to requiring double-quotes). - Fractional numbers without a leading zero, like
.123
. - Multi-line strings -- either use a line continuation character at the end of lines (and it and the newline will be removed from the string), or just start a new line before the string closing quote (and the newline will be left in the string).
And it reports the line number and character offset on error.
This module works in Python 2.7, 3.3, and 3.4.
It should be easy to adapt to other versions as necessary.
The module is derived from Dan Pascu's Python2 module, python-cjson 1.1.0.
See also Hjson, the Human JSON, a pure-py implementation with a very rich syntax..
Simple encoding and decoding string example:
>>> import chjson
>>> chjson.encode({'q': True, '23': None,})
'{"q": true, "23": null}'
>>> chjson.decode('{"q": true, "23": null /* ignored \n */ , \'abc\': .123, } // ignored')
{'23': None, 'q': True, 'abc': 0.123}
Simple file decoding example:
>>> try:
... chjson.decode(open(json_path, 'r').read())
... except chjson.DecodeError as e:
... # Log filename, line number, and column (offset).
... fatal('Failed to load file "%s": %s' % (json_path, e.args[0],)
... raise
Yes, chjson
can be tricked into adhering to the exact JSON spec. Just set strict=True
.
>>> import chjson
>>> chjson.decode('{"q": true, "23": null,}', strict=True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
chjson.DecodeError: expecting object property name rather than
trailing comma at position 23 (lineno 1, offset 23)
The author tested this plugin against demjson
(the only comparable loose (developer-friendly) JSON codec) on 2015.09.25 and saw a seven times improvement in performance over demjson
for a real-world usage scenario involving reading JSON files in Python, parsing them with either demjson
or chjson
, and checking all dictionary values to see if they indicate a JSON path that should be side-loaded. (Read: chjson
is faster than demjson
by around a factor, but it'll depend on your usage scenario.) In real-world numbers, application boot time decreased from 6.65 seconds to 0.95 for this scenario. Not a crazy gain but enough to ease development pains.
You'll at least need a C compiler and the Python headers.
sudo apt-get install -y libpython3-dev
From the source directory, to make a debug build, try:
/bin/rm -rf build/ dist/ python_chjson.egg-info/
python3 ./setup.py clean
CFLAGS='-Wall -O0 -g' python3 ./setup.py build
python3 ./setup.py install
and then, e.g.,
gdb python3
b JSON_decode
run
import chjson
chjson.decode('{"my": "example",} // ignored')
And if you want a python2 build, do it all over again.
/bin/rm -rf build/ dist/ python_chjson.egg-info/
python2 ./setup.py clean
CFLAGS='-Wall -O0 -g' python2 ./setup.py build
python2 ./setup.py install
Omit the CFLAGS
to make a production build, 'natch.
If the Python2 binary builds but fails to load when imported, you may have built with Python3 libraries on your path. Try this:
CPPFLAGS='' LDFLAGS='' python2 ./setup.py build
Some articles on JSON performance in Python:
- https://gist.github.com/lightcatcher/1136415
- http://stackoverflow.com/questions/706101/python-json-decoding-performance
- https://liangnuren.wordpress.com/2012/08/13/python-json-performance/
- https://gist.github.com/techno/4486729
Some articles on writing C Python extensions: