bpo-45644: Make json.tool read infile before writing to outfile (GH-29273)

so that

$ python -m json.tool foo.json foo.json

doesn't result in an empty foo.json.

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
Chris Wesseling 2021-11-06 18:11:35 +01:00 committed by GitHub
parent e9594f6747
commit 815dad42d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 7 deletions

View file

@ -13,6 +13,7 @@
import argparse
import json
import sys
from pathlib import Path
def main():
@ -25,9 +26,9 @@ def main():
help='a JSON file to be validated or pretty-printed',
default=sys.stdin)
parser.add_argument('outfile', nargs='?',
type=argparse.FileType('w', encoding="utf-8"),
type=Path,
help='write the output of infile to outfile',
default=sys.stdout)
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',
@ -58,15 +59,21 @@ def main():
dump_args['indent'] = None
dump_args['separators'] = ',', ':'
with options.infile as infile, options.outfile as outfile:
with options.infile as infile:
try:
if options.json_lines:
objs = (json.loads(line) for line in infile)
else:
objs = (json.load(infile), )
for obj in objs:
json.dump(obj, outfile, **dump_args)
outfile.write('\n')
objs = (json.load(infile),)
if options.outfile is None:
out = sys.stdout
else:
out = options.outfile.open('w', encoding='utf-8')
with out as outfile:
for obj in objs:
json.dump(obj, outfile, **dump_args)
outfile.write('\n')
except ValueError as e:
raise SystemExit(e)

View file

@ -131,6 +131,15 @@ def test_infile_outfile(self):
self.assertEqual(out, b'')
self.assertEqual(err, b'')
def test_writing_in_place(self):
infile = self._create_infile()
rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile)
with open(infile, "r", encoding="utf-8") as fp:
self.assertEqual(fp.read(), self.expect)
self.assertEqual(rc, 0)
self.assertEqual(out, b'')
self.assertEqual(err, b'')
def test_jsonlines(self):
args = sys.executable, '-m', 'json.tool', '--json-lines'
process = subprocess.run(args, input=self.jsonlines_raw, capture_output=True, text=True, check=True)

View file

@ -0,0 +1,3 @@
In-place JSON file formatting using ``python3 -m json.tool infile infile``
now works correctly, previously it left the file empty. Patch by Chris
Wesseling.