bpo-31553: add --json-lines option to json.tool (#10051)
* add jsonlines option to json.tool * code review * fix:avoid read infile after it close * improve doc in whatsnew 3.8
This commit is contained in:
parent
0e7497cb46
commit
f194479949
|
@ -717,6 +717,12 @@ Command line options
|
||||||
|
|
||||||
.. versionadded:: 3.5
|
.. versionadded:: 3.5
|
||||||
|
|
||||||
|
.. cmdoption:: --json-lines
|
||||||
|
|
||||||
|
Parse every input line as separate JSON object.
|
||||||
|
|
||||||
|
.. versionadded:: 3.8
|
||||||
|
|
||||||
.. cmdoption:: -h, --help
|
.. cmdoption:: -h, --help
|
||||||
|
|
||||||
Show the help message.
|
Show the help message.
|
||||||
|
|
|
@ -151,6 +151,12 @@ by right-clicking the button. (Contributed by Tal Einat in :issue:`1529353`.)
|
||||||
The changes above have been backported to 3.7 maintenance releases.
|
The changes above have been backported to 3.7 maintenance releases.
|
||||||
|
|
||||||
|
|
||||||
|
json.tool
|
||||||
|
---------
|
||||||
|
|
||||||
|
Add option ``--json-lines`` to parse every input line as separate JSON object.
|
||||||
|
(Contributed by Weipeng Hong in :issue:`31553`.)
|
||||||
|
|
||||||
os.path
|
os.path
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -26,19 +26,25 @@ def main():
|
||||||
help='write the output of infile to outfile')
|
help='write the output of infile to outfile')
|
||||||
parser.add_argument('--sort-keys', action='store_true', default=False,
|
parser.add_argument('--sort-keys', action='store_true', default=False,
|
||||||
help='sort the output of dictionaries alphabetically by key')
|
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')
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
infile = options.infile or sys.stdin
|
infile = options.infile or sys.stdin
|
||||||
outfile = options.outfile or sys.stdout
|
outfile = options.outfile or sys.stdout
|
||||||
sort_keys = options.sort_keys
|
sort_keys = options.sort_keys
|
||||||
with infile:
|
json_lines = options.json_lines
|
||||||
|
with infile, outfile:
|
||||||
try:
|
try:
|
||||||
obj = json.load(infile)
|
if json_lines:
|
||||||
|
objs = (json.loads(line) for line in infile)
|
||||||
|
else:
|
||||||
|
objs = (json.load(infile), )
|
||||||
|
for obj in objs:
|
||||||
|
json.dump(obj, outfile, sort_keys=sort_keys, indent=4)
|
||||||
|
outfile.write('\n')
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise SystemExit(e)
|
raise SystemExit(e)
|
||||||
with outfile:
|
|
||||||
json.dump(obj, outfile, sort_keys=sort_keys, indent=4)
|
|
||||||
outfile.write('\n')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -60,6 +60,28 @@ class TestTool(unittest.TestCase):
|
||||||
]
|
]
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
jsonlines_raw = textwrap.dedent("""\
|
||||||
|
{"ingredients":["frog", "water", "chocolate", "glucose"]}
|
||||||
|
{"ingredients":["chocolate","steel bolts"]}
|
||||||
|
""")
|
||||||
|
|
||||||
|
jsonlines_expect = textwrap.dedent("""\
|
||||||
|
{
|
||||||
|
"ingredients": [
|
||||||
|
"frog",
|
||||||
|
"water",
|
||||||
|
"chocolate",
|
||||||
|
"glucose"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"ingredients": [
|
||||||
|
"chocolate",
|
||||||
|
"steel bolts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
def test_stdin_stdout(self):
|
def test_stdin_stdout(self):
|
||||||
args = sys.executable, '-m', 'json.tool'
|
args = sys.executable, '-m', 'json.tool'
|
||||||
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
|
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
|
||||||
|
@ -92,6 +114,13 @@ class TestTool(unittest.TestCase):
|
||||||
self.assertEqual(out, b'')
|
self.assertEqual(out, b'')
|
||||||
self.assertEqual(err, b'')
|
self.assertEqual(err, b'')
|
||||||
|
|
||||||
|
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'')
|
||||||
|
|
||||||
def test_help_flag(self):
|
def test_help_flag(self):
|
||||||
rc, out, err = assert_python_ok('-m', 'json.tool', '-h')
|
rc, out, err = assert_python_ok('-m', 'json.tool', '-h')
|
||||||
self.assertEqual(rc, 0)
|
self.assertEqual(rc, 0)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add the --json-lines option to json.tool. Patch by hongweipeng.
|
Loading…
Reference in New Issue