From 04b2ade751b318460c1f0f9566676ef519358328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 22 Jun 2018 23:51:43 +0200 Subject: [PATCH 01/11] bpo-33927: Add support for same infile and outfile to json.tool --- Lib/json/tool.py | 5 +++-- Lib/test/test_json/test_tool.py | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 5932f4ecded7eb..b61c5b5f84ff25 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -22,20 +22,21 @@ def main(): 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'), + parser.add_argument('outfile', nargs='?', default='-', help='write the output of infile to outfile') parser.add_argument('--sort-keys', action='store_true', default=False, help='sort the output of dictionaries alphabetically by key') options = parser.parse_args() infile = options.infile or sys.stdin - outfile = options.outfile or sys.stdout sort_keys = options.sort_keys with infile: try: obj = json.load(infile) except ValueError as e: raise SystemExit(e) + + outfile = sys.stdout if options.outfile == '-' else open(options.outfile, 'w') with outfile: json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 9d93f931ca3958..cff69a17474c3f 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -92,6 +92,13 @@ def test_infile_outfile(self): self.assertEqual(out, b'') self.assertEqual(err, b'') + def test_infile_same_outfile(self): + infile = self._create_infile() + rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile) + 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) From 23593fb76c999ed96583b87d5d4873d5383215a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Tue, 26 Jun 2018 21:44:56 +0200 Subject: [PATCH 02/11] Fix error message on IOError --- Lib/json/tool.py | 5 ++++- Lib/test/test_json/test_tool.py | 11 ++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index b61c5b5f84ff25..d56700d1941ffe 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -36,7 +36,10 @@ def main(): except ValueError as e: raise SystemExit(e) - outfile = sys.stdout if options.outfile == '-' else open(options.outfile, 'w') + try: + outfile = sys.stdout if options.outfile == '-' else open(options.outfile, 'w') + except IOError as e: + parser.error("can't open '{}': {}".format(options.outfile, str(e))) with outfile: json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index cff69a17474c3f..a7dbccbc78d054 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -4,7 +4,7 @@ import unittest from subprocess import Popen, PIPE from test import support -from test.support.script_helper import assert_python_ok +from test.support.script_helper import assert_python_ok, assert_python_failure class TestTool(unittest.TestCase): @@ -99,6 +99,15 @@ def test_infile_same_outfile(self): self.assertEqual(out, b'') self.assertEqual(err, b'') + def test_unavailable_outfile(self): + infile = self._create_infile() + rc, out, err = assert_python_failure('-m', 'json.tool', infile, '/bla/outfile') + self.assertEqual(rc, 2) + self.assertEqual(out, b'') + err = err.decode().splitlines() + self.assertEqual(err[0], 'usage: python -m json.tool [-h] [--sort-keys] [infile] [outfile]') + self.assertEqual(err[1], "python -m json.tool: error: can't open '/bla/outfile': [Errno 2] No such file or directory: '/bla/outfile'") + def test_help_flag(self): rc, out, err = assert_python_ok('-m', 'json.tool', '-h') self.assertEqual(rc, 0) From 6cae5c57204a2f19efd759b3afd2cc17386bbace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Wed, 27 Jun 2018 14:46:34 +0200 Subject: [PATCH 03/11] Add Misc/NEWS entry --- .../next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst diff --git a/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst b/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst new file mode 100644 index 00000000000000..1a75f88f912e2e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst @@ -0,0 +1,2 @@ +`json.tool` can now take the same file as input and ouput. Patch by Rémi +Lapeyre. From ed871c61720789a4267fa1fa7feb70d76a106527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 29 Jun 2018 20:39:58 +0200 Subject: [PATCH 04/11] Add fd leakage tests --- Lib/test/test_json/test_tool.py | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index a7dbccbc78d054..19735fb82f021a 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -1,10 +1,13 @@ +import io import os import sys import textwrap import unittest +import types from subprocess import Popen, PIPE from test import support from test.support.script_helper import assert_python_ok, assert_python_failure +from unittest import mock class TestTool(unittest.TestCase): @@ -121,3 +124,55 @@ def test_sort_keys_flag(self): self.assertEqual(out.splitlines(), self.expect_without_sort_keys.encode().splitlines()) self.assertEqual(err, b'') + + def test_no_fd_leak_infile_outfile(self): + closed = [] + opened = [] + io_open = io.open + + def open(*args, **kwargs): + fd = io_open(*args, **kwargs) + opened.append(fd) + fd_close = fd.close + def close(self): + closed.append(self) + fd_close() + fd.close = types.MethodType(close, fd) + return fd + + infile = self._create_infile() + with mock.patch('builtins.open', side_effect=open): + with mock.patch.object(sys, 'argv', ['tool.py', infile, infile + '.out']): + import json.tool + json.tool.main() + + os.unlink(infile + '.out') + self.assertEqual(opened, closed) + self.assertEqual(len(opened), len(closed)) + + def test_no_fd_leak_same_infile_outfile(self): + closed = [] + opened = [] + io_open = io.open + + def open(*args, **kwargs): + fd = io_open(*args, **kwargs) + opened.append(fd) + fd_close = fd.close + def close(self): + closed.append(self) + fd_close() + fd.close = types.MethodType(close, fd) + return fd + + infile = self._create_infile() + with mock.patch('builtins.open', side_effect=open): + with mock.patch.object(sys, 'argv', ['tool.py', infile, infile]): + try: + import json.tool + json.tool.main() + except SystemExit: # We expect SystemExit to happen on c9d43c + pass + + self.assertEqual(opened, closed) + self.assertEqual(len(opened), len(closed)) From 48fd5619d866a30b65f4a1cfd5234cd464c38eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Sat, 3 Nov 2018 15:21:42 +0100 Subject: [PATCH 05/11] Clean json_tools tests --- Lib/json/tool.py | 2 +- Lib/test/test_json/test_tool.py | 57 ++++++++++++--------------------- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index d56700d1941ffe..c4008681e5e401 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -39,7 +39,7 @@ def main(): try: outfile = sys.stdout if options.outfile == '-' else open(options.outfile, 'w') except IOError as e: - parser.error("can't open '{}': {}".format(options.outfile, str(e))) + parser.error(f"can't open '{options.outfile}': {str(e)}") with outfile: json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 19735fb82f021a..54a2cd56ec6b54 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -80,7 +80,6 @@ def _create_infile(self): 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'') @@ -91,14 +90,12 @@ def test_infile_outfile(self): 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_infile_same_outfile(self): infile = self._create_infile() rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile) - self.assertEqual(rc, 0) self.assertEqual(out, b'') self.assertEqual(err, b'') @@ -107,40 +104,23 @@ def test_unavailable_outfile(self): rc, out, err = assert_python_failure('-m', 'json.tool', infile, '/bla/outfile') self.assertEqual(rc, 2) self.assertEqual(out, b'') - err = err.decode().splitlines() - self.assertEqual(err[0], 'usage: python -m json.tool [-h] [--sort-keys] [infile] [outfile]') - self.assertEqual(err[1], "python -m json.tool: error: can't open '/bla/outfile': [Errno 2] No such file or directory: '/bla/outfile'") + self.assertIn(b"error: can't open '/bla/outfile': [Errno 2]", err) 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'') def test_sort_keys_flag(self): infile = self._create_infile() rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) - self.assertEqual(rc, 0) self.assertEqual(out.splitlines(), self.expect_without_sort_keys.encode().splitlines()) self.assertEqual(err, b'') def test_no_fd_leak_infile_outfile(self): - closed = [] - opened = [] - io_open = io.open - - def open(*args, **kwargs): - fd = io_open(*args, **kwargs) - opened.append(fd) - fd_close = fd.close - def close(self): - closed.append(self) - fd_close() - fd.close = types.MethodType(close, fd) - return fd - infile = self._create_infile() + closed, opened, open = mock_open() with mock.patch('builtins.open', side_effect=open): with mock.patch.object(sys, 'argv', ['tool.py', infile, infile + '.out']): import json.tool @@ -151,28 +131,31 @@ def close(self): self.assertEqual(len(opened), len(closed)) def test_no_fd_leak_same_infile_outfile(self): - closed = [] - opened = [] - io_open = io.open - - def open(*args, **kwargs): - fd = io_open(*args, **kwargs) - opened.append(fd) - fd_close = fd.close - def close(self): - closed.append(self) - fd_close() - fd.close = types.MethodType(close, fd) - return fd - infile = self._create_infile() + closed, opened, open = mock_open() with mock.patch('builtins.open', side_effect=open): with mock.patch.object(sys, 'argv', ['tool.py', infile, infile]): try: import json.tool json.tool.main() - except SystemExit: # We expect SystemExit to happen on c9d43c + except SystemExit: pass self.assertEqual(opened, closed) self.assertEqual(len(opened), len(closed)) + +def mock_open(): + closed = [] + opened = [] + io_open = io.open + + def _open(*args, **kwargs): + fd = io_open(*args, **kwargs) + opened.append(fd) + fd_close = fd.close + def close(self): + closed.append(self) + fd_close() + fd.close = types.MethodType(close, fd) + return fd + return closed, opened, _open From fe960a5bb6ced5b6b3fd203ff792d00f9886d9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Mon, 25 Feb 2019 18:00:47 +0100 Subject: [PATCH 06/11] Add support for json lines --- Lib/json/tool.py | 62 +++++++++++++------ Lib/test/test_json/test_tool.py | 46 +++++++++++--- .../2018-06-27-14-46-03.bpo-33927.felCrI.rst | 4 +- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index fbd43029ff99c4..07c7ed22c799c4 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -14,13 +14,32 @@ import json import sys +def _read(infile, json_lines): + try: + if json_lines: + return (json.loads(line) for line in infile) + else: + return (json.load(infile), ) + except ValueError as e: + raise SystemExit(e) + +def _open_outfile(outfile, parser): + try: + return sys.stdout if outfile == '-' else open(outfile, 'w') + except IOError as e: + parser.error(f"can't open '{outfile}': {str(e)}") + +def _write(parser, outfile, objs, sort_keys): + for obj in objs: + json.dump(obj, outfile, sort_keys=sort_keys, indent=4) + outfile.write('\n') 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='?', type=argparse.FileType(), + parser.add_argument('infile', nargs='?', type=argparse.FileType(), default=sys.stdin, help='a JSON file to be validated or pretty-printed') parser.add_argument('outfile', nargs='?', default='-', help='write the output of infile to outfile') @@ -28,29 +47,36 @@ def main(): 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') + parser.add_argument('-i', '--in-place', action='store_true', default=False, + help='edit the file in-place') options = parser.parse_args() - infile = options.infile or sys.stdin + if options.in_place: + if options.outfile != '-': + parser.error('outfile cannot be set when -i / --in-place is used') + if options.infile is sys.stdin: + parser.error('infile must be set when -i / --in-place is used') + options.outfile = options.infile.name + + outfile = options.outfile + infile = options.infile sort_keys = options.sort_keys json_lines = options.json_lines - with infile: - try: - if json_lines: - objs = tuple(json.loads(line) for line in infile) - else: - objs = (json.load(infile), ) - except ValueError as e: - raise SystemExit(e) - try: - outfile = sys.stdout if options.outfile == '-' else open(options.outfile, 'w') - except IOError as e: - parser.error(f"can't open '{options.outfile}': {str(e)}") - with outfile: - for obj in objs: - json.dump(obj, outfile, sort_keys=sort_keys, indent=4) - outfile.write('\n') + if options.in_place: + with infile: + objs = tuple(_read(infile, json_lines)) + + outfile = _open_outfile(outfile, parser) + + with outfile: + _write(parser, outfile, objs, sort_keys) + else: + outfile = _open_outfile(outfile, parser) + with infile, outfile: + objs = _read(infile, json_lines) + _write(parser, outfile, objs, sort_keys) if __name__ == '__main__': main() diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 8182da44409d7d..8c0f0228ecd8cf 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -92,11 +92,13 @@ def test_stdin_stdout(self): self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) self.assertEqual(err, b'') - def _create_infile(self): + def _create_infile(self, data=None): + if data is None: + data = self.data infile = support.TESTFN with open(infile, "w") as fp: self.addCleanup(os.remove, infile) - fp.write(self.data) + fp.write(data) return infile def test_infile_stdout(self): @@ -117,7 +119,7 @@ def test_infile_outfile(self): def test_infile_same_outfile(self): infile = self._create_infile() - rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile) + rc, out, err = assert_python_ok('-m', 'json.tool', '-i', infile) self.assertEqual(out, b'') self.assertEqual(err, b'') @@ -130,16 +132,38 @@ def test_unavailable_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()) + proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + out, err = proc.communicate(self.jsonlines_raw.encode()) + proc.wait() + self.assertEqual(proc.returncode, 0) self.assertEqual(err, b'') + self.assertEqual(out.splitlines(), self.jsonlines_expect.encode().splitlines()) def test_help_flag(self): rc, out, err = assert_python_ok('-m', 'json.tool', '-h') self.assertTrue(out.startswith(b'usage: ')) self.assertEqual(err, b'') + def test_inplace_flag(self): + rc, out, err = assert_python_failure('-m', 'json.tool', '-i') + self.assertEqual(out, b'') + self.assertIn(b"error: infile must be set when -i / --in-place is used", err) + + rc, out, err = assert_python_failure('-m', 'json.tool', '-i', '-') + self.assertEqual(out, b'') + self.assertIn(b"error: infile must be set when -i / --in-place is used", err) + + infile = self._create_infile() + rc, out, err = assert_python_failure('-m', 'json.tool', '-i', infile, 'test.json') + self.assertEqual(out, b'') + self.assertIn(b"error: outfile cannot be set when -i / --in-place is used", err) + + def test_inplace_jsonlines(self): + infile = self._create_infile(data=self.jsonlines_raw) + rc, out, err = assert_python_ok('-m', 'json.tool', '--json-lines', '-i', infile) + self.assertEqual(out, b'') + 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) @@ -156,14 +180,15 @@ def test_no_fd_leak_infile_outfile(self): json.tool.main() os.unlink(infile + '.out') - self.assertEqual(opened, closed) - self.assertEqual(len(opened), len(closed)) + self.assertEqual(set(opened), set(closed)) + self.assertEqual(len(opened), 2) + self.assertEqual(len(opened), 2) def test_no_fd_leak_same_infile_outfile(self): infile = self._create_infile() closed, opened, open = mock_open() with mock.patch('builtins.open', side_effect=open): - with mock.patch.object(sys, 'argv', ['tool.py', infile, infile]): + with mock.patch.object(sys, 'argv', ['tool.py', '-i', infile]): try: import json.tool json.tool.main() @@ -171,7 +196,8 @@ def test_no_fd_leak_same_infile_outfile(self): pass self.assertEqual(opened, closed) - self.assertEqual(len(opened), len(closed)) + self.assertEqual(len(opened), 2) + self.assertEqual(len(opened), 2) def mock_open(): closed = [] diff --git a/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst b/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst index 1a75f88f912e2e..544e232ff9dfa7 100644 --- a/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst +++ b/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst @@ -1,2 +1,2 @@ -`json.tool` can now take the same file as input and ouput. Patch by Rémi -Lapeyre. +`json.tool` can now take the same file as input and ouput with the `--in-place` +flag. Patch by Rémi Lapeyre. From e7c868efb5a27d1e1c73f56da57cb18469ca70d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Tue, 26 Feb 2019 10:11:07 +0100 Subject: [PATCH 07/11] Fix indentation level --- Lib/json/tool.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 07c7ed22c799c4..b76b7220fcb716 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -15,13 +15,13 @@ import sys def _read(infile, json_lines): - try: - if json_lines: - return (json.loads(line) for line in infile) - else: - return (json.load(infile), ) - except ValueError as e: - raise SystemExit(e) + try: + if json_lines: + return (json.loads(line) for line in infile) + else: + return (json.load(infile), ) + except ValueError as e: + raise SystemExit(e) def _open_outfile(outfile, parser): try: From 67e2116da7ec7be170c468241a640895fa1ad596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Tue, 26 Feb 2019 10:14:31 +0100 Subject: [PATCH 08/11] Remove unused argument --- Lib/json/tool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index b76b7220fcb716..5d3cc1cc3256df 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -29,7 +29,7 @@ def _open_outfile(outfile, parser): except IOError as e: parser.error(f"can't open '{outfile}': {str(e)}") -def _write(parser, outfile, objs, sort_keys): +def _write(outfile, objs, sort_keys): for obj in objs: json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') @@ -70,13 +70,13 @@ def main(): outfile = _open_outfile(outfile, parser) with outfile: - _write(parser, outfile, objs, sort_keys) + _write(outfile, objs, sort_keys) else: outfile = _open_outfile(outfile, parser) with infile, outfile: objs = _read(infile, json_lines) - _write(parser, outfile, objs, sort_keys) + _write(outfile, objs, sort_keys) if __name__ == '__main__': main() From f99c54cf66a730d1a4dd88d248ecb849f742c78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 29 May 2020 00:59:32 +0200 Subject: [PATCH 09/11] Always open outfile with utf-8 --- Lib/json/tool.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 26e8283d8be365..2b509d2957d467 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -25,7 +25,10 @@ def _read(infile, json_lines): def _open_outfile(outfile, parser): try: - return sys.stdout if outfile == '-' else open(outfile, 'w') + if outfile == '-': + return sys.stdout + else: + return open(outfile, 'w', encoding='utf-8') except IOError as e: parser.error(f"can't open '{outfile}': {str(e)}") From d79a4e3600fa87b788ecafd75c12c07846050647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Sun, 7 Nov 2021 22:02:50 +0100 Subject: [PATCH 10/11] Update Lib/json/tool.py Co-authored-by: Inada Naoki --- Lib/json/tool.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/json/tool.py b/Lib/json/tool.py index 2b509d2957d467..24c00f6e0009e2 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -92,9 +92,7 @@ def main(): with options.infile as infile: objs = tuple(_read(infile, options.json_lines)) - outfile = _open_outfile(options.outfile, parser) - - with outfile: + with _open_outfile(options.outfile, parser) as outfile: _write(outfile, objs, **dump_args) else: From 1490e2b1b3f38bb9bf80c56ed42a8fdfee2480dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Sun, 7 Nov 2021 22:02:57 +0100 Subject: [PATCH 11/11] Update Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst Co-authored-by: Inada Naoki --- .../next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst b/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst index 544e232ff9dfa7..f66bd63e101b79 100644 --- a/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst +++ b/Misc/NEWS.d/next/Library/2018-06-27-14-46-03.bpo-33927.felCrI.rst @@ -1,2 +1,2 @@ -`json.tool` can now take the same file as input and ouput with the `--in-place` +``json.tool`` can now take the same file as input and ouput with the ``--in-place`` flag. Patch by Rémi Lapeyre.