diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -99,16 +99,18 @@ Using json.tool from the shell to valida $ echo '{"json":"obj"}' | python -mjson.tool { "json": "obj" } $ echo '{1.2:3.4}' | python -mjson.tool Expecting property name enclosed in double quotes: line 1 column 2 (char 1) +See :ref:`json-commandline` for detailed documentation. + .. highlight:: python3 .. note:: JSON is a subset of `YAML `_ 1.2. The JSON produced by this module's default settings (in particular, the default *separators* value) is also a subset of YAML 1.0 and 1.1. This module can thus also be used as a YAML serializer. @@ -558,8 +560,57 @@ does not specify how repeated names in J default, this module does not raise an exception; instead, it ignores all but the last name-value pair for a given name:: >>> weird_json = '{"x": 1, "x": 2, "x": 3}' >>> json.loads(weird_json) {'x': 3} The *object_pairs_hook* parameter can be used to alter this behavior. + +.. highlight:: bash + +.. _json-commandline: + +Command Line Interface +---------------------- + +The :mod:`json` module provides a simple command line interface to validate +and pretty-print JSON objects. + +If the optional :option:`infile` and :option:`outfile` arguments are not specified, +:attr:`sys.stdin` and :attr:`sys.stdout` will be used respectively:: + + $ echo '{"json": "obj"}' | python -m json.tool + { + "json": "obj" + } + $ echo '{1.2:3.4}' | python -m json.tool + Expecting property name enclosed in double quotes: line 1 column 2 (char 1) + + +Command line options +^^^^^^^^^^^^^^^^^^^^ + +.. cmdoption:: [] + + The JSON file to be validated or pretty-printed:: + + $ python -m json.tool mp_films.json + [ + { + "title": "And Now for Something Completely Different", + "year": 1971 + }, + { + "title": "Monty Python and the Holy Grail", + "year": 1975 + } + ] + +.. cmdoption:: [] + + Write the output of the *infile* to the given *outfile*. Otherwise, write it + to :attr:`sys.stdout`. + +.. cmdoption:: -h, --help + + Show the help message. diff --git a/Lib/json/tool.py b/Lib/json/tool.py --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -5,35 +5,39 @@ Usage:: $ echo '{"json":"obj"}' | python -m json.tool { "json": "obj" } $ echo '{ 1.2:3.4}' | python -m json.tool Expecting property name enclosed in double quotes: line 1 column 3 (char 2) """ +import argparse +import json import sys -import json + def main(): - if len(sys.argv) == 1: - infile = sys.stdin - outfile = sys.stdout - elif len(sys.argv) == 2: - infile = open(sys.argv[1], 'r') - outfile = sys.stdout - elif len(sys.argv) == 3: - infile = open(sys.argv[1], 'r') - outfile = open(sys.argv[2], 'w') - else: - raise SystemExit(sys.argv[0] + " [infile [outfile]]") + prog = 'python -m json.tool' + description = ('A simple command line interface for json module ' + 'to validate and pretty-print JSON objects.') + parser = argparse.ArgumentParser(prog=prog, description=description) + parser.add_argument('infile', nargs='?', type=argparse.FileType(), + help='a JSON file to be validated or pretty-printed') + parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), + help='write the output of infile to outfile') + options = parser.parse_args() + + infile = options.infile or sys.stdin + outfile = options.outfile or sys.stdout with infile: try: obj = json.load(infile) except ValueError as e: raise SystemExit(e) with outfile: json.dump(obj, outfile, sort_keys=True, indent=4) outfile.write('\n') + sys.exit(0) if __name__ == '__main__': main() diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -50,20 +50,28 @@ class TestTool(unittest.TestCase): with open(infile, "w") as fp: self.addCleanup(os.remove, infile) fp.write(self.data) return infile def test_infile_stdout(self): infile = self._create_infile() rc, out, err = assert_python_ok('-m', 'json.tool', infile) + self.assertEqual(rc, 0) self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) self.assertEqual(err, b'') def test_infile_outfile(self): infile = self._create_infile() outfile = support.TESTFN + '.out' rc, out, err = assert_python_ok('-m', 'json.tool', infile, outfile) self.addCleanup(os.remove, outfile) with open(outfile, "r") as fp: self.assertEqual(fp.read(), self.expect) + self.assertEqual(rc, 0) self.assertEqual(out, b'') self.assertEqual(err, b'') + + def test_help_flag(self): + rc, out, err = assert_python_ok('-m', 'json.tool', '-h') + self.assertEqual(rc, 0) + self.assertTrue(out.startswith(b'usage: ')) + self.assertEqual(err, b'')