mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Bump json to 3.14.2 (#6774)
This commit is contained in:
1 parent
e8dd5826e6
commit
5242ff5243
13 files changed
+340
-123
No files matched your search
Vendored
+3
-3
@@ -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'
|
||||
|
||||
Vendored
+20
@@ -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)
|
||||
Vendored
+67
-52
@@ -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
|
||||
Vendored
+48
-16
@@ -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)
|
||||
Vendored
+1
-2
@@ -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')
|
||||
|
||||
Vendored
+1
-5
@@ -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):
|
||||
|
||||
Vendored
+21
@@ -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')
|
||||
|
||||
Vendored
+24
-3
@@ -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 = [
|
||||
|
||||
Vendored
+26
-13
@@ -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
@@ -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)
|
||||
|
||||
Vendored
+3
-6
@@ -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})
|
||||
|
||||
Vendored
+124
-19
@@ -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()
|
||||
Vendored
+1
-2
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user