1r"""Command-line tool to validate and pretty-print JSON
2
3Usage::
4
5    $ echo '{"json":"obj"}' | python -m json.tool
6    {
7        "json": "obj"
8    }
9    $ echo '{ 1.2:3.4}' | python -m json.tool
10    Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
11
12"""
13import argparse
14import json
15import sys
16
17
18def main():
19    prog = 'python -m json.tool'
20    description = ('A simple command line interface for json module '
21                   'to validate and pretty-print JSON objects.')
22    parser = argparse.ArgumentParser(prog=prog, description=description)
23    parser.add_argument('infile', nargs='?',
24                        type=argparse.FileType(encoding="utf-8"),
25                        help='a JSON file to be validated or pretty-printed',
26                        default=sys.stdin)
27    parser.add_argument('outfile', nargs='?',
28                        type=argparse.FileType('w', encoding="utf-8"),
29                        help='write the output of infile to outfile',
30                        default=sys.stdout)
31    parser.add_argument('--sort-keys', action='store_true', default=False,
32                        help='sort the output of dictionaries alphabetically by key')
33    parser.add_argument('--no-ensure-ascii', dest='ensure_ascii', action='store_false',
34                        help='disable escaping of non-ASCII characters')
35    parser.add_argument('--json-lines', action='store_true', default=False,
36                        help='parse input using the JSON Lines format. '
37                        'Use with --no-indent or --compact to produce valid JSON Lines output.')
38    group = parser.add_mutually_exclusive_group()
39    group.add_argument('--indent', default=4, type=int,
40                       help='separate items with newlines and use this number '
41                       'of spaces for indentation')
42    group.add_argument('--tab', action='store_const', dest='indent',
43                       const='\t', help='separate items with newlines and use '
44                       'tabs for indentation')
45    group.add_argument('--no-indent', action='store_const', dest='indent',
46                       const=None,
47                       help='separate items with spaces rather than newlines')
48    group.add_argument('--compact', action='store_true',
49                       help='suppress all whitespace separation (most compact)')
50    options = parser.parse_args()
51
52    dump_args = {
53        'sort_keys': options.sort_keys,
54        'indent': options.indent,
55        'ensure_ascii': options.ensure_ascii,
56    }
57    if options.compact:
58        dump_args['indent'] = None
59        dump_args['separators'] = ',', ':'
60
61    with options.infile as infile, options.outfile as outfile:
62        try:
63            if options.json_lines:
64                objs = (json.loads(line) for line in infile)
65            else:
66                objs = (json.load(infile), )
67            for obj in objs:
68                json.dump(obj, outfile, **dump_args)
69                outfile.write('\n')
70        except ValueError as e:
71            raise SystemExit(e)
72
73
74if __name__ == '__main__':
75    try:
76        main()
77    except BrokenPipeError as exc:
78        sys.exit(exc.errno)
79