Skip to content

masaccio/fractured-json-python

Repository files navigation

fractured-json

build:

build: codecov

fractured-json is a python wrapper of FracturedJson by j-brooke. The package fully follows the .NET version and includes the required assembly to run as long as you have installed a suitabe .NET runtime.

Installation

You must install a valid .NET runtime that is compatible with Python.NET (pythonnet). The package honors the environment variable PYTHONNET_RUNTIME for selecting the runtime variant but defaults to coreclr. As of current testing, Python versions 3.11 through 3.12 and .NET versions 7.0 and 8.0 are supported. Later versions are currently not supported by pythonnet.

You can download the Core .NET runtime from the Microsoft .NET website and version 8.0 is recommended as the stable and long-term supported version. Once installed, installation is simply:

python3 -m pip install fractured-json

There is a pure Python implementation of a JSON compactor called compact-json however this has now been archived on PyPI and will receive no further development.

The FracturedJson Wiki provides full documentation of intent, and a description of the options. This README is untended to cover only the Python specific elements of the wrapper.

Command-line

The package installs a command-line script fractured-json which can compact one or more JSON files according to command-line switches.

usage: fractured-json [-h] [-V] [--in-place] [--output OUTPUT]
                      [--allow-trailing-commas] [--always-expand-depth N]
                      [--colon-before-prop-name-padding] [--colon-padding]
                      [--comma-padding] [--comment-padding]
                      [--comment-policy {TREAT_AS_ERROR,REMOVE,PRESERVE}]
                      [--indent-spaces N]
                      [--json-eol-style {DEFAULT,CRLF,LF}]
                      [--max-compact-array-complexity N]
                      [--max-inline-complexity N]
                      [--max-prop-name-padding N]
                      [--max-table-row-complexity N]
                      [--max-total-line-length N]
                      [--min-compact-array-row-items N]
                      [--nested-bracket-padding]
                      [--number-list-alignment {LEFT,RIGHT,DECIMAL,
                                                NORMALIZE}]
                      [--prefix-string PREFIX_STRING]
                      [--preserve-blank-lines] [--simple-bracket-padding]
                      [--table-comma-placement {BEFORE_PADDING,AFTER_PADDING,
                                                BEFORE_PADDING_EXCEPT_NUMBERS}]
                      [--use-tab-to-indent] [--east-asian-chars]
                      [json ...]

Format JSON into compact, human readable form

positional arguments:
  json                  JSON file(s) to parse (or stdin with "-")

options:
  -h, --help            Show this help message and exit
  -V, --version         Output the script version and exit
  --in-place            Save any edits back to the input file
  --output, -o OUTPUT   The output file name(s). The number of output file
                        names must match the number of input files.
  --allow-trailing-commas
                        If true, the final element in an array or object
                        in the input may have a comma after it; otherwise
                        an exception is thrown. The JSON standard doesn't
                        allow trailing commas, but some other tools allow
                        them, so the option is provided for
                        interoperability with them. (default=False)
  --always-expand-depth N
                        Forces elements close to the root to always fully
                        expand, regardless of other settings. (default=-1)
  --colon-before-prop-name-padding
                        Set to true if you want colons to the left of the
                        spaces uses to line up expanded properties. false
                        puts them after the padding, in a row of their
                        own. (default=False)
  --colon-padding       If true, a space is added after a colon.
                        (default=True)
  --comma-padding       If true, a space is added after a comma.
                        (default=True)
  --comment-padding     If true, a space is added between a prefix/postfix
                        comment and the element to which it is attached.
                        (default=True)
  --comment-policy {TREAT_AS_ERROR,REMOVE,PRESERVE}
                        Determines how comments should be handled. The
                        JSON standard doesn't allow comments, but as an
                        unofficial extension they are fairly wide-spread
                        and useful. (default=TREAT_AS_ERROR)
  --indent-spaces N     Indents by this number of spaces for each level of
                        depth. If use-tab-to-indent=true , tab characters
                        will be used instead of spaces, but the indent-
                        spaces value will still be used to calculate line
                        lengths. (default=4)
  --json-eol-style {DEFAULT,CRLF,LF}
                        Determines which sort of line endings to use.
                        (default=DEFAULT)
  --max-compact-array-complexity N
                        Maximum nesting level that can be arranged
                        spanning multiple lines, with multiple items per
                        line. (default=2)
  --max-inline-complexity N
                        The maximum nesting level that can be displayed on
                        a single line. A primitive type or an empty array
                        or object has a complexity of 0. An object or
                        array has a complexity of 1 greater than its most
                        complex child. (default=2)
  --max-prop-name-padding N
                        Expanded object property values will be lined up
                        as long as the size difference in labels is this
                        value or less. Generally, lining up the property
                        values looks good as long as the labels are
                        roughly the same size, but not if they vary a lot.
                        This only applies to expanded objects; table
                        properties are lined up no matter what.
                        (default=16)
  --max-table-row-complexity N
                        Maximum nesting level allowed in a row of a table-
                        formatted array/object. (default=2)
  --max-total-line-length N
                        Maximum length of a line, including indentation
                        and everything, for purposes of deciding how much
                        to pile together. (default=120)
  --min-compact-array-row-items N
                        Minimum number of items per line to be eligible
                        for compact-multiline-array formatting.
                        (default=3)
  --nested-bracket-padding
                        If true, a space is added between an
                        array/object's brackets and its contents, if that
                        array/object has a complexity of 2 or more. That
                        is, if it contains non-empty arrays/objects.
                        (default=True)
  --number-list-alignment {LEFT,RIGHT,DECIMAL,NORMALIZE}
                        Controls how lists or table columns that contain
                        only numbers and nulls are aligned. In all cases
                        other than Normalize , numbers in the output are
                        exactly the same as in the input document. In all
                        cases, values too big to fit into a 64-bit float
                        or integer are preserved without issue.
                        (default=DECIMAL)
  --prefix-string PREFIX_STRING
                        A string to be included at the start of every line
                        of output. Note that if this string is anything
                        other than whitespace, it will probably make the
                        output invalid as JSON. (default=)
  --preserve-blank-lines
                        If true, blank lines (default=False)
  --simple-bracket-padding
                        If true, a space is added between an
                        array/object's brackets and its contents, if that
                        array/object has a complexity of 1. That is, if it
                        only contains primitive elements and/or empty
                        arrays/objects. (default=False)
  --table-comma-placement {BEFORE_PADDING,AFTER_PADDING,
                           BEFORE_PADDING_EXCEPT_NUMBERS}
                        Where to place commas in table-formatted elements.
                        (default=BEFORE_PADDING_EXCEPT_NUMBERS)
  --use-tab-to-indent   If true, a single tab character is used per
                        indentation level, instead of spaces.
                        (default=False)
  --east-asian-chars    Treat strings as unicode East Asian characters

The option --east-asian-chars indicates that fractured-json should take account of variable width East-Asian character sets when reformatting JSON.

Multiple files and output files can be processed at once but the number of input and output files must match:

fractured-json --output new_json_1.json --output new_json_2.json json_1.json json_2.json

Command-line help is printed when no arguments are passed, with --help, -h or -?.

API Usage

Follow the following steps to reformat JSON strings:

  • Optionally configure settings using a fractured_json.FracturedJsonOptions instance
  • Instantiate an instance of fractured_json.Formatter
  • Call Formatter.reformat().

Example:

>>> from fractured_json import Formatter, FracturedJsonOptions
>>> options = FracturedJsonOptions(indent_spaces=4)
>>> formatter = Formatter(options)
>>> formatter.reformat('{"a":1}')
'{"a": 1}\n'

Options

A full description of the options available can be found in the FracturedJson Wiki and these are dynamically created from the .NET library so will always match the .NET implementation.

from fractured_json import Formatter, FracturedJsonOptions, CommentPolicy
from pathlib import Path

options = FracturedJsonOptions(
    allow_trailing_commas=True,
    always_expand_depth=2,
    colon_before_prop_name_padding=True,
    comment_policy=CommentPolicy.PRESERVE
    indent_spaces=2,
)
formatter = Formatter(options=options)
json_input = Path("example.jsonc").read_text()
json_output = formatter.reformat(json_input)

Enumerations can be passed to FracturedJsonOptions as strings or as Python-style enums:

>>> from fractured_json import NumberListAlignment
>>> FracturedJsonOptions(number_list_alignment=NumberListAlignment.LEFT)
<fractured_json.FracturedJsonOptions object at 0x10966fc50>
>>> FracturedJsonOptions(number_list_alignment="LEFT")
<fractured_json.FracturedJsonOptions object at 0x10966f9d0>

Wide character support

When formatting dictionaries, FracturedJson needs to know the length of strings and for some East-Asian characters, the rendering width needs to be adjusted. The Formatter.string_length_func property is used to specify an alternative function to calculate strings lengths. The easiest approach is to use wcwidth.wcswidth which is packaged with fractured-json as a dependency:

options = FracturedJsonOptions()
formatter = Formatter(options=options)
formatter.string_length_func = lambda s: wcswidth(s)

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.

Feel free to join the discussion about the python wrapper. The goal of the python wrapper is to track the .NET core of the JSON formatter and provide all the features of the .NET version in python.

About

Python support for the FracturedJson JSON formatter

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages