Bump json to 3.14.2 (#6774)

This commit is contained in:
Lee Dogeon authored and GitHub committed 2026-01-18 19:16:48 +09:00
1 parent e8dd5826e6
commit 5242ff5243
13 files changed
+340 -123

No files matched your search

+3 -3
View File
@@ -86,13 +86,13 @@ Specializing JSON object encoding::
'[2.0, 1.0]'
Using json.tool from the shell to validate and pretty-print::
Using json from the shell to validate and pretty-print::
$ echo '{"json":"obj"}' | python -m json.tool
$ echo '{"json":"obj"}' | python -m json
{
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m json.tool
$ echo '{ 1.2:3.4}' | python -m json
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
"""
__version__ = '2.0.9'
+20
View File
@@ -0,0 +1,20 @@
"""Command-line tool to validate and pretty-print JSON
Usage::
$ echo '{"json":"obj"}' | python -m json
{
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m json
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
"""
import json.tool
if __name__ == '__main__':
try:
json.tool.main()
except BrokenPipeError as exc:
raise SystemExit(exc.errno)
+67 -52
View File
@@ -295,37 +295,40 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
else:
newline_indent = None
separator = _item_separator
first = True
for value in lst:
if first:
first = False
else:
for i, value in enumerate(lst):
if i:
buf = separator
if isinstance(value, str):
yield buf + _encoder(value)
elif value is None:
yield buf + 'null'
elif value is True:
yield buf + 'true'
elif value is False:
yield buf + 'false'
elif isinstance(value, int):
# Subclasses of int/float may override __repr__, but we still
# want to encode them as integers/floats in JSON. One example
# within the standard library is IntEnum.
yield buf + _intstr(value)
elif isinstance(value, float):
# see comment above for int
yield buf + _floatstr(value)
else:
yield buf
if isinstance(value, (list, tuple)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
try:
if isinstance(value, str):
yield buf + _encoder(value)
elif value is None:
yield buf + 'null'
elif value is True:
yield buf + 'true'
elif value is False:
yield buf + 'false'
elif isinstance(value, int):
# Subclasses of int/float may override __repr__, but we still
# want to encode them as integers/floats in JSON. One example
# within the standard library is IntEnum.
yield buf + _intstr(value)
elif isinstance(value, float):
# see comment above for int
yield buf + _floatstr(value)
else:
chunks = _iterencode(value, _current_indent_level)
yield from chunks
yield buf
if isinstance(value, (list, tuple)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
else:
chunks = _iterencode(value, _current_indent_level)
yield from chunks
except GeneratorExit:
raise
except BaseException as exc:
exc.add_note(f'when serializing {type(lst).__name__} item {i}')
raise
if newline_indent is not None:
_current_indent_level -= 1
yield '\n' + _indent * _current_indent_level
@@ -385,28 +388,34 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
yield item_separator
yield _encoder(key)
yield _key_separator
if isinstance(value, str):
yield _encoder(value)
elif value is None:
yield 'null'
elif value is True:
yield 'true'
elif value is False:
yield 'false'
elif isinstance(value, int):
# see comment for int/float in _make_iterencode
yield _intstr(value)
elif isinstance(value, float):
# see comment for int/float in _make_iterencode
yield _floatstr(value)
else:
if isinstance(value, (list, tuple)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
try:
if isinstance(value, str):
yield _encoder(value)
elif value is None:
yield 'null'
elif value is True:
yield 'true'
elif value is False:
yield 'false'
elif isinstance(value, int):
# see comment for int/float in _make_iterencode
yield _intstr(value)
elif isinstance(value, float):
# see comment for int/float in _make_iterencode
yield _floatstr(value)
else:
chunks = _iterencode(value, _current_indent_level)
yield from chunks
if isinstance(value, (list, tuple)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
else:
chunks = _iterencode(value, _current_indent_level)
yield from chunks
except GeneratorExit:
raise
except BaseException as exc:
exc.add_note(f'when serializing {type(dct).__name__} item {key!r}')
raise
if not first and newline_indent is not None:
_current_indent_level -= 1
yield '\n' + _indent * _current_indent_level
@@ -439,8 +448,14 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = o
o = _default(o)
yield from _iterencode(o, _current_indent_level)
newobj = _default(o)
try:
yield from _iterencode(newobj, _current_indent_level)
except GeneratorExit:
raise
except BaseException as exc:
exc.add_note(f'when serializing {type(o).__name__} object')
raise
if markers is not None:
del markers[markerid]
return _iterencode
+48 -16
View File
@@ -1,25 +1,50 @@
r"""Command-line tool to validate and pretty-print JSON
Usage::
$ echo '{"json":"obj"}' | python -m json.tool
{
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
"""Command-line tool to validate and pretty-print JSON
See `json.__main__` for a usage example (invocation as
`python -m json.tool` is supported for backwards compatibility).
"""
import argparse
import json
import re
import sys
from _colorize import get_theme, can_colorize
# The string we are colorizing is valid JSON,
# so we can use a looser but simpler regex to match
# the various parts, most notably strings and numbers,
# where the regex given by the spec is much more complex.
_color_pattern = re.compile(r'''
(?P<key>"(\\.|[^"\\])*")(?=:) |
(?P<string>"(\\.|[^"\\])*") |
(?P<number>NaN|-?Infinity|[0-9\-+.Ee]+) |
(?P<boolean>true|false) |
(?P<null>null)
''', re.VERBOSE)
_group_to_theme_color = {
"key": "definition",
"string": "string",
"number": "number",
"boolean": "keyword",
"null": "keyword",
}
def _colorize_json(json_str, theme):
def _replace_match_callback(match):
for group, color in _group_to_theme_color.items():
if m := match.group(group):
return f"{theme[color]}{m}{theme.reset}"
return match.group()
return re.sub(_color_pattern, _replace_match_callback, json_str)
def main():
prog = 'python -m json.tool'
description = ('A simple command line interface for json module '
'to validate and pretty-print JSON objects.')
parser = argparse.ArgumentParser(prog=prog, description=description)
parser = argparse.ArgumentParser(description=description, color=True)
parser.add_argument('infile', nargs='?',
help='a JSON file to be validated or pretty-printed',
default='-')
@@ -75,9 +100,16 @@ def main():
else:
outfile = open(options.outfile, 'w', encoding='utf-8')
with outfile:
for obj in objs:
json.dump(obj, outfile, **dump_args)
outfile.write('\n')
if can_colorize(file=outfile):
t = get_theme(tty_file=outfile).syntax
for obj in objs:
json_str = json.dumps(obj, **dump_args)
outfile.write(_colorize_json(json_str, t))
outfile.write('\n')
else:
for obj in objs:
json.dump(obj, outfile, **dump_args)
outfile.write('\n')
except ValueError as e:
raise SystemExit(e)
@@ -86,4 +118,4 @@ if __name__ == '__main__':
try:
main()
except BrokenPipeError as exc:
sys.exit(exc.errno)
raise SystemExit(exc.errno)
+1 -2
View File
@@ -41,8 +41,7 @@ class TestPyTest(PyTest):
'json.encoder')
class TestCTest(CTest):
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_cjson(self):
self.assertEqual(self.json.scanner.make_scanner.__module__, '_json')
self.assertEqual(self.json.decoder.scanstring.__module__, '_json')
+1 -5
View File
@@ -18,8 +18,7 @@ class TestDecode:
self.assertIsInstance(rval, float)
self.assertEqual(rval, 1.0)
# TODO: RUSTPYTHON
@unittest.skip("TODO: RUSTPYTHON; called `Result::unwrap()` on an `Err` value: ParseFloatError { kind: Invalid }")
@unittest.skip('TODO: RUSTPYTHON; called `Result::unwrap()` on an `Err` value: ParseFloatError { kind: Invalid }')
def test_nonascii_digits_rejected(self):
# JSON specifies only ascii digits, see gh-125687
for num in ["1\uff10", "0.\uff10", "0e\uff10"]:
@@ -138,9 +137,6 @@ class TestDecode:
class TestPyDecode(TestDecode, PyTest): pass
class TestCDecode(TestDecode, CTest):
def test_keys_reuse(self):
return super().test_keys_reuse()
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_limit_int(self):
+21
View File
@@ -1,4 +1,5 @@
import collections
import unittest # XXX: RUSTPYTHON; importing to be able to skip tests
from test.test_json import PyTest, CTest
@@ -8,6 +9,26 @@ class TestDefault:
self.dumps(type, default=repr),
self.dumps(repr(type)))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_bad_default(self):
def default(obj):
if obj is NotImplemented:
raise ValueError
if obj is ...:
return NotImplemented
if obj is type:
return collections
return [...]
with self.assertRaises(ValueError) as cm:
self.dumps(type, default=default)
self.assertEqual(cm.exception.__notes__,
['when serializing ellipsis object',
'when serializing list item 0',
'when serializing module object',
'when serializing type object'])
def test_ordereddict(self):
od = collections.OrderedDict(a=1, b=2, c=3, d=4)
od.move_to_end('b')
+24 -3
View File
@@ -1,7 +1,7 @@
from test.test_json import PyTest, CTest
import unittest # XXX: RUSTPYTHON; importing to be able to skip tests
from test.test_json import PyTest, CTest
# 2007-10-05
JSONDOCS = [
# https://json.org/JSON_checker/test/fail1.json
@@ -99,11 +99,32 @@ class TestFail:
'keys must be str, int, float, bool or None, not tuple'):
self.dumps(data)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_not_serializable(self):
import sys
with self.assertRaisesRegex(TypeError,
'Object of type module is not JSON serializable'):
'Object of type module is not JSON serializable') as cm:
self.dumps(sys)
self.assertNotHasAttr(cm.exception, '__notes__')
with self.assertRaises(TypeError) as cm:
self.dumps([1, [2, 3, sys]])
self.assertEqual(cm.exception.__notes__,
['when serializing list item 2',
'when serializing list item 1'])
with self.assertRaises(TypeError) as cm:
self.dumps((1, (2, 3, sys)))
self.assertEqual(cm.exception.__notes__,
['when serializing tuple item 2',
'when serializing tuple item 1'])
with self.assertRaises(TypeError) as cm:
self.dumps({'a': {'b': sys}})
self.assertEqual(cm.exception.__notes__,
["when serializing dict item 'b'",
"when serializing dict item 'a'"])
def test_truncated_input(self):
test_cases = [
+26 -13
View File
@@ -14,8 +14,8 @@ class TestRecursion:
x.append(x)
try:
self.dumps(x)
except ValueError:
pass
except ValueError as exc:
self.assertEqual(exc.__notes__, ["when serializing list item 0"])
else:
self.fail("didn't raise ValueError on list recursion")
x = []
@@ -23,8 +23,8 @@ class TestRecursion:
x.append(y)
try:
self.dumps(x)
except ValueError:
pass
except ValueError as exc:
self.assertEqual(exc.__notes__, ["when serializing list item 0"]*2)
else:
self.fail("didn't raise ValueError on alternating list recursion")
y = []
@@ -37,8 +37,8 @@ class TestRecursion:
x["test"] = x
try:
self.dumps(x)
except ValueError:
pass
except ValueError as exc:
self.assertEqual(exc.__notes__, ["when serializing dict item 'test'"])
else:
self.fail("didn't raise ValueError on dict recursion")
x = {}
@@ -62,31 +62,41 @@ class TestRecursion:
enc.recurse = True
try:
enc.encode(JSONTestObject)
except ValueError:
pass
except ValueError as exc:
self.assertEqual(exc.__notes__,
["when serializing list item 0",
"when serializing type object"])
else:
self.fail("didn't raise ValueError on default recursion")
# TODO: RUSTPYTHON
@unittest.skip("TODO: RUSTPYTHON; crashes")
@unittest.skip('TODO: RUSTPYTHON; crashes')
# TODO: RUSTPYHTON; needs to upgrade test.support to 3.14 above
# @support.skip_emscripten_stack_overflow()
# @support.skip_wasi_stack_overflow()
def test_highly_nested_objects_decoding(self):
very_deep = 200000
# test that loading highly-nested objects doesn't segfault when C
# accelerations are used. See #12017
with self.assertRaises(RecursionError):
with support.infinite_recursion():
self.loads('{"a":' * 100000 + '1' + '}' * 100000)
self.loads('{"a":' * very_deep + '1' + '}' * very_deep)
with self.assertRaises(RecursionError):
with support.infinite_recursion():
self.loads('{"a":' * 100000 + '[1]' + '}' * 100000)
self.loads('{"a":' * very_deep + '[1]' + '}' * very_deep)
with self.assertRaises(RecursionError):
with support.infinite_recursion():
self.loads('[' * 100000 + '1' + ']' * 100000)
self.loads('[' * very_deep + '1' + ']' * very_deep)
# TODO: RUSTPYHTON; needs to upgrade test.support to 3.14 above
# @support.skip_wasi_stack_overflow()
# @support.skip_emscripten_stack_overflow()
@support.requires_resource('cpu')
def test_highly_nested_objects_encoding(self):
# See #12051
l, d = [], {}
for x in range(100000):
for x in range(200_000):
l, d = [l], {'k':d}
with self.assertRaises(RecursionError):
with support.infinite_recursion(5000):
@@ -95,6 +105,9 @@ class TestRecursion:
with support.infinite_recursion(5000):
self.dumps(d)
# TODO: RUSTPYHTON; needs to upgrade test.support to 3.14 above
# @support.skip_emscripten_stack_overflow()
# @support.skip_wasi_stack_overflow()
def test_endless_recursion(self):
# See #12051
class EndlessJSONEncoder(self.json.JSONEncoder):
+1 -2
View File
@@ -144,8 +144,7 @@ class TestScanstring:
with self.assertRaises(self.JSONDecodeError, msg=s):
scanstring(s, 1, True)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_overflow(self):
with self.assertRaises(OverflowError):
self.json.decoder.scanstring("xxx", sys.maxsize+1)
+3 -6
View File
@@ -40,8 +40,7 @@ class TestEncode(CTest):
b"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75",
None)
# TODO: RUSTPYTHON; TypeError: 'NoneType' object is not callable
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: 'NoneType' object is not callable
def test_bad_str_encoder(self):
# Issue #31505: There shouldn't be an assertion failure in case
# c_make_encoder() receives a bad encoder() argument.
@@ -63,8 +62,7 @@ class TestEncode(CTest):
with self.assertRaises(ZeroDivisionError):
enc('spam', 4)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_bad_markers_argument_to_encoder(self):
# https://bugs.python.org/issue45269
with self.assertRaisesRegex(
@@ -74,8 +72,7 @@ class TestEncode(CTest):
self.json.encoder.c_make_encoder(1, None, None, None, ': ', ', ',
False, False, False)
# TODO: RUSTPYTHON; ZeroDivisionError not raised by test
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; ZeroDivisionError not raised by test
def test_bad_bool_args(self):
def test(name):
self.json.encoder.JSONEncoder(**{name: BadBool()}).encode({'a': 1})
+124 -19
View File
@@ -6,12 +6,23 @@ import unittest
import subprocess
from test import support
from test.support import os_helper
from test.support import force_not_colorized, os_helper
from test.support.script_helper import assert_python_ok
from _colorize import get_theme
# XXX: RUSTPYTHON; force_colorized not available in test.support
def force_colorized(func):
"""Placeholder decorator for RustPython - force_colorized not available."""
import functools
@functools.wraps(func)
def wrapper(*args, **kwargs):
raise unittest.SkipTest("TODO: RUSTPYTHON; force_colorized not available")
return wrapper
@support.requires_subprocess()
class TestTool(unittest.TestCase):
class TestMain(unittest.TestCase):
data = """
[["blorpie"],[ "whoops" ] , [
@@ -19,6 +30,7 @@ class TestTool(unittest.TestCase):
"i-vhbjkhnth", {"nifty":87}, {"morefield" :\tfalse,"field"
:"yes"} ]
"""
module = 'json'
expect_without_sort_keys = textwrap.dedent("""\
[
@@ -86,8 +98,9 @@ class TestTool(unittest.TestCase):
}
""")
@force_not_colorized
def test_stdin_stdout(self):
args = sys.executable, '-m', 'json.tool'
args = sys.executable, '-m', self.module
process = subprocess.run(args, input=self.data, capture_output=True, text=True, check=True)
self.assertEqual(process.stdout, self.expect)
self.assertEqual(process.stderr, '')
@@ -101,7 +114,8 @@ class TestTool(unittest.TestCase):
def test_infile_stdout(self):
infile = self._create_infile()
rc, out, err = assert_python_ok('-m', 'json.tool', infile)
rc, out, err = assert_python_ok('-m', self.module, infile,
PYTHON_COLORS='0')
self.assertEqual(rc, 0)
self.assertEqual(out.splitlines(), self.expect.encode().splitlines())
self.assertEqual(err, b'')
@@ -115,7 +129,8 @@ class TestTool(unittest.TestCase):
''').encode()
infile = self._create_infile(data)
rc, out, err = assert_python_ok('-m', 'json.tool', infile)
rc, out, err = assert_python_ok('-m', self.module, infile,
PYTHON_COLORS='0')
self.assertEqual(rc, 0)
self.assertEqual(out.splitlines(), expect.splitlines())
@@ -124,7 +139,8 @@ class TestTool(unittest.TestCase):
def test_infile_outfile(self):
infile = self._create_infile()
outfile = os_helper.TESTFN + '.out'
rc, out, err = assert_python_ok('-m', 'json.tool', infile, outfile)
rc, out, err = assert_python_ok('-m', self.module, infile, outfile,
PYTHON_COLORS='0')
self.addCleanup(os.remove, outfile)
with open(outfile, "r", encoding="utf-8") as fp:
self.assertEqual(fp.read(), self.expect)
@@ -134,33 +150,39 @@ class TestTool(unittest.TestCase):
def test_writing_in_place(self):
infile = self._create_infile()
rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile)
rc, out, err = assert_python_ok('-m', self.module, infile, infile,
PYTHON_COLORS='0')
with open(infile, "r", encoding="utf-8") as fp:
self.assertEqual(fp.read(), self.expect)
self.assertEqual(rc, 0)
self.assertEqual(out, b'')
self.assertEqual(err, b'')
@force_not_colorized
def test_jsonlines(self):
args = sys.executable, '-m', 'json.tool', '--json-lines'
args = sys.executable, '-m', self.module, '--json-lines'
process = subprocess.run(args, input=self.jsonlines_raw, capture_output=True, text=True, check=True)
self.assertEqual(process.stdout, self.jsonlines_expect)
self.assertEqual(process.stderr, '')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_help_flag(self):
rc, out, err = assert_python_ok('-m', 'json.tool', '-h')
rc, out, err = assert_python_ok('-m', self.module, '-h',
PYTHON_COLORS='0')
self.assertEqual(rc, 0)
self.assertTrue(out.startswith(b'usage: '))
self.assertStartsWith(out, b'usage: ')
self.assertEqual(err, b'')
def test_sort_keys_flag(self):
infile = self._create_infile()
rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile)
rc, out, err = assert_python_ok('-m', self.module, '--sort-keys', infile,
PYTHON_COLORS='0')
self.assertEqual(rc, 0)
self.assertEqual(out.splitlines(),
self.expect_without_sort_keys.encode().splitlines())
self.assertEqual(err, b'')
@force_not_colorized
def test_indent(self):
input_ = '[1, 2]'
expect = textwrap.dedent('''\
@@ -169,31 +191,34 @@ class TestTool(unittest.TestCase):
2
]
''')
args = sys.executable, '-m', 'json.tool', '--indent', '2'
args = sys.executable, '-m', self.module, '--indent', '2'
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
self.assertEqual(process.stdout, expect)
self.assertEqual(process.stderr, '')
@force_not_colorized
def test_no_indent(self):
input_ = '[1,\n2]'
expect = '[1, 2]\n'
args = sys.executable, '-m', 'json.tool', '--no-indent'
args = sys.executable, '-m', self.module, '--no-indent'
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
self.assertEqual(process.stdout, expect)
self.assertEqual(process.stderr, '')
@force_not_colorized
def test_tab(self):
input_ = '[1, 2]'
expect = '[\n\t1,\n\t2\n]\n'
args = sys.executable, '-m', 'json.tool', '--tab'
args = sys.executable, '-m', self.module, '--tab'
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
self.assertEqual(process.stdout, expect)
self.assertEqual(process.stderr, '')
@force_not_colorized
def test_compact(self):
input_ = '[ 1 ,\n 2]'
expect = '[1,2]\n'
args = sys.executable, '-m', 'json.tool', '--compact'
args = sys.executable, '-m', self.module, '--compact'
process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True)
self.assertEqual(process.stdout, expect)
self.assertEqual(process.stderr, '')
@@ -202,7 +227,8 @@ class TestTool(unittest.TestCase):
infile = self._create_infile('{"key":"💩"}')
outfile = os_helper.TESTFN + '.out'
self.addCleanup(os.remove, outfile)
assert_python_ok('-m', 'json.tool', '--no-ensure-ascii', infile, outfile)
assert_python_ok('-m', self.module, '--no-ensure-ascii', infile,
outfile, PYTHON_COLORS='0')
with open(outfile, "rb") as f:
lines = f.read().splitlines()
# asserting utf-8 encoded output file
@@ -213,20 +239,99 @@ class TestTool(unittest.TestCase):
infile = self._create_infile('{"key":"💩"}')
outfile = os_helper.TESTFN + '.out'
self.addCleanup(os.remove, outfile)
assert_python_ok('-m', 'json.tool', infile, outfile)
assert_python_ok('-m', self.module, infile, outfile, PYTHON_COLORS='0')
with open(outfile, "rb") as f:
lines = f.read().splitlines()
# asserting an ascii encoded output file
expected = [b'{', rb' "key": "\ud83d\udca9"', b"}"]
self.assertEqual(lines, expected)
@force_not_colorized
@unittest.skipIf(sys.platform =="win32", "The test is failed with ValueError on Windows")
def test_broken_pipe_error(self):
cmd = [sys.executable, '-m', 'json.tool']
cmd = [sys.executable, '-m', self.module]
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE)
# bpo-39828: Closing before json.tool attempts to write into stdout.
# bpo-39828: Closing before json attempts to write into stdout.
proc.stdout.close()
proc.communicate(b'"{}"')
self.assertEqual(proc.returncode, errno.EPIPE)
@force_colorized
def test_colors(self):
infile = os_helper.TESTFN
self.addCleanup(os.remove, infile)
t = get_theme().syntax
ob = "{"
cb = "}"
cases = (
('{}', '{}'),
('[]', '[]'),
('null', f'{t.keyword}null{t.reset}'),
('true', f'{t.keyword}true{t.reset}'),
('false', f'{t.keyword}false{t.reset}'),
('NaN', f'{t.number}NaN{t.reset}'),
('Infinity', f'{t.number}Infinity{t.reset}'),
('-Infinity', f'{t.number}-Infinity{t.reset}'),
('"foo"', f'{t.string}"foo"{t.reset}'),
(r'" \"foo\" "', f'{t.string}" \\"foo\\" "{t.reset}'),
('"α"', f'{t.string}"\\u03b1"{t.reset}'),
('123', f'{t.number}123{t.reset}'),
('-1.25e+23', f'{t.number}-1.25e+23{t.reset}'),
(r'{"\\": ""}',
f'''\
{ob}
{t.definition}"\\\\"{t.reset}: {t.string}""{t.reset}
{cb}'''),
(r'{"\\\\": ""}',
f'''\
{ob}
{t.definition}"\\\\\\\\"{t.reset}: {t.string}""{t.reset}
{cb}'''),
('''\
{
"foo": "bar",
"baz": 1234,
"qux": [true, false, null],
"xyz": [NaN, -Infinity, Infinity]
}''',
f'''\
{ob}
{t.definition}"foo"{t.reset}: {t.string}"bar"{t.reset},
{t.definition}"baz"{t.reset}: {t.number}1234{t.reset},
{t.definition}"qux"{t.reset}: [
{t.keyword}true{t.reset},
{t.keyword}false{t.reset},
{t.keyword}null{t.reset}
],
{t.definition}"xyz"{t.reset}: [
{t.number}NaN{t.reset},
{t.number}-Infinity{t.reset},
{t.number}Infinity{t.reset}
]
{cb}'''),
)
for input_, expected in cases:
with self.subTest(input=input_):
with open(infile, "w", encoding="utf-8") as fp:
fp.write(input_)
_, stdout_b, _ = assert_python_ok(
'-m', self.module, infile, FORCE_COLOR='1', __isolated='1'
)
stdout = stdout_b.decode()
stdout = stdout.replace('\r\n', '\n') # normalize line endings
stdout = stdout.strip()
self.assertEqual(stdout, expected)
@support.requires_subprocess()
class TestTool(TestMain):
module = 'json.tool'
if __name__ == "__main__":
unittest.main()
+1 -2
View File
@@ -94,8 +94,7 @@ class TestUnicode:
self.assertRaises(TypeError, self.dumps, b"hi")
self.assertRaises(TypeError, self.dumps, [b"hi"])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_bytes_decode(self):
for encoding, bom in [
('utf-8', codecs.BOM_UTF8),