compact-json
is a JSON formatter that produces configurably compact JSON that remains human-readable.
Any given container is formatted in one of three ways:
- Python lists or dicts will be written on a single line, if their contents aren't too complex and the resulting line wouldn't be too long.
- lists can be written on multiple lines, with multiple items per line, as long as those items aren't too complex.
- Otherwise, each dict property or array item is written beginning on its own line, indented one step deeper than its parent.
The following JSON is the standard output from running python3 -mjson.tool
:
{
"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}
}
The window
and image
objects are fairly short so when formatted with compact-json
they can be formated on a single line. With the default setting the text
object is still too long to fit on one line, but this can be configured to be longer:
{
"widget": {
"debug": "on",
"window": {"title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500},
"image": {"src": "Images/Sun.png", "name": "sun1", "hOffset": 250, "vOffset": 250, "alignment": "center"},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}
}
python3 -m pip install compact-json
As a python package, compact-json
is instantiated with a Formatter
class that has a range of properties to configure the formatting:
import json
from compact_json import Formatter, EolStyle
formatter = Formatter()
formatter.indent_spaces = 2
formatter.max_inline_complexity = 10
formatter.json_eol_style = EolStyle.LF
# Format the JSON contents:
with open("input.json", "r") as f:
obj = json.load(f)
json_string = formatter.serialize(obj)
print(json_string)
# Create a new JSON file with formatted JSON contents:
with open("input.json", "r") as f:
obj = json.load(f)
formatter.dump(obj, output_file="output.json", newline_at_eof=True)
Unlike the builtin json
package, compact-json
will issue runtime warnings when dictionary keys are forced to strings or overwritten to ensure that the resulting JSON is well-formed:
>>> from compact_json import Formatter
>>> Formatter().serialize({100: "error", 200: "had", 300: ["a", "little", "lamb"], "100": "mary"})
/path/src/compact_json/formatter.py:346: RuntimeWarning: coercing key value 100 to string
warnings.warn(f"converting key value {k} to string", RuntimeWarning)
/path/src/compact_json/formatter.py:346: RuntimeWarning: coercing key value 200 to string
warnings.warn(f"converting key value {k} to string", RuntimeWarning)
/path/src/compact_json/formatter.py:346: RuntimeWarning: coercing key value 300 to string
warnings.warn(f"converting key value {k} to string", RuntimeWarning)
/path/src/compact_json/formatter.py:349: RuntimeWarning: duplicate key value 100
warnings.warn(f"duplicate key value {k}", RuntimeWarning)
'{ "100": "mary", "200": "had", "300": ["a", "little", "lamb"] }'
When installed from pip
a command-line utility compact-json
is installed which has some useful defaults and most of the parameters available in Formatter
can be set on the command-line:
usage: compact-json [-h] [-V]
[--output-filename [OUTPUT_FILENAME ...]]
[--crlf] [--max-inline-length N]
[--max-inline-complexity N]
[--max-compact-list-complexity N]
[--bracket-padding {simple,nested}] [--indent N]
[--tab-indent] [--justify-numbers]
[--prefix-string STRING] [--align-properties]
[json ...]
Format JSON into compact, human readable form
positional arguments:
json JSON file(s) to parse (or stdin with "-")
optional arguments:
-h, --help show this help message and exit
-V, --version
--output-filename [OUTPUT_FILENAME ...], -out [OUTPUT_FILENAME ...]
The output file name(s). If empty, no new JSON file(s)
will be saved. If provided, the number of output file
names must match that of the input files.
--crlf Use Windows-style CRLF line endings
--max-inline-length N
Limit inline elements to N chars, excluding
indentation and leading property names (default=50)
--max-inline-complexity N
Maximum nesting: 0=basic types, 1=dict/list, 2=all
(default=2)
--max-compact-list-complexity N
Maximum nesting over multiple lines (default 1)
--bracket-padding {simple,nested}
If nested padding, add speces inside outside brackes
for nested lists/dicts
--indent N Indent N spaces (default=4)
--tab-indent Use tabs to indent
--justify-numbers Right-align numbers with matching precision
--prefix-string STRING
String attached to the beginning of every line
--align-properties Align property names of expanded dicts
--unicode Treat strings as unicode East Asian characters
compact-json
can be used in a shell pipeline to read from stdin when passed -
as the file argument.
The Formatter
class has the following properties:
Dictates what sort of line endings to use. EolStyle.LF
is Unix-style line endings (the default) and EolStyle.CRLF
Windows-style.
Maximum length of a complex element on a single line. This includes only the data for the inlined element not indentation or leading property names. The default is 80.
Maximum nesting level that can be displayed on a single line. A primitive type or an empty list or dict has a complexity of 0. A dict or list has a complexity of 1 greater than its most complex child. The default is 2.
Maximum nesting level that can be arranged spanning multiple lines, with multiple items per line. The default is 1.
If an inlined list or dict contains other lists or dicts, setting nested_bracket_padding
to True
will include spaces inside the outer brackets. The default is True
.
See also simple_bracket_padding
.
If an inlined list or dict does NOT contain other lists/dicts, setting simple_bracket_padding
to True
will include spaces inside the brackets. The default is False
.
See also nested_bracket_padding
.
If True
(the default), includes a space after property colons.
If True
(the default), includes a space after commas separating list items and dict properties.
Depth at which lists/dicts are always fully expanded, regardless of other settings
- -1 = none. This is the default
- 0 = root node only
- 1 = root node and its children.
Number of spaces to use per indent level (unless use_tab_to_indent
is True
). The default is 4.
Uses a single tab per indent level, instead of spaces. The default is False
.
Value from 0 to 100 indicating how similar collections of inline dicts need to be to be formatted as a table. A group of dicts that don't have any property names in common has a similarity of zero. A group of dicts that all contain the exact same property names has a similarity of 100. Setting this to a value > 100 disables table formatting with dicts as rows. The default is 75.
Value from 0 to 100 indicating how similar collections of inline lists need to be to be formatted as a table. Similarity for lists refers to how similar they are in length; if they all have the same length their similarity is 100. Setting this to a value > disables table formatting with lists as rows. The default is 75.
If True
, property names of expanded dicts are padded to the same size. The default is False
.
If True
, numbers won't be right-aligned with matching precision. The default is False
.
String attached to the beginning of every line, before regular indentation.
If True
(the default), the output is guaranteed to have all incoming non-ASCII characters escaped. If ensure_ascii
is False
, these characters will be output as-is.
If True
, format strings using unicodedata.east_asian_width rather than simple string lengths
compact-json
is primarily a Python port of FracturedJsonJs by j-brooke. FractureJson is also
an excellent Visual Studio Code extension. This package has no other relationship
with this original code, and hence all the bugs are my own.
All code in this repository is licensed under the MIT License
Contributions are greatly appreciated and welcomed. Please follow the project guidance on how to contribute.