Skip to content

Commit f194479

Browse files
hongweipengserhiy-storchaka
authored andcommitted
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
1 parent 0e7497c commit f194479

File tree

5 files changed

+53
-5
lines changed

5 files changed

+53
-5
lines changed

Doc/library/json.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,12 @@ Command line options
717717

718718
.. versionadded:: 3.5
719719

720+
.. cmdoption:: --json-lines
721+
722+
Parse every input line as separate JSON object.
723+
724+
.. versionadded:: 3.8
725+
720726
.. cmdoption:: -h, --help
721727

722728
Show the help message.

Doc/whatsnew/3.8.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ by right-clicking the button. (Contributed by Tal Einat in :issue:`1529353`.)
151151
The changes above have been backported to 3.7 maintenance releases.
152152

153153

154+
json.tool
155+
---------
156+
157+
Add option ``--json-lines`` to parse every input line as separate JSON object.
158+
(Contributed by Weipeng Hong in :issue:`31553`.)
159+
154160
os.path
155161
-------
156162

Lib/json/tool.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,25 @@ def main():
2626
help='write the output of infile to outfile')
2727
parser.add_argument('--sort-keys', action='store_true', default=False,
2828
help='sort the output of dictionaries alphabetically by key')
29+
parser.add_argument('--json-lines', action='store_true', default=False,
30+
help='parse input using the jsonlines format')
2931
options = parser.parse_args()
3032

3133
infile = options.infile or sys.stdin
3234
outfile = options.outfile or sys.stdout
3335
sort_keys = options.sort_keys
34-
with infile:
36+
json_lines = options.json_lines
37+
with infile, outfile:
3538
try:
36-
obj = json.load(infile)
39+
if json_lines:
40+
objs = (json.loads(line) for line in infile)
41+
else:
42+
objs = (json.load(infile), )
43+
for obj in objs:
44+
json.dump(obj, outfile, sort_keys=sort_keys, indent=4)
45+
outfile.write('\n')
3746
except ValueError as e:
3847
raise SystemExit(e)
39-
with outfile:
40-
json.dump(obj, outfile, sort_keys=sort_keys, indent=4)
41-
outfile.write('\n')
4248

4349

4450
if __name__ == '__main__':

Lib/test/test_json/test_tool.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,28 @@ class TestTool(unittest.TestCase):
6060
]
6161
""")
6262

63+
jsonlines_raw = textwrap.dedent("""\
64+
{"ingredients":["frog", "water", "chocolate", "glucose"]}
65+
{"ingredients":["chocolate","steel bolts"]}
66+
""")
67+
68+
jsonlines_expect = textwrap.dedent("""\
69+
{
70+
"ingredients": [
71+
"frog",
72+
"water",
73+
"chocolate",
74+
"glucose"
75+
]
76+
}
77+
{
78+
"ingredients": [
79+
"chocolate",
80+
"steel bolts"
81+
]
82+
}
83+
""")
84+
6385
def test_stdin_stdout(self):
6486
args = sys.executable, '-m', 'json.tool'
6587
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
@@ -92,6 +114,13 @@ def test_infile_outfile(self):
92114
self.assertEqual(out, b'')
93115
self.assertEqual(err, b'')
94116

117+
def test_jsonlines(self):
118+
args = sys.executable, '-m', 'json.tool', '--json-lines'
119+
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
120+
out, err = proc.communicate(self.jsonlines_raw.encode())
121+
self.assertEqual(out.splitlines(), self.jsonlines_expect.encode().splitlines())
122+
self.assertEqual(err, b'')
123+
95124
def test_help_flag(self):
96125
rc, out, err = assert_python_ok('-m', 'json.tool', '-h')
97126
self.assertEqual(rc, 0)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add the --json-lines option to json.tool. Patch by hongweipeng.

0 commit comments

Comments
 (0)