From db29af197634bcf1fae8e40b024425eb416ac09e Mon Sep 17 00:00:00 2001 From: Daniel Himmelstein Date: Thu, 5 Dec 2019 14:15:16 -0800 Subject: [PATCH 1/6] update json.tool rst documentation --- Doc/library/json.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 23e39e95f783ef..12bda5300ead8a 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -738,6 +738,12 @@ Command line options .. versionadded:: 3.8 +.. cmdoption:: --indent, --tab, --no-indent, --compact + + Mutually exclusive options for whitespace control + + .. versionadded:: 3.9 + .. cmdoption:: -h, --help Show the help message. From bb90d8593e2ac4a176cac467d41ae9a51c726f43 Mon Sep 17 00:00:00 2001 From: Daniel Himmelstein Date: Thu, 5 Dec 2019 14:46:14 -0800 Subject: [PATCH 2/6] simplify tests with subprocess.check_call --- Lib/test/test_json/test_tool.py | 60 +++++++++++++++------------------ 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 953a5696e7c225..53e6a9fcb41e8f 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 -from subprocess import Popen, PIPE +from subprocess import check_call from test import support from test.support.script_helper import assert_python_ok @@ -84,10 +84,9 @@ class TestTool(unittest.TestCase): def test_stdin_stdout(self): 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, b'') + process = check_call(args, input=self.data, capture_output=True, text=True) + self.assertEqual(process.stdout, self.expect) + self.assertEqual(process.stderr, '') def _create_infile(self, data=None): infile = support.TESTFN @@ -131,10 +130,9 @@ def test_infile_outfile(self): def test_jsonlines(self): args = sys.executable, '-m', 'json.tool', '--json-lines' - with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc: - out, err = proc.communicate(self.jsonlines_raw.encode()) - self.assertEqual(out.splitlines(), self.jsonlines_expect.encode().splitlines()) - self.assertEqual(err, b'') + process = check_call(args, input=self.jsonlines_raw, capture_output=True, text=True) + self.assertEqual(process.stdout, self.jsonlines_expect) + self.assertEqual(process.stderr, '') def test_help_flag(self): rc, out, err = assert_python_ok('-m', 'json.tool', '-h') @@ -151,42 +149,38 @@ def test_sort_keys_flag(self): self.assertEqual(err, b'') def test_indent(self): - json_stdin = b'[1, 2]' + input_ = '[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'') + process = check_call(args, input=input_, capture_output=True, text=True) + self.assertEqual(process.stdout, expect) + self.assertEqual(process.stderr, '') def test_no_indent(self): - json_stdin = b'[1,\n2]' - expect = b'[1, 2]' + input_ = '[1,\n2]' + expect = '[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(expect.splitlines(), json_stdout.splitlines()) - self.assertEqual(err, b'') + process = check_call(args, input=input_, capture_output=True, text=True) + self.assertEqual(process.stdout, expect) + self.assertEqual(process.stderr, '') def test_tab(self): - json_stdin = b'[1, 2]' - expect = b'[\n\t1,\n\t2\n]\n' + input_ = '[1, 2]' + expect = '[\n\t1,\n\t2\n]\n' args = sys.executable, '-m', 'json.tool', '--tab' - 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'') + process = check_call(args, input=input_, capture_output=True, text=True) + self.assertEqual(process.stdout, expect) + self.assertEqual(process.stderr, '') def test_compact(self): - json_stdin = b'[ 1 ,\n 2]' - expect = b'[1,2]' + input_ = '[ 1 ,\n 2]' + expect = '[1,2]' args = sys.executable, '-m', 'json.tool', '--compact' - 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'') + process = check_call(args, input=input_, capture_output=True, text=True) + self.assertEqual(process.stdout, expect) + self.assertEqual(process.stderr, '') From 35a842789983635407b510d9dc040bb08a801c38 Mon Sep 17 00:00:00 2001 From: Daniel Himmelstein Date: Thu, 5 Dec 2019 15:40:52 -0800 Subject: [PATCH 3/6] help: note indentation options for valid --json-lines --- Lib/json/tool.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 2a404a44417960..a3ce6968367cfa 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -31,7 +31,8 @@ def main(): parser.add_argument('--sort-keys', action='store_true', default=False, help='sort the output of dictionaries alphabetically by key') parser.add_argument('--json-lines', action='store_true', default=False, - help='parse input using the jsonlines format') + help='parse input using the jsonlines format. ' + 'Use with --no-indent or --compact to produce valid jsonlines output.') group = parser.add_mutually_exclusive_group() group.add_argument('--indent', default=4, type=int, help='separate items with newlines and use this number ' From 9029cad6342cebb5fb9191e8ef9a80607a9d0ef7 Mon Sep 17 00:00:00 2001 From: Daniel Himmelstein Date: Thu, 5 Dec 2019 18:26:10 -0700 Subject: [PATCH 4/6] Update style to "JSON Lines" As per http://jsonlines.org/: > JSON Lines is a convenient format for storing structured data --- Lib/json/tool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index a3ce6968367cfa..02040f1c61b08f 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -31,8 +31,8 @@ def main(): parser.add_argument('--sort-keys', action='store_true', default=False, help='sort the output of dictionaries alphabetically by key') parser.add_argument('--json-lines', action='store_true', default=False, - help='parse input using the jsonlines format. ' - 'Use with --no-indent or --compact to produce valid jsonlines output.') + help='parse input using the JSON Lines format. ' + 'Use with --no-indent or --compact to produce valid JSON Lines output.') group = parser.add_mutually_exclusive_group() group.add_argument('--indent', default=4, type=int, help='separate items with newlines and use this number ' From aaf141ce822a74330313846361a91f40cb57fcad Mon Sep 17 00:00:00 2001 From: Daniel Himmelstein Date: Thu, 5 Dec 2019 18:54:03 -0700 Subject: [PATCH 5/6] use subprocess.run with check=True --- Lib/test/test_json/test_tool.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 53e6a9fcb41e8f..12e37a9e9b4b0c 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 -from subprocess import check_call +import subprocess from test import support from test.support.script_helper import assert_python_ok @@ -84,7 +84,7 @@ class TestTool(unittest.TestCase): def test_stdin_stdout(self): args = sys.executable, '-m', 'json.tool' - process = check_call(args, input=self.data, capture_output=True, text=True) + process = subprocess.run(args, input=self.data, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, self.expect) self.assertEqual(process.stderr, '') @@ -130,7 +130,7 @@ def test_infile_outfile(self): def test_jsonlines(self): args = sys.executable, '-m', 'json.tool', '--json-lines' - process = check_call(args, input=self.jsonlines_raw, capture_output=True, text=True) + process = subprocess.run(args, input=self.jsonlines_raw, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, self.jsonlines_expect) self.assertEqual(process.stderr, '') @@ -157,7 +157,7 @@ def test_indent(self): ] ''') args = sys.executable, '-m', 'json.tool', '--indent', '2' - process = check_call(args, input=input_, capture_output=True, text=True) + process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) self.assertEqual(process.stderr, '') @@ -165,7 +165,7 @@ def test_no_indent(self): input_ = '[1,\n2]' expect = '[1, 2]' args = sys.executable, '-m', 'json.tool', '--no-indent' - process = check_call(args, input=input_, capture_output=True, text=True) + process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) self.assertEqual(process.stderr, '') @@ -173,7 +173,7 @@ def test_tab(self): input_ = '[1, 2]' expect = '[\n\t1,\n\t2\n]\n' args = sys.executable, '-m', 'json.tool', '--tab' - process = check_call(args, input=input_, capture_output=True, text=True) + process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) self.assertEqual(process.stderr, '') @@ -181,6 +181,6 @@ def test_compact(self): input_ = '[ 1 ,\n 2]' expect = '[1,2]' args = sys.executable, '-m', 'json.tool', '--compact' - process = check_call(args, input=input_, capture_output=True, text=True) + process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) self.assertEqual(process.stderr, '') From b9362f129192e10ed491b67c004fcca36463d34c Mon Sep 17 00:00:00 2001 From: Daniel Himmelstein Date: Thu, 5 Dec 2019 21:01:07 -0700 Subject: [PATCH 6/6] Add trailing newlines to expected test output trailing newlines were previously ignored due to .splitlines Probably is better to test for this to ensure any future change in behavior is intentional. --- Lib/test/test_json/test_tool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 12e37a9e9b4b0c..6489db765ff45a 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -163,7 +163,7 @@ def test_indent(self): def test_no_indent(self): input_ = '[1,\n2]' - expect = '[1, 2]' + expect = '[1, 2]\n' args = sys.executable, '-m', 'json.tool', '--no-indent' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) @@ -179,7 +179,7 @@ def test_tab(self): def test_compact(self): input_ = '[ 1 ,\n 2]' - expect = '[1,2]' + expect = '[1,2]\n' args = sys.executable, '-m', 'json.tool', '--compact' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect)