diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 4f3182c0c1e7f1..d0f43f770dd6f9 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -25,24 +25,38 @@ def main(): 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') + parser.add_argument('--no-ensure-ascii', action='store_true', default=False, + help='Do not escape non-ASCII characters in output.') + group = parser.add_mutually_exclusive_group() + group.add_argument('--indent', default=4, type=int, + help='Indent level (number of spaces) for ' + 'pretty-printing. Defaults to 4.') + group.add_argument('--no-indent', action='store_const', dest='indent', + const=None, help='Use compact mode.') parser.add_argument('--sort-keys', action='store_true', default=False, help='sort the output of dictionaries alphabetically by key') options = parser.parse_args() + # Read input JSON infile = options.infile or sys.stdin - outfile = options.outfile or sys.stdout - sort_keys = options.sort_keys with infile: try: - if sort_keys: + if options.sort_keys: obj = json.load(infile) else: obj = json.load(infile, object_pairs_hook=collections.OrderedDict) except ValueError as e: raise SystemExit(e) + + # Export JSON + outfile = options.outfile or sys.stdout with outfile: - json.dump(obj, outfile, sort_keys=sort_keys, indent=4) + json.dump(obj, outfile, + indent=options.indent, + ensure_ascii=not options.no_ensure_ascii, + sort_keys=options.sort_keys, + ) outfile.write('\n') diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 15f373664e1278..b8890c096aaa47 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -2,7 +2,7 @@ import sys import textwrap import unittest -import subprocess +from subprocess import Popen, PIPE from test import support from test.support.script_helper import assert_python_ok @@ -61,12 +61,11 @@ class TestTool(unittest.TestCase): """) def test_stdin_stdout(self): - with subprocess.Popen( - (sys.executable, '-m', 'json.tool'), - stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc: + args = sys.executable, '-m', 'json.tool' + with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc: out, err = proc.communicate(self.data.encode()) self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) - self.assertEqual(err, None) + self.assertEqual(err, b'') def _create_infile(self): infile = support.TESTFN @@ -106,3 +105,42 @@ def test_sort_keys_flag(self): self.assertEqual(out.splitlines(), self.expect_without_sort_keys.encode().splitlines()) self.assertEqual(err, b'') + + def test_indent(self): + json_stdin = b'[1, 2]' + expect = textwrap.dedent('''\ + [ + 1, + 2 + ] + ''').encode() + args = sys.executable, '-m', 'json.tool', '--indent', '2' + with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc: + json_stdout, err = proc.communicate(json_stdin) + self.assertEqual(expect.splitlines(), json_stdout.splitlines()) + self.assertEqual(err, b'') + + def test_no_indent(self): + json_stdin = b'[1, 2]' + args = sys.executable, '-m', 'json.tool', '--no-indent' + with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc: + json_stdout, err = proc.communicate(json_stdin) + self.assertEqual(json_stdin.splitlines(), json_stdout.splitlines()) + self.assertEqual(err, b'') + + def test_ensure_ascii(self): + json_stdin = '"\xA7 \N{snake} \u03B4 \U0001D037"'.encode() + expect = b'"\\u00a7 \\ud83d\\udc0d \\u03b4 \\ud834\\udc37"\n' + args = sys.executable, '-m', 'json.tool' + with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc: + json_stdout, err = proc.communicate(json_stdin) + self.assertEqual(expect.splitlines(), json_stdout.splitlines()) + self.assertEqual(err, b'') + + def test_no_ensure_ascii(self): + json_stdin = '"\xA7 \N{snake} \u03B4 \U0001D037"'.encode() + args = sys.executable, '-m', 'json.tool', '--no-ensure-ascii' + with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc: + json_stdout, err = proc.communicate(json_stdin) + self.assertEqual(json_stdin.splitlines(), json_stdout.splitlines()) + self.assertEqual(err, b'')