]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-45644: Make json.tool read infile before writing to outfile (GH-29273)
authorChris Wesseling <chris.wesseling@protonmail.com>
Sat, 6 Nov 2021 17:11:35 +0000 (18:11 +0100)
committerGitHub <noreply@github.com>
Sat, 6 Nov 2021 17:11:35 +0000 (18:11 +0100)
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>
Lib/json/tool.py
Lib/test/test_json/test_tool.py
Misc/NEWS.d/next/Library/2021-11-06-17-47-46.bpo-45644.ZMqHD_.rst [new file with mode: 0644]

index 5dee0a744b2a99e1e88c52dfecfec56a8598d10f..0490b8c0be11dfec924f5dc075e42961d364bf91 100644 (file)
@@ -13,6 +13,7 @@ Usage::
 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)
 
index 0386690cad95beb1ea5858bb0a8ba8cdf4a75458..1d7fca6efb1cc725aae787fe4a0df421d598eb85 100644 (file)
@@ -131,6 +131,15 @@ class TestTool(unittest.TestCase):
         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)
diff --git a/Misc/NEWS.d/next/Library/2021-11-06-17-47-46.bpo-45644.ZMqHD_.rst b/Misc/NEWS.d/next/Library/2021-11-06-17-47-46.bpo-45644.ZMqHD_.rst
new file mode 100644 (file)
index 0000000..2cf4eae
--- /dev/null
@@ -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.