Skip to content

bpo-27413: add --no-ensure-ascii argument to json.tool #201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
22 changes: 18 additions & 4 deletions Lib/json/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,38 @@ def main():
help='a JSON file to be validated or pretty-printed')
parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
help='write the output of infile to outfile')
parser.add_argument('--no-ensure-ascii', action='store_true', default=False,
help='Do not escape non-ASCII characters in output.')
group = parser.add_mutually_exclusive_group()
group.add_argument('--indent', default=4, type=int,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed tests for --indent and --no-indent.

help='Indent level (number of spaces) for '
'pretty-printing. Defaults to 4.')
group.add_argument('--no-indent', action='store_const', dest='indent',
const=None, help='Use compact mode.')
parser.add_argument('--sort-keys', action='store_true', default=False,
help='sort the output of dictionaries alphabetically by key')
options = parser.parse_args()

# Read input JSON
infile = options.infile or sys.stdin
outfile = options.outfile or sys.stdout
sort_keys = options.sort_keys
with infile:
try:
if sort_keys:
if options.sort_keys:
obj = json.load(infile)
else:
obj = json.load(infile,
object_pairs_hook=collections.OrderedDict)
except ValueError as e:
raise SystemExit(e)

# Export JSON
outfile = options.outfile or sys.stdout
with outfile:
json.dump(obj, outfile, sort_keys=sort_keys, indent=4)
json.dump(obj, outfile,
indent=options.indent,
ensure_ascii=not options.no_ensure_ascii,
sort_keys=options.sort_keys,
)
outfile.write('\n')


Expand Down
48 changes: 43 additions & 5 deletions Lib/test/test_json/test_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
import textwrap
import unittest
import subprocess
from subprocess import Popen, PIPE
from test import support
from test.support.script_helper import assert_python_ok

Expand Down Expand Up @@ -61,12 +61,11 @@ class TestTool(unittest.TestCase):
""")

def test_stdin_stdout(self):
with subprocess.Popen(
(sys.executable, '-m', 'json.tool'),
stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc:
args = sys.executable, '-m', 'json.tool'
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
out, err = proc.communicate(self.data.encode())
self.assertEqual(out.splitlines(), self.expect.encode().splitlines())
self.assertEqual(err, None)
self.assertEqual(err, b'')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@berkerpeksag is it okay to bundle a change to an unrelated test within these PRs? Previously stderr wasn't being piped, and err would invariably be None even if the process were to fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, --no-ensure-ascii and --indent/--no-indent are two separate enhancements so there should be two pull requests.

@berkerpeksag will keep this PR for --no-ensure-ascii and open a new one for --indent/--no-indent. I think it would make sense to merge the indent PR first, as it's closer to complete.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say open a third pull request for this one (this way we can quickly merge the pipe change) No need to create a new issue on bugs.python.org.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@berkerpeksag opened at #346


def _create_infile(self):
infile = support.TESTFN
Expand Down Expand Up @@ -106,3 +105,42 @@ def test_sort_keys_flag(self):
self.assertEqual(out.splitlines(),
self.expect_without_sort_keys.encode().splitlines())
self.assertEqual(err, b'')

def test_indent(self):
json_stdin = b'[1, 2]'
expect = textwrap.dedent('''\
[
1,
2
]
''').encode()
args = sys.executable, '-m', 'json.tool', '--indent', '2'
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
json_stdout, err = proc.communicate(json_stdin)
self.assertEqual(expect.splitlines(), json_stdout.splitlines())
self.assertEqual(err, b'')

def test_no_indent(self):
json_stdin = b'[1, 2]'
args = sys.executable, '-m', 'json.tool', '--no-indent'
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
json_stdout, err = proc.communicate(json_stdin)
self.assertEqual(json_stdin.splitlines(), json_stdout.splitlines())
self.assertEqual(err, b'')

def test_ensure_ascii(self):
json_stdin = '"\xA7 \N{snake} \u03B4 \U0001D037"'.encode()
expect = b'"\\u00a7 \\ud83d\\udc0d \\u03b4 \\ud834\\udc37"\n'
args = sys.executable, '-m', 'json.tool'
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
json_stdout, err = proc.communicate(json_stdin)
self.assertEqual(expect.splitlines(), json_stdout.splitlines())
self.assertEqual(err, b'')

def test_no_ensure_ascii(self):
json_stdin = '"\xA7 \N{snake} \u03B4 \U0001D037"'.encode()
args = sys.executable, '-m', 'json.tool', '--no-ensure-ascii'
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
json_stdout, err = proc.communicate(json_stdin)
self.assertEqual(json_stdin.splitlines(), json_stdout.splitlines())
self.assertEqual(err, b'')