-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
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
Changes from 3 commits
a47f396
fb5d984
4fb3bb3
29d01fe
a3e2b23
97152e9
d699070
0f38c18
66a173a
dd25cf3
3413f4f
52bafb0
1306518
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,18 @@ | |
import sys | ||
|
||
|
||
def parse_indent(indent): | ||
"""Parse the argparse indent argument.""" | ||
if indent == 'None': | ||
return None | ||
if indent == r'\t': | ||
return '\t' | ||
try: | ||
return int(indent) | ||
except ValueError: | ||
return indent | ||
|
||
|
||
def main(): | ||
prog = 'python -m json.tool' | ||
description = ('A simple command line interface for json module ' | ||
|
@@ -25,24 +37,36 @@ 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_escape', action='store_true', default=False, | ||
help='Do not set ensure_ascii to escape non-ASCII characters') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This option name should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @methane are you suggesting: parser.add_argument('--ensure_ascii', action='store_false', default=True)
# And then when calling `json.dump`:
ensure_ascii=options.ensure_ascii The problem here is that it's counterintuitive for parser.add_argument('--no-ensure-ascii', action='store_true', default=False)
# And then when calling `json.dump`:
ensure_ascii=not options.no_ensure_ascii Just let me know what's preferred. |
||
parser.add_argument('--indent', default='4', type=parse_indent, | ||
help='Indent level or str for pretty-printing. ' | ||
'Use None for the most compact representation. ' | ||
r'Use "\t" for tab indentation.') | ||
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_escape, | ||
sort_keys=options.sort_keys, | ||
) | ||
outfile.write('\n') | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,22 +68,22 @@ def test_stdin_stdout(self): | |
self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) | ||
self.assertEqual(err, None) | ||
|
||
def _create_infile(self): | ||
def _create_infile(self, text): | ||
infile = support.TESTFN | ||
with open(infile, "w") as fp: | ||
self.addCleanup(os.remove, infile) | ||
fp.write(self.data) | ||
fp.write(text) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps it would be better just to add non-ascii data to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in a3e2b23. |
||
return infile | ||
|
||
def test_infile_stdout(self): | ||
infile = self._create_infile() | ||
infile = self._create_infile(self.data) | ||
rc, out, err = assert_python_ok('-m', 'json.tool', infile) | ||
self.assertEqual(rc, 0) | ||
self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) | ||
self.assertEqual(err, b'') | ||
|
||
def test_infile_outfile(self): | ||
infile = self._create_infile() | ||
infile = self._create_infile(self.data) | ||
outfile = support.TESTFN + '.out' | ||
rc, out, err = assert_python_ok('-m', 'json.tool', infile, outfile) | ||
self.addCleanup(os.remove, outfile) | ||
|
@@ -100,9 +100,22 @@ def test_help_flag(self): | |
self.assertEqual(err, b'') | ||
|
||
def test_sort_keys_flag(self): | ||
infile = self._create_infile() | ||
infile = self._create_infile(self.data) | ||
rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) | ||
self.assertEqual(rc, 0) | ||
self.assertEqual(out.splitlines(), | ||
self.expect_without_sort_keys.encode().splitlines()) | ||
self.assertEqual(err, b'') | ||
|
||
def test_no_ascii_flag(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. test_no_ensure_ascii_flag There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in a3e2b23. |
||
data = '{"json": "🐍 and δ"}' | ||
expect = textwrap.dedent('''\ | ||
{ | ||
"json": "🐍 and δ" | ||
} | ||
''') | ||
infile = self._create_infile(data) | ||
rc, out, err = assert_python_ok('-m', 'json.tool', '--no_ascii', infile) | ||
self.assertEqual(rc, 0) | ||
self.assertEqual(out.splitlines(), expect.splitlines()) | ||
self.assertEqual(err, b'') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like such special casing.
I think
json.tool
should be minimal to exposejson.dumps
as CLI.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@methane can you think of any other way to expose setting
indent
? The issue is thatindent
can take an int, string, or None. Command line arguments are not ideal for type flexibility. Furthermore, the most common string is a tab, which is difficult to pass via the command line without such special casing.Another option would be to pass
options.indent
throughast.literal_eval
. Therefore, users could specify any python value, but the command line usage would be more cumbersome.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this either. You can use external commands like
unexpand
for converting spaces to tabs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cross-referencing bpo-29636.
@serhiy-storchaka so do you think it's best to simplify so you must either pass
--indent
an int orNone
. Anything that cannot be converted to an int besidesNone
would throw an error?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just pass an integer with
--indent
. Add--no-indent
forNone
.