Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 906b796

Browse filesBrowse files
treyhunnerAA-Turnerhugovkncoghlan
authored
gh-122873: Allow "python -m json" to work (#122884)
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
1 parent db6f5e1 commit 906b796
Copy full SHA for 906b796

File tree

Expand file treeCollapse file tree

8 files changed

+77
-45
lines changed
Filter options
Expand file treeCollapse file tree

8 files changed

+77
-45
lines changed

‎Doc/library/cmdline.rst

Copy file name to clipboardExpand all lines: Doc/library/cmdline.rst
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The following modules have a command-line interface.
2323
* :ref:`http.server <http-server-cli>`
2424
* :mod:`!idlelib`
2525
* :ref:`inspect <inspect-module-cli>`
26-
* :ref:`json.tool <json-commandline>`
26+
* :ref:`json <json-commandline>`
2727
* :mod:`mimetypes`
2828
* :mod:`pdb`
2929
* :mod:`pickle`

‎Doc/library/json.rst

Copy file name to clipboardExpand all lines: Doc/library/json.rst
+18-12Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ Extending :class:`JSONEncoder`::
116116
['[2.0', ', 1.0', ']']
117117

118118

119-
Using :mod:`json.tool` from the shell to validate and pretty-print:
119+
Using :mod:`json` from the shell to validate and pretty-print:
120120

121121
.. code-block:: shell-session
122122
123-
$ echo '{"json":"obj"}' | python -m json.tool
123+
$ echo '{"json":"obj"}' | python -m json
124124
{
125125
"json": "obj"
126126
}
127-
$ echo '{1.2:3.4}' | python -m json.tool
127+
$ echo '{1.2:3.4}' | python -m json
128128
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
129129
130130
See :ref:`json-commandline` for detailed documentation.
@@ -678,40 +678,46 @@ when serializing instances of "exotic" numerical types such as
678678

679679

680680
.. _json-commandline:
681-
.. program:: json.tool
681+
.. program:: json
682682

683-
Command Line Interface
683+
Command-line interface
684684
----------------------
685685

686686
.. module:: json.tool
687-
:synopsis: A command line to validate and pretty-print JSON.
687+
:synopsis: A command-line interface to validate and pretty-print JSON.
688688

689689
**Source code:** :source:`Lib/json/tool.py`
690690

691691
--------------
692692

693-
The :mod:`json.tool` module provides a simple command line interface to validate
694-
and pretty-print JSON objects.
693+
The :mod:`json` module can be invoked as a script via ``python -m json``
694+
to validate and pretty-print JSON objects. The :mod:`json.tool` submodule
695+
implements this interface.
695696

696697
If the optional ``infile`` and ``outfile`` arguments are not
697698
specified, :data:`sys.stdin` and :data:`sys.stdout` will be used respectively:
698699

699700
.. code-block:: shell-session
700701
701-
$ echo '{"json": "obj"}' | python -m json.tool
702+
$ echo '{"json": "obj"}' | python -m json
702703
{
703704
"json": "obj"
704705
}
705-
$ echo '{1.2:3.4}' | python -m json.tool
706+
$ echo '{1.2:3.4}' | python -m json
706707
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
707708
708709
.. versionchanged:: 3.5
709710
The output is now in the same order as the input. Use the
710711
:option:`--sort-keys` option to sort the output of dictionaries
711712
alphabetically by key.
712713

714+
.. versionchanged:: 3.14
715+
The :mod:`json` module may now be directly executed as
716+
``python -m json``. For backwards compatibility, invoking
717+
the CLI as ``python -m json.tool`` remains supported.
713718

714-
Command line options
719+
720+
Command-line options
715721
^^^^^^^^^^^^^^^^^^^^
716722

717723
.. option:: infile
@@ -720,7 +726,7 @@ Command line options
720726

721727
.. code-block:: shell-session
722728
723-
$ python -m json.tool mp_films.json
729+
$ python -m json mp_films.json
724730
[
725731
{
726732
"title": "And Now for Something Completely Different",

‎Doc/whatsnew/3.14.rst

Copy file name to clipboardExpand all lines: Doc/whatsnew/3.14.rst
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ Add notes for JSON serialization errors that allow to identify the source
124124
of the error.
125125
(Contributed by Serhiy Storchaka in :gh:`122163`.)
126126

127+
Enable :mod:`json` module to work as a script using the :option:`-m` switch: ``python -m json``.
128+
See the :ref:`JSON command-line interface <json-commandline>` documentation.
129+
(Contributed by Trey Hunner in :gh:`122873`.)
130+
127131
operator
128132
--------
129133

‎Lib/json/__init__.py

Copy file name to clipboardExpand all lines: Lib/json/__init__.py
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@
8686
'[2.0, 1.0]'
8787
8888
89-
Using json.tool from the shell to validate and pretty-print::
89+
Using json from the shell to validate and pretty-print::
9090
91-
$ echo '{"json":"obj"}' | python -m json.tool
91+
$ echo '{"json":"obj"}' | python -m json
9292
{
9393
"json": "obj"
9494
}
95-
$ echo '{ 1.2:3.4}' | python -m json.tool
95+
$ echo '{ 1.2:3.4}' | python -m json
9696
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
9797
"""
9898
__version__ = '2.0.9'

‎Lib/json/__main__.py

Copy file name to clipboard
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Command-line tool to validate and pretty-print JSON
2+
3+
Usage::
4+
5+
$ echo '{"json":"obj"}' | python -m json
6+
{
7+
"json": "obj"
8+
}
9+
$ echo '{ 1.2:3.4}' | python -m json
10+
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
11+
12+
"""
13+
import json.tool
14+
15+
16+
if __name__ == '__main__':
17+
try:
18+
json.tool.main()
19+
except BrokenPipeError as exc:
20+
raise SystemExit(exc.errno)

‎Lib/json/tool.py

Copy file name to clipboardExpand all lines: Lib/json/tool.py
+5-12Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
1-
r"""Command-line tool to validate and pretty-print JSON
2-
3-
Usage::
4-
5-
$ echo '{"json":"obj"}' | python -m json.tool
6-
{
7-
"json": "obj"
8-
}
9-
$ echo '{ 1.2:3.4}' | python -m json.tool
10-
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
1+
"""Command-line tool to validate and pretty-print JSON
112
3+
See `json.__main__` for a usage example (invocation as
4+
`python -m json.tool` is supported for backwards compatibility).
125
"""
136
import argparse
147
import json
158
import sys
169

1710

1811
def main():
19-
prog = 'python -m json.tool'
12+
prog = 'python -m json'
2013
description = ('A simple command line interface for json module '
2114
'to validate and pretty-print JSON objects.')
2215
parser = argparse.ArgumentParser(prog=prog, description=description)
@@ -86,4 +79,4 @@ def main():
8679
try:
8780
main()
8881
except BrokenPipeError as exc:
89-
sys.exit(exc.errno)
82+
raise SystemExit(exc.errno)

‎Lib/test/test_json/test_tool.py

Copy file name to clipboardExpand all lines: Lib/test/test_json/test_tool.py
+23-17Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111

1212

1313
@support.requires_subprocess()
14-
class TestTool(unittest.TestCase):
14+
class TestMain(unittest.TestCase):
1515
data = """
1616
1717
[["blorpie"],[ "whoops" ] , [
1818
],\t"d-shtaeou",\r"d-nthiouh",
1919
"i-vhbjkhnth", {"nifty":87}, {"morefield" :\tfalse,"field"
2020
:"yes"} ]
2121
"""
22+
module = 'json'
2223

2324
expect_without_sort_keys = textwrap.dedent("""\
2425
[
@@ -87,7 +88,7 @@ class TestTool(unittest.TestCase):
8788
""")
8889

8990
def test_stdin_stdout(self):
90-
args = sys.executable, '-m', 'json.tool'
91+
args = sys.executable, '-m', self.module
9192
process = subprocess.run(args, input=self.data, capture_output=True, text=True, check=True)
9293
self.assertEqual(process.stdout, self.expect)
9394
self.assertEqual(process.stderr, '')
@@ -101,7 +102,7 @@ def _create_infile(self, data=None):
101102

102103
def test_infile_stdout(self):
103104
infile = self._create_infile()
104-
rc, out, err = assert_python_ok('-m', 'json.tool', infile)
105+
rc, out, err = assert_python_ok('-m', self.module, infile)
105106
self.assertEqual(rc, 0)
106107
self.assertEqual(out.splitlines(), self.expect.encode().splitlines())
107108
self.assertEqual(err, b'')
@@ -115,7 +116,7 @@ def test_non_ascii_infile(self):
115116
''').encode()
116117

117118
infile = self._create_infile(data)
118-
rc, out, err = assert_python_ok('-m', 'json.tool', infile)
119+
rc, out, err = assert_python_ok('-m', self.module, infile)
119120

120121
self.assertEqual(rc, 0)
121122
self.assertEqual(out.splitlines(), expect.splitlines())
@@ -124,7 +125,7 @@ def test_non_ascii_infile(self):
124125
def test_infile_outfile(self):
125126
infile = self._create_infile()
126127
outfile = os_helper.TESTFN + '.out'
127-
rc, out, err = assert_python_ok('-m', 'json.tool', infile, outfile)
128+
rc, out, err = assert_python_ok('-m', self.module, infile, outfile)
128129
self.addCleanup(os.remove, outfile)
129130
with open(outfile, "r", encoding="utf-8") as fp:
130131
self.assertEqual(fp.read(), self.expect)
@@ -134,28 +135,28 @@ def test_infile_outfile(self):
134135

135136
def test_writing_in_place(self):
136137
infile = self._create_infile()
137-
rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile)
138+
rc, out, err = assert_python_ok('-m', self.module, infile, infile)
138139
with open(infile, "r", encoding="utf-8") as fp:
139140
self.assertEqual(fp.read(), self.expect)
140141
self.assertEqual(rc, 0)
141142
self.assertEqual(out, b'')
142143
self.assertEqual(err, b'')
143144

144145
def test_jsonlines(self):
145-
args = sys.executable, '-m', 'json.tool', '--json-lines'
146+
args = sys.executable, '-m', self.module, '--json-lines'
146147
process = subprocess.run(args, input=self.jsonlines_raw, capture_output=True, text=True, check=True)
147148
self.assertEqual(process.stdout, self.jsonlines_expect)
148149
self.assertEqual(process.stderr, '')
149150

150151
def test_help_flag(self):
151-
rc, out, err = assert_python_ok('-m', 'json.tool', '-h')
152+
rc, out, err = assert_python_ok('-m', self.module, '-h')
152153
self.assertEqual(rc, 0)
153154
self.assertTrue(out.startswith(b'usage: '))
154155
self.assertEqual(err, b'')
155156

156157
def test_sort_keys_flag(self):
157158
infile = self._create_infile()
158-
rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile)
159+
rc, out, err = assert_python_ok('-m', self.module, '--sort-keys', infile)
159160
self.assertEqual(rc, 0)
160161
self.assertEqual(out.splitlines(),
161162
self.expect_without_sort_keys.encode().splitlines())
@@ -169,31 +170,31 @@ def test_indent(self):
169170
2
170171
]
171172
''')
172-
args = sys.executable, '-m', 'json.tool', '--indent', '2'
173+
args = sys.executable, '-m', self.module, '--indent', '2'
173174
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
174175
self.assertEqual(process.stdout, expect)
175176
self.assertEqual(process.stderr, '')
176177

177178
def test_no_indent(self):
178179
input_ = '[1,\n2]'
179180
expect = '[1, 2]\n'
180-
args = sys.executable, '-m', 'json.tool', '--no-indent'
181+
args = sys.executable, '-m', self.module, '--no-indent'
181182
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
182183
self.assertEqual(process.stdout, expect)
183184
self.assertEqual(process.stderr, '')
184185

185186
def test_tab(self):
186187
input_ = '[1, 2]'
187188
expect = '[\n\t1,\n\t2\n]\n'
188-
args = sys.executable, '-m', 'json.tool', '--tab'
189+
args = sys.executable, '-m', self.module, '--tab'
189190
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
190191
self.assertEqual(process.stdout, expect)
191192
self.assertEqual(process.stderr, '')
192193

193194
def test_compact(self):
194195
input_ = '[ 1 ,\n 2]'
195196
expect = '[1,2]\n'
196-
args = sys.executable, '-m', 'json.tool', '--compact'
197+
args = sys.executable, '-m', self.module, '--compact'
197198
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
198199
self.assertEqual(process.stdout, expect)
199200
self.assertEqual(process.stderr, '')
@@ -202,7 +203,7 @@ def test_no_ensure_ascii_flag(self):
202203
infile = self._create_infile('{"key":"💩"}')
203204
outfile = os_helper.TESTFN + '.out'
204205
self.addCleanup(os.remove, outfile)
205-
assert_python_ok('-m', 'json.tool', '--no-ensure-ascii', infile, outfile)
206+
assert_python_ok('-m', self.module, '--no-ensure-ascii', infile, outfile)
206207
with open(outfile, "rb") as f:
207208
lines = f.read().splitlines()
208209
# asserting utf-8 encoded output file
@@ -213,7 +214,7 @@ def test_ensure_ascii_default(self):
213214
infile = self._create_infile('{"key":"💩"}')
214215
outfile = os_helper.TESTFN + '.out'
215216
self.addCleanup(os.remove, outfile)
216-
assert_python_ok('-m', 'json.tool', infile, outfile)
217+
assert_python_ok('-m', self.module, infile, outfile)
217218
with open(outfile, "rb") as f:
218219
lines = f.read().splitlines()
219220
# asserting an ascii encoded output file
@@ -222,11 +223,16 @@ def test_ensure_ascii_default(self):
222223

223224
@unittest.skipIf(sys.platform =="win32", "The test is failed with ValueError on Windows")
224225
def test_broken_pipe_error(self):
225-
cmd = [sys.executable, '-m', 'json.tool']
226+
cmd = [sys.executable, '-m', self.module]
226227
proc = subprocess.Popen(cmd,
227228
stdout=subprocess.PIPE,
228229
stdin=subprocess.PIPE)
229-
# bpo-39828: Closing before json.tool attempts to write into stdout.
230+
# bpo-39828: Closing before json attempts to write into stdout.
230231
proc.stdout.close()
231232
proc.communicate(b'"{}"')
232233
self.assertEqual(proc.returncode, errno.EPIPE)
234+
235+
236+
@support.requires_subprocess()
237+
class TestTool(TestMain):
238+
module = 'json.tool'
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Enable :mod:`json` module to work as a script using the :option:`-m` switch: ``python -m json``.
2+
See the :ref:`JSON command-line interface <json-commandline>` documentation.
3+
Patch by Trey Hunner.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.