• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                        help='a JSON file to be validated or pretty-printed',
25                        default='-')
26    parser.add_argument('outfile', nargs='?',
27                        help='write the output of infile to outfile',
28                        default=None)
29    parser.add_argument('--sort-keys', action='store_true', default=False,
30                        help='sort the output of dictionaries alphabetically by key')
31    parser.add_argument('--no-ensure-ascii', dest='ensure_ascii', action='store_false',
32                        help='disable escaping of non-ASCII characters')
33    parser.add_argument('--json-lines', action='store_true', default=False,
34                        help='parse input using the JSON Lines format. '
35                        'Use with --no-indent or --compact to produce valid JSON Lines output.')
36    group = parser.add_mutually_exclusive_group()
37    group.add_argument('--indent', default=4, type=int,
38                       help='separate items with newlines and use this number '
39                       'of spaces for indentation')
40    group.add_argument('--tab', action='store_const', dest='indent',
41                       const='\t', help='separate items with newlines and use '
42                       'tabs for indentation')
43    group.add_argument('--no-indent', action='store_const', dest='indent',
44                       const=None,
45                       help='separate items with spaces rather than newlines')
46    group.add_argument('--compact', action='store_true',
47                       help='suppress all whitespace separation (most compact)')
48    options = parser.parse_args()
49
50    dump_args = {
51        'sort_keys': options.sort_keys,
52        'indent': options.indent,
53        'ensure_ascii': options.ensure_ascii,
54    }
55    if options.compact:
56        dump_args['indent'] = None
57        dump_args['separators'] = ',', ':'
58
59    try:
60        if options.infile == '-':
61            infile = sys.stdin
62        else:
63            infile = open(options.infile, encoding='utf-8')
64        try:
65            if options.json_lines:
66                objs = (json.loads(line) for line in infile)
67            else:
68                objs = (json.load(infile),)
69        finally:
70            if infile is not sys.stdin:
71                infile.close()
72
73        if options.outfile is None:
74            outfile = sys.stdout
75        else:
76            outfile = open(options.outfile, 'w', encoding='utf-8')
77        with outfile:
78            for obj in objs:
79                json.dump(obj, outfile, **dump_args)
80                outfile.write('\n')
81    except ValueError as e:
82        raise SystemExit(e)
83
84
85if __name__ == '__main__':
86    try:
87        main()
88    except BrokenPipeError as exc:
89        sys.exit(exc.errno)
90