From 1226315e2df0d4229558734d5f0d50f1386a025e Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 31 Jul 2024 17:35:25 -0700 Subject: [PATCH 1/4] Rename json.tool to json.__main__ --- Lib/json/{tool.py => __main__.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Lib/json/{tool.py => __main__.py} (100%) diff --git a/Lib/json/tool.py b/Lib/json/__main__.py similarity index 100% rename from Lib/json/tool.py rename to Lib/json/__main__.py From 7ce95d21886c7ad5278c07c1a20cda5bebab4731 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 31 Jul 2024 17:36:40 -0700 Subject: [PATCH 2/4] Make json.tool delegate to json.__main__ --- Lib/json/tool.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Lib/json/tool.py diff --git a/Lib/json/tool.py b/Lib/json/tool.py new file mode 100644 index 00000000000000..e46a9bb03820c0 --- /dev/null +++ b/Lib/json/tool.py @@ -0,0 +1,10 @@ +import sys + +from .__main__ import main + + +if __name__ == '__main__': + try: + main() + except BrokenPipeError as exc: + sys.exit(exc.errno) From ae4ca62346c690e1c6aaf1ccfed37069984b5d67 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 31 Jul 2024 18:32:16 -0700 Subject: [PATCH 3/4] Note json.tool deprecation --- Lib/json/tool.py | 9 ++++- Lib/test/test_json/test_tool.py | 71 ++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index e46a9bb03820c0..fb9e4592b411c2 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -1,6 +1,13 @@ import sys +import warnings -from .__main__ import main +from . import __main__ + + +def main(): + warnings.warn('The json.tool module is deprecated', + DeprecationWarning, stacklevel=2) + __main__.main() if __name__ == '__main__': diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 2b63810d53981e..fc9149dbd8d363 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -11,7 +11,7 @@ @support.requires_subprocess() -class TestTool(unittest.TestCase): +class TestMain(unittest.TestCase): data = """ [["blorpie"],[ "whoops" ] , [ @@ -19,6 +19,9 @@ class TestTool(unittest.TestCase): "i-vhbjkhnth", {"nifty":87}, {"morefield" :\tfalse,"field" :"yes"} ] """ + module = 'json' + env_vars = {} + warnings_expected = False expect_without_sort_keys = textwrap.dedent("""\ [ @@ -87,10 +90,11 @@ class TestTool(unittest.TestCase): """) def test_stdin_stdout(self): - args = sys.executable, '-m', 'json.tool' + args = sys.executable, '-m', self.module process = subprocess.run(args, input=self.data, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, self.expect) - self.assertEqual(process.stderr, '') + if not self.warnings_expected: + self.assertEqual(process.stderr, '') def _create_infile(self, data=None): infile = os_helper.TESTFN @@ -101,7 +105,7 @@ def _create_infile(self, data=None): def test_infile_stdout(self): infile = self._create_infile() - rc, out, err = assert_python_ok('-m', 'json.tool', infile) + rc, out, err = assert_python_ok('-m', self.module, infile, **self.env_vars) self.assertEqual(rc, 0) self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) self.assertEqual(err, b'') @@ -115,7 +119,7 @@ def test_non_ascii_infile(self): ''').encode() infile = self._create_infile(data) - rc, out, err = assert_python_ok('-m', 'json.tool', infile) + rc, out, err = assert_python_ok('-m', self.module, infile, **self.env_vars) self.assertEqual(rc, 0) self.assertEqual(out.splitlines(), expect.splitlines()) @@ -124,7 +128,7 @@ def test_non_ascii_infile(self): def test_infile_outfile(self): infile = self._create_infile() outfile = os_helper.TESTFN + '.out' - rc, out, err = assert_python_ok('-m', 'json.tool', infile, outfile) + rc, out, err = assert_python_ok('-m', self.module, infile, outfile, **self.env_vars) self.addCleanup(os.remove, outfile) with open(outfile, "r", encoding="utf-8") as fp: self.assertEqual(fp.read(), self.expect) @@ -134,7 +138,7 @@ def test_infile_outfile(self): def test_writing_in_place(self): infile = self._create_infile() - rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile) + rc, out, err = assert_python_ok('-m', self.module, infile, infile, **self.env_vars) with open(infile, "r", encoding="utf-8") as fp: self.assertEqual(fp.read(), self.expect) self.assertEqual(rc, 0) @@ -142,20 +146,21 @@ def test_writing_in_place(self): self.assertEqual(err, b'') def test_jsonlines(self): - args = sys.executable, '-m', 'json.tool', '--json-lines' + args = sys.executable, '-m', self.module, '--json-lines' 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, '') + if not self.warnings_expected: + self.assertEqual(process.stderr, '') def test_help_flag(self): - rc, out, err = assert_python_ok('-m', 'json.tool', '-h') + rc, out, err = assert_python_ok('-m', self.module, '-h', **self.env_vars) self.assertEqual(rc, 0) self.assertTrue(out.startswith(b'usage: ')) self.assertEqual(err, b'') def test_sort_keys_flag(self): infile = self._create_infile() - rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) + rc, out, err = assert_python_ok('-m', self.module, '--sort-keys', infile, **self.env_vars) self.assertEqual(rc, 0) self.assertEqual(out.splitlines(), self.expect_without_sort_keys.encode().splitlines()) @@ -169,40 +174,44 @@ def test_indent(self): 2 ] ''') - args = sys.executable, '-m', 'json.tool', '--indent', '2' + args = sys.executable, '-m', self.module, '--indent', '2' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) - self.assertEqual(process.stderr, '') + if not self.warnings_expected: + self.assertEqual(process.stderr, '') def test_no_indent(self): input_ = '[1,\n2]' expect = '[1, 2]\n' - args = sys.executable, '-m', 'json.tool', '--no-indent' + args = sys.executable, '-m', self.module, '--no-indent' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) - self.assertEqual(process.stderr, '') + if not self.warnings_expected: + self.assertEqual(process.stderr, '') def test_tab(self): input_ = '[1, 2]' expect = '[\n\t1,\n\t2\n]\n' - args = sys.executable, '-m', 'json.tool', '--tab' + args = sys.executable, '-m', self.module, '--tab' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) - self.assertEqual(process.stderr, '') + if not self.warnings_expected: + self.assertEqual(process.stderr, '') def test_compact(self): input_ = '[ 1 ,\n 2]' expect = '[1,2]\n' - args = sys.executable, '-m', 'json.tool', '--compact' + args = sys.executable, '-m', self.module, '--compact' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) - self.assertEqual(process.stderr, '') + if not self.warnings_expected: + self.assertEqual(process.stderr, '') def test_no_ensure_ascii_flag(self): infile = self._create_infile('{"key":"💩"}') outfile = os_helper.TESTFN + '.out' self.addCleanup(os.remove, outfile) - assert_python_ok('-m', 'json.tool', '--no-ensure-ascii', infile, outfile) + assert_python_ok('-m', self.module, '--no-ensure-ascii', infile, outfile, **self.env_vars) with open(outfile, "rb") as f: lines = f.read().splitlines() # asserting utf-8 encoded output file @@ -213,7 +222,7 @@ def test_ensure_ascii_default(self): infile = self._create_infile('{"key":"💩"}') outfile = os_helper.TESTFN + '.out' self.addCleanup(os.remove, outfile) - assert_python_ok('-m', 'json.tool', infile, outfile) + assert_python_ok('-m', self.module, infile, outfile, **self.env_vars) with open(outfile, "rb") as f: lines = f.read().splitlines() # asserting an ascii encoded output file @@ -222,11 +231,27 @@ def test_ensure_ascii_default(self): @unittest.skipIf(sys.platform =="win32", "The test is failed with ValueError on Windows") def test_broken_pipe_error(self): - cmd = [sys.executable, '-m', 'json.tool'] + cmd = [sys.executable, '-m', self.module] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) - # bpo-39828: Closing before json.tool attempts to write into stdout. + # bpo-39828: Closing before json attempts to write into stdout. proc.stdout.close() proc.communicate(b'"{}"') self.assertEqual(proc.returncode, errno.EPIPE) + + +@support.requires_subprocess() +class TestTool(TestMain): + module = 'json.tool' + env_vars = {'PYTHONWARNINGS': 'ignore'} + warnings_expected = True + + def test_with_warnings(self): + import json.tool + filename = json.tool.__file__ + infile = self._create_infile() + rc, out, err = assert_python_ok('-m', self.module, infile) + self.assertEqual(rc, 0) + self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) + self.assertEqual(err.decode(), f'{filename}:15: DeprecationWarning: The json.tool module is deprecated\n main()\n') From 5600afa497024989bad7a2a3ce0b5eb15b9d2541 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Fri, 2 Aug 2024 13:37:15 -0700 Subject: [PATCH 4/4] Move main function from json.__main__ to json.tool --- Lib/json/__main__.py | 76 ++------------------------------- Lib/json/tool.py | 72 ++++++++++++++++++++++++++++--- Lib/test/test_json/test_tool.py | 3 +- 3 files changed, 73 insertions(+), 78 deletions(-) diff --git a/Lib/json/__main__.py b/Lib/json/__main__.py index fdfc3372bcca02..7d2dc2ff02e32d 100644 --- a/Lib/json/__main__.py +++ b/Lib/json/__main__.py @@ -2,88 +2,20 @@ Usage:: - $ echo '{"json":"obj"}' | python -m json.tool + $ echo '{"json":"obj"}' | python -m json { "json": "obj" } - $ echo '{ 1.2:3.4}' | python -m json.tool + $ echo '{ 1.2:3.4}' | python -m json Expecting property name enclosed in double quotes: line 1 column 3 (char 2) """ -import argparse -import json +import json.tool import sys -def main(): - 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='?', - help='a JSON file to be validated or pretty-printed', - default='-') - parser.add_argument('outfile', nargs='?', - help='write the output of infile to outfile', - default=None) - parser.add_argument('--sort-keys', action='store_true', default=False, - help='sort the output of dictionaries alphabetically by key') - parser.add_argument('--no-ensure-ascii', dest='ensure_ascii', action='store_false', - help='disable escaping of non-ASCII characters') - parser.add_argument('--json-lines', action='store_true', default=False, - 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 ' - 'of spaces for indentation') - group.add_argument('--tab', action='store_const', dest='indent', - const='\t', help='separate items with newlines and use ' - 'tabs for indentation') - group.add_argument('--no-indent', action='store_const', dest='indent', - const=None, - help='separate items with spaces rather than newlines') - group.add_argument('--compact', action='store_true', - help='suppress all whitespace separation (most compact)') - options = parser.parse_args() - - dump_args = { - 'sort_keys': options.sort_keys, - 'indent': options.indent, - 'ensure_ascii': options.ensure_ascii, - } - if options.compact: - dump_args['indent'] = None - dump_args['separators'] = ',', ':' - - try: - if options.infile == '-': - infile = sys.stdin - else: - infile = open(options.infile, encoding='utf-8') - try: - if options.json_lines: - objs = (json.loads(line) for line in infile) - else: - objs = (json.load(infile),) - finally: - if infile is not sys.stdin: - infile.close() - - if options.outfile is None: - outfile = sys.stdout - else: - outfile = open(options.outfile, 'w', encoding='utf-8') - with outfile: - for obj in objs: - json.dump(obj, outfile, **dump_args) - outfile.write('\n') - except ValueError as e: - raise SystemExit(e) - - if __name__ == '__main__': try: - main() + json.tool.main() except BrokenPipeError as exc: sys.exit(exc.errno) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index fb9e4592b411c2..615343acc4e729 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -1,16 +1,78 @@ +import argparse +import json import sys import warnings -from . import __main__ - def main(): - warnings.warn('The json.tool module is deprecated', - DeprecationWarning, stacklevel=2) - __main__.main() + 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='?', + help='a JSON file to be validated or pretty-printed', + default='-') + parser.add_argument('outfile', nargs='?', + help='write the output of infile to outfile', + default=None) + parser.add_argument('--sort-keys', action='store_true', default=False, + help='sort the output of dictionaries alphabetically by key') + parser.add_argument('--no-ensure-ascii', dest='ensure_ascii', action='store_false', + help='disable escaping of non-ASCII characters') + parser.add_argument('--json-lines', action='store_true', default=False, + 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 ' + 'of spaces for indentation') + group.add_argument('--tab', action='store_const', dest='indent', + const='\t', help='separate items with newlines and use ' + 'tabs for indentation') + group.add_argument('--no-indent', action='store_const', dest='indent', + const=None, + help='separate items with spaces rather than newlines') + group.add_argument('--compact', action='store_true', + help='suppress all whitespace separation (most compact)') + options = parser.parse_args() + + dump_args = { + 'sort_keys': options.sort_keys, + 'indent': options.indent, + 'ensure_ascii': options.ensure_ascii, + } + if options.compact: + dump_args['indent'] = None + dump_args['separators'] = ',', ':' + + try: + if options.infile == '-': + infile = sys.stdin + else: + infile = open(options.infile, encoding='utf-8') + try: + if options.json_lines: + objs = (json.loads(line) for line in infile) + else: + objs = (json.load(infile),) + finally: + if infile is not sys.stdin: + infile.close() + + if options.outfile is None: + outfile = sys.stdout + else: + outfile = open(options.outfile, 'w', encoding='utf-8') + with outfile: + for obj in objs: + json.dump(obj, outfile, **dump_args) + outfile.write('\n') + except ValueError as e: + raise SystemExit(e) if __name__ == '__main__': + warnings.warn('The json.tool module is deprecated', DeprecationWarning) try: main() except BrokenPipeError as exc: diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index fc9149dbd8d363..eb568359c6b132 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -254,4 +254,5 @@ def test_with_warnings(self): rc, out, err = assert_python_ok('-m', self.module, infile) self.assertEqual(rc, 0) self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) - self.assertEqual(err.decode(), f'{filename}:15: DeprecationWarning: The json.tool module is deprecated\n main()\n') + self.assertRegex(err.decode(), + r'^.+/json/tool\.py:\d+: DeprecationWarning: The json.tool module is deprecated\n.+\n$') pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy