masaccio / compact-json

A JSON formatter that produces compact but human-readable
MIT License
27 stars 6 forks source link

compact-json

build: build: codecov

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:

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;"
        }
    }
}

Installation

python3 -m pip install compact-json

Usage

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)

Runtime warnings

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

Command-line usage

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.

Format options

The Formatter class has the following properties:

json_eol_style

Dictates what sort of line endings to use. EolStyle.LF is Unix-style line endings (the default) and EolStyle.CRLF Windows-style.

max_inline_length

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.

max_inline_complexity

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.

max_compact_list_complexity

Maximum nesting level that can be arranged spanning multiple lines, with multiple items per line. The default is 1.

nested_bracket_padding

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.

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.

colon_padding

If True (the default), includes a space after property colons.

comma_padding

If True (the default), includes a space after commas separating list items and dict properties.

always_expand_depth

Depth at which lists/dicts are always fully expanded, regardless of other settings

indent_spaces

Number of spaces to use per indent level (unless use_tab_to_indent is True). The default is 4.

use_tab_to_indent

Uses a single tab per indent level, instead of spaces. The default is False.

table_dict_minimum_similarity

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.

table_list_minimum_similarity

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.

align_expanded_property_names

If True, property names of expanded dicts are padded to the same size. The default is False.

dont_justify_numbers

If True, numbers won't be right-aligned with matching precision. The default is False.

prefix_string

String attached to the beginning of every line, before regular indentation.

ensure_ascii

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.

east_asian_string_widths

If True, format strings using unicodedata.east_asian_width rather than simple string lengths

Credits

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.

License

All code in this repository is licensed under the MIT License

Contribute

Contributions are greatly appreciated and welcomed. Please follow the project guidance on how to contribute.