A Python implementation of the JSON5 data format.
JSON5 extends the JSON data interchange format to make it slightly more usable as a configuration language:
JavaScript-style comments (both single and multi-line) are legal.
Object keys may be unquoted if they are legal ECMAScript identifiers
Objects and arrays may end with trailing commas.
Strings can be single-quoted, and multi-line string literals are allowed.
There are a few other more minor extensions to JSON; see the above page for the full details.
This project implements a reader and writer implementation for Python; where possible, it mirrors the standard Python JSON API package for ease of use.
There is one notable difference from the JSON api: the load() and
loads() methods support optionally checking for (and rejecting) duplicate
object keys; pass allow_duplicate_keys=False to do so (duplicates are
allowed by default).
This is an early release. It has been reasonably well-tested, but it is SLOW. It can be 1000-6000x slower than the C-optimized JSON module, and is 200x slower (or more) than the pure Python JSON module.
Please Note: This library only handles JSON5 documents, it does not allow you to read arbitrary JavaScript. For example, bare integers can be legal object keys in JavaScript, but they aren't in JSON5.
Did I mention that it is SLOW?
The implementation follows Python3's json implementation where
possible. This means that the encoding method to dump() is
ignored, and unicode strings are always returned.
The cls keyword argument that json.load()/json.loads() accepts
to specify a custom subclass of JSONDecoder is not and will not be
supported, because this implementation uses a completely different
approach to parsing strings and doesn't have anything like the
JSONDecoder class.
The cls keyword argument that json.dump()/json.dumps() accepts
is also not supported, for consistency with json5.load(). The default
keyword is supported, though, and might be able to serve as a
workaround.
json5 have no runtime dependencies and it is supported on Python version 3.8
or later. However, in order to develop and build the package you need a
bunch of extra tools and the latest versions of those tools may require 3.9
or later. You can install the extra environment on 3.8 (and get older versions
of the tools), but they may not run completely cleanly.
The easiest thing to do is to install uv and
use uv and the //run script to develop things. See ./run --help for
the various commands that are supported. glop is the parser generator
tool used to generate a parser from the grammar in json5/json5.g.
$ brew install uv
$ git clone https://github.com/dpranke/pyjson5
$ git clone https://github.com/dpranke/glop
$ cd pyjson5
$ source $(./run devenv) # To activate a venv w/ all the needed dev tools.
Install uv via whatever mechanism is appropriate.
$ ./run devenv
(This calls uv sync --extra dev.)
$ ./run tests
# Update the version in json5/version.py to $VERSION, which should be of
# the form X.Y.Z where X, Y, and Z are numbers.
$ ./run regen
$ ./run presubmit
$ git commit -a -m "Bump the version to $VERSION"
$ git tag "v$VERSION"
$ ./run build
$ ./run publish --prod
$ git push origin
$ git push --tags origin
(Assuming you have upload privileges to PyPI and the GitHub repo, of course.)
v0.15.0 (2026-06-19)
-0x1f and +0xff was raising
a ValueError instead of being allowed.v0.14.0 (2026-03-27) This is really just a dependency bump release.
v0.13.0 (2026-01-01)
v0.12.1 (2025-08-12)
v0.12.0 (2025-04-03)
v0.11.0 (2025-04-01)
cls argument; turns
out mypy was right and I was wrong and I didn't realize it :).parse method that can be used to iterate through
a string, extracting multiple values.consume_trailing parameter to load/loads/parse
that specifies whether to keep parsing after a valid object is
reached. By default, this is True and the string must only contain
trailing whitespace. If set to False, parsing will stop when a
valid object is reached.start parameter to load/loads/parse to specify
the zero-based offset to start parsing the string or file from.v0.10.0 (2024-11-25)
JSON5Encoder class that can be overridden to do custom
encoding of values. This class is vaguely similar to the JSONEncoder
class in the standard json library, except that it has an
encode() method that can be overridden to customize any
value, not just ones the standard encoder doesn't know how to handle.
It does also support a default() method that can be used to
encode things not normally encodable, like the JSONEncoder class.
It does not support an iterencode method. One could probably
be added in the future, although exactly how that would work and
interact with encode is a little unclear.quote_style argument to dump()/dumps() to control
how strings are encoded by default. For compatibility with older
versions of the json5 library and the standard json library, it
uses QuoteStyle.ALWAYS_DOUBLE which encodes all strings with double
quotes all the time. You can also configure it to use single quotes
all the time (ALWAYS_SINGLE), and to switch between single and double
when doing so eliminates a need to escape quotes (PREFER_SINGLE and
PREFER_DOUBLE). This also adds a --quote-style argument to
python -m json5.v0.9.28 (2024-11-11)
uv so ./run tests works properly.v0.9.27 (2024-11-10)
v0.9.26 (2024-11-10)
strict parameter to load()/loads().run script to be
contemporary.v0.9.25 (2024-04-12)
v0.9.24 (2024-03-16)
hypothesize in v0.9.23.v0.9.23 (2024-03-16)
hypothesize. This ran model-based checks
and didn't really add anything useful in terms of coverage to
the test suite, and it introduced dependencies and slowed down
the tests significantly. It was a good experiment but I think
we're better off without it.ruff check
using ruff 0.3.3 (Note that commit message in 00d73a3 says pylint
3.11, which is a typo).ruff formatv0.9.22 (2024-03-06)
v0.9.21 (2024-03-06)
v0.9.20 (2024-03-03)
json5.__version__ in addition to json5.VERSION.//run script to use python3.v0.9.19 (2024-03-03)
v0.9.18 (2024-02-29)
v0.9.17 (2024-02-19)
setup.py to pyproject.toml.v0.9.16 (2024-02-19)
setup.py//README.md.v0.9.15 (2024-02-19)
v0.9.14 (2023-05-14)
+Infinity as well as -Infinity and Infinity.v0.9.13 (2023-03-16)
v0.9.12 (2023-01-02)
v0.9.11 (2023-01-02)
float("inf") instead of math.inf.v0.9.10 (2022-08-18)
v0.9.9 (2022-08-01)
int or float:
Previously we would use the objects str implementation, but
that might result in an illegal JSON5 value if the object had
customized str to return something illegal. Instead,
we follow the lead of the JSON module and call int.__repr__
or float.__repr__ directly.allow_nan=False.v0.9.8 (2022-05-08)
v0.9.7 (2022-05-06)
default fn in dump and dumps. Previously
we didn't require the function to return a string, and so we could
end up returning something that wasn't actually valid. This change
now matches the behavior in the json module. Note: This is a
potentially breaking change.v0.9.6 (2021-06-21)
hypothesis isn't installed.v0.9.5 (2020-05-26)
v0.9.4 (2020-03-26)
v0.9.3 (2020-03-17)
v0.9.2 (2020-03-02)
v0.9.1 (2020-02-09)
v0.9.0 (2020-01-30)
dump()/dumps().
Add an allow_duplicate_keys=False to prevent possible
ill-formed JSON that might result.v0.8.5 (2019-07-04)
v0.8.4 (2019-06-11)
v0.8.3 (2019-06-11)
v0.8.2 (2019-06-11)
v0.8.1 (2019-06-11)
v0.8.0 (2019-06-11)
allow_duplicate_keys=True as a default argument to
json5.load()/json5.loads(). If you set the key to False, duplicate
keys in a single dict will be rejected. The default is set to True
for compatibility with json.load(), earlier versions of json5, and
because it's simply not clear if people would want duplicate checking
enabled by default.v0.7 (2019-03-31)
quote_keys=True will turn that off
and always quote object keys.indent is not None). Passing trailing_commas=False will
turn that off.json5.tool command line tool now supports the --indent,
--[no-]quote-keys, and --[no-]trailing-commas flags to allow
for more control over the output, in addition to the existing
--as-json flag.json5.tool command line tool no longer supports reading from
multiple files, you can now only read from a single file or
from standard input.json module
for anything. The output should still match the json module (except
as noted above) and discrepancies should be reported as bugs.v0.6.2 (2019-03-08)
v0.6.1 (2018-05-22)
v0.6.0 (2017-11-28)
v0.5.0 (2017-09-04)
json module supports.77 followers · starred Feb 2022
1,538 followers · starred Aug 2025
314 followers · starred Jun 2021
66 followers · starred Nov 2024
A Python implementation of the JSON5 data format.
JSON5 extends the JSON data interchange format to make it slightly more usable as a configuration language:
JavaScript-style comments (both single and multi-line) are legal.
Object keys may be unquoted if they are legal ECMAScript identifiers
Objects and arrays may end with trailing commas.
Strings can be single-quoted, and multi-line string literals are allowed.
There are a few other more minor extensions to JSON; see the above page for the full details.
This project implements a reader and writer implementation for Python; where possible, it mirrors the standard Python JSON API package for ease of use.
There is one notable difference from the JSON api: the load() and
loads() methods support optionally checking for (and rejecting) duplicate
object keys; pass allow_duplicate_keys=False to do so (duplicates are
allowed by default).
This is an early release. It has been reasonably well-tested, but it is SLOW. It can be 1000-6000x slower than the C-optimized JSON module, and is 200x slower (or more) than the pure Python JSON module.
Please Note: This library only handles JSON5 documents, it does not allow you to read arbitrary JavaScript. For example, bare integers can be legal object keys in JavaScript, but they aren't in JSON5.
Did I mention that it is SLOW?
The implementation follows Python3's json implementation where
possible. This means that the encoding method to dump() is
ignored, and unicode strings are always returned.
The cls keyword argument that json.load()/json.loads() accepts
to specify a custom subclass of JSONDecoder is not and will not be
supported, because this implementation uses a completely different
approach to parsing strings and doesn't have anything like the
JSONDecoder class.
The cls keyword argument that json.dump()/json.dumps() accepts
is also not supported, for consistency with json5.load(). The default
keyword is supported, though, and might be able to serve as a
workaround.
json5 have no runtime dependencies and it is supported on Python version 3.8
or later. However, in order to develop and build the package you need a
bunch of extra tools and the latest versions of those tools may require 3.9
or later. You can install the extra environment on 3.8 (and get older versions
of the tools), but they may not run completely cleanly.
The easiest thing to do is to install uv and
use uv and the //run script to develop things. See ./run --help for
the various commands that are supported. glop is the parser generator
tool used to generate a parser from the grammar in json5/json5.g.
$ brew install uv
$ git clone https://github.com/dpranke/pyjson5
$ git clone https://github.com/dpranke/glop
$ cd pyjson5
$ source $(./run devenv) # To activate a venv w/ all the needed dev tools.
Install uv via whatever mechanism is appropriate.
$ ./run devenv
(This calls uv sync --extra dev.)
$ ./run tests
# Update the version in json5/version.py to $VERSION, which should be of
# the form X.Y.Z where X, Y, and Z are numbers.
$ ./run regen
$ ./run presubmit
$ git commit -a -m "Bump the version to $VERSION"
$ git tag "v$VERSION"
$ ./run build
$ ./run publish --prod
$ git push origin
$ git push --tags origin
(Assuming you have upload privileges to PyPI and the GitHub repo, of course.)
v0.15.0 (2026-06-19)
-0x1f and +0xff was raising
a ValueError instead of being allowed.v0.14.0 (2026-03-27) This is really just a dependency bump release.
v0.13.0 (2026-01-01)
v0.12.1 (2025-08-12)
v0.12.0 (2025-04-03)
v0.11.0 (2025-04-01)
cls argument; turns
out mypy was right and I was wrong and I didn't realize it :).parse method that can be used to iterate through
a string, extracting multiple values.consume_trailing parameter to load/loads/parse
that specifies whether to keep parsing after a valid object is
reached. By default, this is True and the string must only contain
trailing whitespace. If set to False, parsing will stop when a
valid object is reached.start parameter to load/loads/parse to specify
the zero-based offset to start parsing the string or file from.v0.10.0 (2024-11-25)
JSON5Encoder class that can be overridden to do custom
encoding of values. This class is vaguely similar to the JSONEncoder
class in the standard json library, except that it has an
encode() method that can be overridden to customize any
value, not just ones the standard encoder doesn't know how to handle.
It does also support a default() method that can be used to
encode things not normally encodable, like the JSONEncoder class.
It does not support an iterencode method. One could probably
be added in the future, although exactly how that would work and
interact with encode is a little unclear.quote_style argument to dump()/dumps() to control
how strings are encoded by default. For compatibility with older
versions of the json5 library and the standard json library, it
uses QuoteStyle.ALWAYS_DOUBLE which encodes all strings with double
quotes all the time. You can also configure it to use single quotes
all the time (ALWAYS_SINGLE), and to switch between single and double
when doing so eliminates a need to escape quotes (PREFER_SINGLE and
PREFER_DOUBLE). This also adds a --quote-style argument to
python -m json5.v0.9.28 (2024-11-11)
uv so ./run tests works properly.v0.9.27 (2024-11-10)
v0.9.26 (2024-11-10)
strict parameter to load()/loads().run script to be
contemporary.v0.9.25 (2024-04-12)
v0.9.24 (2024-03-16)
hypothesize in v0.9.23.v0.9.23 (2024-03-16)
hypothesize. This ran model-based checks
and didn't really add anything useful in terms of coverage to
the test suite, and it introduced dependencies and slowed down
the tests significantly. It was a good experiment but I think
we're better off without it.ruff check
using ruff 0.3.3 (Note that commit message in 00d73a3 says pylint
3.11, which is a typo).ruff formatv0.9.22 (2024-03-06)
v0.9.21 (2024-03-06)
v0.9.20 (2024-03-03)
json5.__version__ in addition to json5.VERSION.//run script to use python3.v0.9.19 (2024-03-03)
v0.9.18 (2024-02-29)
v0.9.17 (2024-02-19)
setup.py to pyproject.toml.v0.9.16 (2024-02-19)
setup.py//README.md.v0.9.15 (2024-02-19)
v0.9.14 (2023-05-14)
+Infinity as well as -Infinity and Infinity.v0.9.13 (2023-03-16)
v0.9.12 (2023-01-02)
v0.9.11 (2023-01-02)
float("inf") instead of math.inf.v0.9.10 (2022-08-18)
v0.9.9 (2022-08-01)
int or float:
Previously we would use the objects str implementation, but
that might result in an illegal JSON5 value if the object had
customized str to return something illegal. Instead,
we follow the lead of the JSON module and call int.__repr__
or float.__repr__ directly.allow_nan=False.v0.9.8 (2022-05-08)
v0.9.7 (2022-05-06)
default fn in dump and dumps. Previously
we didn't require the function to return a string, and so we could
end up returning something that wasn't actually valid. This change
now matches the behavior in the json module. Note: This is a
potentially breaking change.v0.9.6 (2021-06-21)
hypothesis isn't installed.v0.9.5 (2020-05-26)
v0.9.4 (2020-03-26)
v0.9.3 (2020-03-17)
v0.9.2 (2020-03-02)
v0.9.1 (2020-02-09)
v0.9.0 (2020-01-30)
dump()/dumps().
Add an allow_duplicate_keys=False to prevent possible
ill-formed JSON that might result.v0.8.5 (2019-07-04)
v0.8.4 (2019-06-11)
v0.8.3 (2019-06-11)
v0.8.2 (2019-06-11)
v0.8.1 (2019-06-11)
v0.8.0 (2019-06-11)
allow_duplicate_keys=True as a default argument to
json5.load()/json5.loads(). If you set the key to False, duplicate
keys in a single dict will be rejected. The default is set to True
for compatibility with json.load(), earlier versions of json5, and
because it's simply not clear if people would want duplicate checking
enabled by default.v0.7 (2019-03-31)
quote_keys=True will turn that off
and always quote object keys.indent is not None). Passing trailing_commas=False will
turn that off.json5.tool command line tool now supports the --indent,
--[no-]quote-keys, and --[no-]trailing-commas flags to allow
for more control over the output, in addition to the existing
--as-json flag.json5.tool command line tool no longer supports reading from
multiple files, you can now only read from a single file or
from standard input.json module
for anything. The output should still match the json module (except
as noted above) and discrepancies should be reported as bugs.v0.6.2 (2019-03-08)
v0.6.1 (2018-05-22)
v0.6.0 (2017-11-28)
v0.5.0 (2017-09-04)
json module supports.77 followers · starred Feb 2022
1,538 followers · starred Aug 2025
314 followers · starred Jun 2021
66 followers · starred Nov 2024