Update simplejson-3.17.5

This commit is contained in:
JonnyWong16 2021-10-14 23:52:53 -07:00
parent f165d2d080
commit cdeff390d9
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
6 changed files with 95 additions and 25 deletions

View file

@ -118,7 +118,7 @@ Serializing multiple objects to JSON lines (newline-delimited JSON)::
"""
from __future__ import absolute_import
__version__ = '3.17.0'
__version__ = '3.17.5'
__all__ = [
'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
@ -360,7 +360,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
If specified, *item_sort_key* is a callable used to sort the items in
each dictionary. This is useful if you want to sort items other than
in alphabetical order by key. This option takes precendence over
in alphabetical order by key. This option takes precedence over
*sort_keys*.
If *sort_keys* is true (default: ``False``), the output of dictionaries

View file

@ -386,6 +386,8 @@ static int
_is_namedtuple(PyObject *obj)
{
int rval = 0;
/* We intentionally accept anything with a duck typed _asdict method rather
* than requiring it to pass PyTuple_Check(obj). */
PyObject *_asdict = PyObject_GetAttrString(obj, "_asdict");
if (_asdict == NULL) {
PyErr_Clear();
@ -2853,6 +2855,15 @@ encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ss
return rv;
newobj = PyObject_CallMethod(obj, "_asdict", NULL);
if (newobj != NULL) {
if (!PyDict_Check(newobj)) {
PyErr_Format(
PyExc_TypeError,
"_asdict() must return a dict, not %.80s",
Py_TYPE(newobj)->tp_name
);
Py_DECREF(newobj);
return -1;
}
rv = encoder_listencode_dict(s, rval, newobj, indent_level);
Py_DECREF(newobj);
}

View file

@ -520,7 +520,10 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
else:
_asdict = _namedtuple_as_object and getattr(value, '_asdict', None)
if _asdict and callable(_asdict):
chunks = _iterencode_dict(_asdict(),
dct = _asdict()
if not isinstance(dct, dict):
raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
chunks = _iterencode_dict(dct,
_current_indent_level)
elif _tuple_as_array and isinstance(value, tuple):
chunks = _iterencode_list(value, _current_indent_level)
@ -641,7 +644,10 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
else:
_asdict = _namedtuple_as_object and getattr(value, '_asdict', None)
if _asdict and callable(_asdict):
chunks = _iterencode_dict(_asdict(),
dct = _asdict()
if not isinstance(dct, dict):
raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
chunks = _iterencode_dict(dct,
_current_indent_level)
elif _tuple_as_array and isinstance(value, tuple):
chunks = _iterencode_list(value, _current_indent_level)
@ -686,8 +692,10 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
else:
_asdict = _namedtuple_as_object and getattr(o, '_asdict', None)
if _asdict and callable(_asdict):
for chunk in _iterencode_dict(_asdict(),
_current_indent_level):
dct = _asdict()
if not isinstance(dct, dict):
raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
for chunk in _iterencode_dict(dct, _current_indent_level):
yield chunk
elif (_tuple_as_array and isinstance(o, tuple)):
for chunk in _iterencode_list(o, _current_indent_level):

View file

@ -7,6 +7,7 @@ import os
class NoExtensionTestSuite(unittest.TestSuite):
def run(self, result):
import simplejson
simplejson._toggle_speedups(False)
result = unittest.TestSuite.run(self, result)
simplejson._toggle_speedups(True)
@ -15,16 +16,17 @@ class NoExtensionTestSuite(unittest.TestSuite):
class TestMissingSpeedups(unittest.TestCase):
def runTest(self):
if hasattr(sys, 'pypy_translation_info'):
if hasattr(sys, "pypy_translation_info"):
"PyPy doesn't need speedups! :)"
elif hasattr(self, 'skipTest'):
self.skipTest('_speedups.so is missing!')
elif hasattr(self, "skipTest"):
self.skipTest("_speedups.so is missing!")
def additional_tests(suite=None):
def additional_tests(suite=None, project_dir=None):
import simplejson
import simplejson.encoder
import simplejson.decoder
if suite is None:
suite = unittest.TestSuite()
try:
@ -36,39 +38,54 @@ def additional_tests(suite=None):
raise
for mod in (simplejson, simplejson.encoder, simplejson.decoder):
suite.addTest(doctest.DocTestSuite(mod))
suite.addTest(doctest.DocFileSuite('../../index.rst'))
if project_dir is not None:
suite.addTest(
doctest.DocFileSuite(
os.path.join(project_dir, "index.rst"), module_relative=False
)
)
return suite
def all_tests_suite():
def all_tests_suite(project_dir=None):
def get_suite():
suite_names = [
'simplejson.tests.%s' % (os.path.splitext(f)[0],)
"simplejson.tests.%s" % (os.path.splitext(f)[0],)
for f in os.listdir(os.path.dirname(__file__))
if f.startswith('test_') and f.endswith('.py')
if f.startswith("test_") and f.endswith(".py")
]
return additional_tests(
unittest.TestLoader().loadTestsFromNames(suite_names))
suite=unittest.TestLoader().loadTestsFromNames(suite_names),
project_dir=project_dir,
)
suite = get_suite()
import simplejson
if simplejson._import_c_make_encoder() is None:
suite.addTest(TestMissingSpeedups())
else:
suite = unittest.TestSuite([
suite,
NoExtensionTestSuite([get_suite()]),
])
suite = unittest.TestSuite(
[
suite,
NoExtensionTestSuite([get_suite()]),
]
)
return suite
def main():
runner = unittest.TextTestRunner(verbosity=1 + sys.argv.count('-v'))
suite = all_tests_suite()
def main(project_dir=None):
runner = unittest.TextTestRunner(verbosity=1 + sys.argv.count("-v"))
suite = all_tests_suite(project_dir=project_dir)
raise SystemExit(not runner.run(suite).wasSuccessful())
if __name__ == '__main__':
if __name__ == "__main__":
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
main()
project_dir = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
sys.path.insert(0, project_dir)
main(project_dir=project_dir)

View file

@ -0,0 +1,7 @@
"""Internal module for running tests from cibuildwheel"""
import sys
import simplejson.tests
if __name__ == '__main__':
simplejson.tests.main(project_dir=sys.argv[1])

View file

@ -3,6 +3,11 @@ import unittest
import simplejson as json
from simplejson.compat import StringIO
try:
from unittest import mock
except ImportError:
mock = None
try:
from collections import namedtuple
except ImportError:
@ -120,3 +125,25 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(
json.dumps(f({})),
json.dumps(f(DeadDict()), namedtuple_as_object=True))
def test_asdict_does_not_return_dict(self):
if not mock:
if hasattr(unittest, "SkipTest"):
raise unittest.SkipTest("unittest.mock required")
else:
print("unittest.mock not available")
return
fake = mock.Mock()
self.assertTrue(hasattr(fake, '_asdict'))
self.assertTrue(callable(fake._asdict))
self.assertFalse(isinstance(fake._asdict(), dict))
# https://github.com/simplejson/simplejson/pull/284
# when running under a debug build of CPython (COPTS=-UNDEBUG)
# a C assertion could fire due to an unchecked error of an PyDict
# API call on a non-dict internally in _speedups.c. Without a debug
# build of CPython this test likely passes either way despite the
# potential for internal data corruption. Getting it to crash in
# a debug build is not always easy either as it requires an
# assert(!PyErr_Occurred()) that could fire later on.
with self.assertRaises(TypeError):
json.dumps({23: fake}, namedtuple_as_object=True, for_json=False)