simplejson 4.1.2__tar.gz → 4.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simplejson-4.1.2 → simplejson-4.2.0}/CHANGES.txt +23 -0
- {simplejson-4.1.2/simplejson.egg-info → simplejson-4.2.0}/PKG-INFO +5 -5
- {simplejson-4.1.2 → simplejson-4.2.0}/README.rst +2 -2
- {simplejson-4.1.2 → simplejson-4.2.0}/conf.py +2 -2
- {simplejson-4.1.2 → simplejson-4.2.0}/index.rst +5 -1
- {simplejson-4.1.2 → simplejson-4.2.0}/setup.py +3 -3
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/__init__.py +2 -2
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/_speedups.c +101 -25
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/_speedups_scan.h +5 -1
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/encoder.py +26 -11
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_bitsize_int_as_string.py +97 -0
- simplejson-4.2.0/simplejson/tests/test_custom_method_cycles.py +71 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_fail.py +26 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_scanstring.py +1 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_speedups.py +1 -8
- {simplejson-4.1.2 → simplejson-4.2.0/simplejson.egg-info}/PKG-INFO +5 -5
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson.egg-info/SOURCES.txt +1 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/LICENSE.txt +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/MANIFEST.in +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/pyproject.toml +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/scripts/make_docs.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/setup.cfg +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/compat.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/decoder.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/errors.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/ordered_dict.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/raw_json.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/scanner.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/__init__.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/_cibw_runner.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/_helpers.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_bigint_as_string.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_check_circular.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_decimal.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_decode.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_default.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_dump.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_encode_basestring_ascii.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_encode_for_html.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_errors.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_float.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_for_json.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_free_threading.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_indent.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_item_sort_key.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_iterable.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_namedtuple.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_pass1.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_pass2.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_pass3.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_raw_json.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_recursion.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_separators.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_str_subclass.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_subclass.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_subinterpreters.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_tool.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_tuple.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tests/test_unicode.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson/tool.py +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson.egg-info/dependency_links.txt +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/simplejson.egg-info/top_level.txt +0 -0
- {simplejson-4.1.2 → simplejson-4.2.0}/tsan_stress_simplejson.py +0 -0
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
Version 4.2.0 released 2026-10-02
|
|
2
|
+
|
|
3
|
+
* Start building wheels for Python 3.15 and drop Python 3.8 support
|
|
4
|
+
via upgrade to cibuildwheel v4.2.0
|
|
5
|
+
https://github.com/simplejson/simplejson/pull/385
|
|
6
|
+
* Build and test riscv64 Linux wheels on native RISE runners
|
|
7
|
+
https://github.com/simplejson/simplejson/pull/389
|
|
8
|
+
* The C scanner now reports the same error message as the pure Python
|
|
9
|
+
decoder for an invalid first key in an object
|
|
10
|
+
https://github.com/simplejson/simplejson/pull/388
|
|
11
|
+
* ``int_as_string_bitcount`` now supports thresholds of 64 bits and above
|
|
12
|
+
(including 128-bit integers) in both the C and pure Python encoders;
|
|
13
|
+
the C encoder previously rejected them
|
|
14
|
+
https://github.com/simplejson/simplejson/pull/387
|
|
15
|
+
* Circular references introduced through ``for_json()`` or ``_asdict()``
|
|
16
|
+
now raise ``ValueError("Circular reference detected")`` instead of
|
|
17
|
+
recursing without bound
|
|
18
|
+
https://github.com/simplejson/simplejson/pull/390
|
|
19
|
+
* CI now tests Python 3.15 (including free-threaded 3.15t), PyPy 3.12,
|
|
20
|
+
CPython 3.14.8 debug builds, and uses current GitHub Actions and
|
|
21
|
+
cibuildwheel v4.2.1
|
|
22
|
+
https://github.com/simplejson/simplejson/pull/386
|
|
23
|
+
|
|
1
24
|
Version 4.1.2 released 2026-08-26
|
|
2
25
|
|
|
3
26
|
* Fix control character error position when content precedes the control char
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simplejson
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Simple, fast, extensible JSON encoder/decoder for Python
|
|
5
5
|
Home-page: https://github.com/simplejson/simplejson
|
|
6
6
|
Author: Bob Ippolito
|
|
@@ -14,18 +14,18 @@ Classifier: Programming Language :: Python
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 2
|
|
15
15
|
Classifier: Programming Language :: Python :: 2.7
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
24
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
25
|
Classifier: Programming Language :: Python :: Implementation :: GraalPy
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
-
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*
|
|
28
|
+
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, !=3.8.*
|
|
29
29
|
License-File: LICENSE.txt
|
|
30
30
|
Dynamic: author
|
|
31
31
|
Dynamic: author-email
|
|
@@ -42,7 +42,7 @@ simplejson
|
|
|
42
42
|
----------
|
|
43
43
|
|
|
44
44
|
simplejson is a simple, fast, complete, correct and extensible
|
|
45
|
-
JSON <http://json.org> encoder and decoder for Python 3.
|
|
45
|
+
JSON <http://json.org> encoder and decoder for Python 3.9+
|
|
46
46
|
with legacy support for Python 2.7. It is pure Python code
|
|
47
47
|
with no dependencies, but includes an optional C extension
|
|
48
48
|
for a serious speed boost.
|
|
@@ -53,7 +53,7 @@ https://simplejson.readthedocs.io/
|
|
|
53
53
|
simplejson is the externally maintained development version of the
|
|
54
54
|
json library included with Python (since 2.6). This version is tested
|
|
55
55
|
with Python 3.14 (including free-threaded builds) and maintains
|
|
56
|
-
backwards compatibility with Python 3.
|
|
56
|
+
backwards compatibility with Python 3.9+. A legacy Python 2.7 wheel
|
|
57
57
|
is also published.
|
|
58
58
|
|
|
59
59
|
The encoder can be specialized to provide serialization in any kind of
|
|
@@ -2,7 +2,7 @@ simplejson
|
|
|
2
2
|
----------
|
|
3
3
|
|
|
4
4
|
simplejson is a simple, fast, complete, correct and extensible
|
|
5
|
-
JSON <http://json.org> encoder and decoder for Python 3.
|
|
5
|
+
JSON <http://json.org> encoder and decoder for Python 3.9+
|
|
6
6
|
with legacy support for Python 2.7. It is pure Python code
|
|
7
7
|
with no dependencies, but includes an optional C extension
|
|
8
8
|
for a serious speed boost.
|
|
@@ -13,7 +13,7 @@ https://simplejson.readthedocs.io/
|
|
|
13
13
|
simplejson is the externally maintained development version of the
|
|
14
14
|
json library included with Python (since 2.6). This version is tested
|
|
15
15
|
with Python 3.14 (including free-threaded builds) and maintains
|
|
16
|
-
backwards compatibility with Python 3.
|
|
16
|
+
backwards compatibility with Python 3.9+. A legacy Python 2.7 wheel
|
|
17
17
|
is also published.
|
|
18
18
|
|
|
19
19
|
The encoder can be specialized to provide serialization in any kind of
|
|
@@ -42,9 +42,9 @@ copyright = '2026, Bob Ippolito'
|
|
|
42
42
|
# other places throughout the built documents.
|
|
43
43
|
#
|
|
44
44
|
# The short X.Y version.
|
|
45
|
-
version = '4.
|
|
45
|
+
version = '4.2'
|
|
46
46
|
# The full version, including alpha/beta/rc tags.
|
|
47
|
-
release = '4.
|
|
47
|
+
release = '4.2.0'
|
|
48
48
|
|
|
49
49
|
# There are two options for replacing |today|: either, you set today to some
|
|
50
50
|
# non-false value, then it is used:
|
|
@@ -21,7 +21,7 @@ for a serious speed boost.
|
|
|
21
21
|
:mod:`simplejson` exposes an API familiar to users of the standard library
|
|
22
22
|
:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
|
|
23
23
|
version of the :mod:`json` library, but maintains
|
|
24
|
-
compatibility with Python 3.
|
|
24
|
+
compatibility with Python 3.9 through 3.15 (including free-threaded
|
|
25
25
|
builds) as well as legacy Python 2.7.
|
|
26
26
|
|
|
27
27
|
Development of simplejson happens on Github:
|
|
@@ -310,6 +310,10 @@ Basic Usage
|
|
|
310
310
|
:class:`int` ``2**n`` and higher or lower than ``-2**n`` will be encoded as strings. This is to
|
|
311
311
|
avoid the rounding that happens in Javascript otherwise. Note that this
|
|
312
312
|
option loses type information, so use with extreme caution.
|
|
313
|
+
Thresholds of 64 bits and above are supported by both encoders, including
|
|
314
|
+
128-bit integers. Very large thresholds do not allocate a power-of-two
|
|
315
|
+
boundary.
|
|
316
|
+
|
|
313
317
|
See also *bigint_as_string* (which is equivalent to `int_as_string_bitcount=53`).
|
|
314
318
|
|
|
315
319
|
.. note::
|
|
@@ -12,13 +12,13 @@ from distutils.errors import CCompilerError, DistutilsExecError, \
|
|
|
12
12
|
|
|
13
13
|
IS_PYPY = hasattr(sys, 'pypy_translation_info')
|
|
14
14
|
IS_GRAALPY = getattr(getattr(sys, "implementation", None), "name", None) == "graalpy"
|
|
15
|
-
VERSION = '4.
|
|
15
|
+
VERSION = '4.2.0'
|
|
16
16
|
DESCRIPTION = "Simple, fast, extensible JSON encoder/decoder for Python"
|
|
17
17
|
|
|
18
18
|
with open('README.rst', 'r') as f:
|
|
19
19
|
LONG_DESCRIPTION = f.read()
|
|
20
20
|
|
|
21
|
-
PYTHON_REQUIRES = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*'
|
|
21
|
+
PYTHON_REQUIRES = '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, !=3.8.*'
|
|
22
22
|
|
|
23
23
|
CLASSIFIERS = [
|
|
24
24
|
'Development Status :: 5 - Production/Stable',
|
|
@@ -28,13 +28,13 @@ CLASSIFIERS = [
|
|
|
28
28
|
'Programming Language :: Python :: 2',
|
|
29
29
|
'Programming Language :: Python :: 2.7',
|
|
30
30
|
'Programming Language :: Python :: 3',
|
|
31
|
-
'Programming Language :: Python :: 3.8',
|
|
32
31
|
'Programming Language :: Python :: 3.9',
|
|
33
32
|
'Programming Language :: Python :: 3.10',
|
|
34
33
|
'Programming Language :: Python :: 3.11',
|
|
35
34
|
'Programming Language :: Python :: 3.12',
|
|
36
35
|
'Programming Language :: Python :: 3.13',
|
|
37
36
|
'Programming Language :: Python :: 3.14',
|
|
37
|
+
'Programming Language :: Python :: 3.15',
|
|
38
38
|
'Programming Language :: Python :: Implementation :: CPython',
|
|
39
39
|
'Programming Language :: Python :: Implementation :: GraalPy',
|
|
40
40
|
'Programming Language :: Python :: Implementation :: PyPy',
|
|
@@ -5,7 +5,7 @@ interchange format.
|
|
|
5
5
|
:mod:`simplejson` exposes an API familiar to users of the standard library
|
|
6
6
|
:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
|
|
7
7
|
version of the :mod:`json` library contained in Python 2.6+, supporting
|
|
8
|
-
Python 2.7 and Python 3.
|
|
8
|
+
Python 2.7 and Python 3.9+, and has significant performance advantages,
|
|
9
9
|
even without using the optional C extension for speedups.
|
|
10
10
|
|
|
11
11
|
Encoding basic Python object hierarchies::
|
|
@@ -118,7 +118,7 @@ Serializing multiple objects to JSON lines (newline-delimited JSON)::
|
|
|
118
118
|
|
|
119
119
|
"""
|
|
120
120
|
from __future__ import absolute_import
|
|
121
|
-
__version__ = '4.
|
|
121
|
+
__version__ = '4.2.0'
|
|
122
122
|
__all__ = [
|
|
123
123
|
'dump', 'dumps', 'load', 'loads',
|
|
124
124
|
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
|
|
@@ -301,6 +301,7 @@ typedef struct _PyEncoderObject {
|
|
|
301
301
|
int iterable_as_array;
|
|
302
302
|
PyObject *max_long_size;
|
|
303
303
|
PyObject *min_long_size;
|
|
304
|
+
PyObject *large_int_bitcount;
|
|
304
305
|
PyObject *item_sort_key;
|
|
305
306
|
PyObject *item_sort_kw;
|
|
306
307
|
int for_json;
|
|
@@ -327,6 +328,7 @@ typedef struct _PyEncoderObject {
|
|
|
327
328
|
X(item_sort_key) \
|
|
328
329
|
X(max_long_size) \
|
|
329
330
|
X(min_long_size) \
|
|
331
|
+
X(large_int_bitcount) \
|
|
330
332
|
X(Decimal)
|
|
331
333
|
|
|
332
334
|
static PyMemberDef encoder_members[] = {
|
|
@@ -708,22 +710,46 @@ maybe_quote_bigint(PyEncoderObject* s, PyObject *encoded, PyObject *obj)
|
|
|
708
710
|
int ge, le;
|
|
709
711
|
PyObject *quoted;
|
|
710
712
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
713
|
+
if (s->large_int_bitcount != NULL) {
|
|
714
|
+
size_t nbits;
|
|
715
|
+
PyObject *bits;
|
|
716
|
+
nbits = _PyLong_NumBits(obj);
|
|
717
|
+
if (nbits == (size_t)-1 && PyErr_Occurred()) {
|
|
718
|
+
Py_DECREF(encoded);
|
|
719
|
+
return NULL;
|
|
720
|
+
}
|
|
721
|
+
bits = PyLong_FromSize_t(nbits);
|
|
722
|
+
if (bits == NULL) {
|
|
723
|
+
Py_DECREF(encoded);
|
|
724
|
+
return NULL;
|
|
725
|
+
}
|
|
726
|
+
ge = PyObject_RichCompareBool(bits, s->large_int_bitcount, Py_GT);
|
|
727
|
+
Py_DECREF(bits);
|
|
728
|
+
if (ge < 0) {
|
|
729
|
+
Py_DECREF(encoded);
|
|
730
|
+
return NULL;
|
|
731
|
+
}
|
|
732
|
+
if (!ge)
|
|
733
|
+
return encoded;
|
|
719
734
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
735
|
+
else {
|
|
736
|
+
/* int_as_string_bitcount is not set: fast path, return as-is. */
|
|
737
|
+
if (s->max_long_size == Py_None || s->min_long_size == Py_None)
|
|
738
|
+
return encoded;
|
|
739
|
+
|
|
740
|
+
ge = PyObject_RichCompareBool(obj, s->max_long_size, Py_GE);
|
|
741
|
+
if (ge < 0) {
|
|
742
|
+
Py_DECREF(encoded);
|
|
743
|
+
return NULL;
|
|
744
|
+
}
|
|
745
|
+
le = PyObject_RichCompareBool(obj, s->min_long_size, Py_LE);
|
|
746
|
+
if (le < 0) {
|
|
747
|
+
Py_DECREF(encoded);
|
|
748
|
+
return NULL;
|
|
749
|
+
}
|
|
750
|
+
if (!(ge || le))
|
|
751
|
+
return encoded;
|
|
724
752
|
}
|
|
725
|
-
if (!(ge || le))
|
|
726
|
-
return encoded;
|
|
727
753
|
|
|
728
754
|
#if PY_MAJOR_VERSION >= 3
|
|
729
755
|
quoted = PyUnicode_FromFormat("\"%U\"", encoded);
|
|
@@ -2653,10 +2679,11 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
2653
2679
|
goto bail;
|
|
2654
2680
|
if (PyInt_Check(int_as_string_bitcount) || PyLong_Check(int_as_string_bitcount)) {
|
|
2655
2681
|
static const unsigned long long_long_bitsize = sizeof(long long) * CHAR_BIT;
|
|
2656
|
-
|
|
2682
|
+
int overflow = 0;
|
|
2683
|
+
long int_as_string_bitcount_val = PyLong_AsLongAndOverflow(int_as_string_bitcount, &overflow);
|
|
2657
2684
|
if (int_as_string_bitcount_val == -1 && PyErr_Occurred())
|
|
2658
2685
|
goto bail;
|
|
2659
|
-
if (int_as_string_bitcount_val > 0 && int_as_string_bitcount_val < (long)long_long_bitsize) {
|
|
2686
|
+
if (!overflow && int_as_string_bitcount_val > 0 && int_as_string_bitcount_val < (long)long_long_bitsize) {
|
|
2660
2687
|
int n = (int)int_as_string_bitcount_val;
|
|
2661
2688
|
/* Compute 2^n as unsigned (well-defined for n < 64) and
|
|
2662
2689
|
* -(2^n) as signed without UB. Naive "-1LL << n" is a
|
|
@@ -2672,10 +2699,19 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
2672
2699
|
goto bail;
|
|
2673
2700
|
}
|
|
2674
2701
|
}
|
|
2702
|
+
else if (overflow > 0 || int_as_string_bitcount_val > 0) {
|
|
2703
|
+
/* Compare magnitudes without allocating a 2**n boundary. */
|
|
2704
|
+
s->large_int_bitcount = PyNumber_Long(int_as_string_bitcount);
|
|
2705
|
+
if (s->large_int_bitcount == NULL)
|
|
2706
|
+
goto bail;
|
|
2707
|
+
Py_INCREF(Py_None);
|
|
2708
|
+
s->max_long_size = Py_None;
|
|
2709
|
+
Py_INCREF(Py_None);
|
|
2710
|
+
s->min_long_size = Py_None;
|
|
2711
|
+
}
|
|
2675
2712
|
else {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
int_as_string_bitcount_val, long_long_bitsize);
|
|
2713
|
+
PyErr_SetString(PyExc_TypeError,
|
|
2714
|
+
"int_as_string_bitcount must be a positive integer");
|
|
2679
2715
|
goto bail;
|
|
2680
2716
|
}
|
|
2681
2717
|
}
|
|
@@ -2979,7 +3015,8 @@ encoder_markers_pop(PyEncoderObject *s, PyObject *ident)
|
|
|
2979
3015
|
|
|
2980
3016
|
/* Helper for the for_json / _asdict paths in encoder_listencode_obj.
|
|
2981
3017
|
* Steals the reference to `newobj` (returned by _call_json_method),
|
|
2982
|
-
*
|
|
3018
|
+
* tracks the original object's circular-reference marker and recursion
|
|
3019
|
+
* depth, and dispatches to the right
|
|
2983
3020
|
* sub-encoder:
|
|
2984
3021
|
* - if as_dict is 0, encodes newobj as a generic JSON value via
|
|
2985
3022
|
* encoder_listencode_obj (for_json contract: return any JSON-
|
|
@@ -2990,14 +3027,20 @@ encoder_markers_pop(PyEncoderObject *s, PyObject *ident)
|
|
|
2990
3027
|
* Cleans up on every exit path. */
|
|
2991
3028
|
static int
|
|
2992
3029
|
encoder_steal_encode(PyEncoderObject *s, JSON_Accu *rval,
|
|
2993
|
-
PyObject *newobj, Py_ssize_t indent_level,
|
|
3030
|
+
PyObject *obj, PyObject *newobj, Py_ssize_t indent_level,
|
|
2994
3031
|
int as_dict)
|
|
2995
3032
|
{
|
|
2996
3033
|
int rv;
|
|
3034
|
+
PyObject *ident = NULL;
|
|
2997
3035
|
if (newobj == NULL)
|
|
2998
3036
|
return -1;
|
|
3037
|
+
if (encoder_markers_push(s, obj, &ident)) {
|
|
3038
|
+
Py_DECREF(newobj);
|
|
3039
|
+
return -1;
|
|
3040
|
+
}
|
|
2999
3041
|
if (Py_EnterRecursiveCall(" while encoding a JSON object")) {
|
|
3000
3042
|
Py_DECREF(newobj);
|
|
3043
|
+
Py_XDECREF(ident);
|
|
3001
3044
|
return -1;
|
|
3002
3045
|
}
|
|
3003
3046
|
if (as_dict) {
|
|
@@ -3014,6 +3057,12 @@ encoder_steal_encode(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3014
3057
|
}
|
|
3015
3058
|
Py_DECREF(newobj);
|
|
3016
3059
|
Py_LeaveRecursiveCall();
|
|
3060
|
+
if (rv == 0) {
|
|
3061
|
+
if (encoder_markers_pop(s, ident) < 0)
|
|
3062
|
+
rv = -1;
|
|
3063
|
+
} else {
|
|
3064
|
+
Py_XDECREF(ident);
|
|
3065
|
+
}
|
|
3017
3066
|
return rv;
|
|
3018
3067
|
}
|
|
3019
3068
|
|
|
@@ -3121,12 +3170,39 @@ encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ss
|
|
|
3121
3170
|
rv = _steal_accumulate(state, rval, cstr);
|
|
3122
3171
|
}
|
|
3123
3172
|
else if (PyInt_Check(obj) || PyLong_Check(obj)) {
|
|
3124
|
-
PyObject *encoded
|
|
3173
|
+
PyObject *integer, *encoded;
|
|
3174
|
+
/* Large thresholds inspect the same normalized value we serialize. */
|
|
3175
|
+
if (s->large_int_bitcount != NULL) {
|
|
3176
|
+
#if PY_MAJOR_VERSION < 3
|
|
3177
|
+
/* Match int(value) in the Python encoder before widening for
|
|
3178
|
+
* _PyLong_NumBits: long(value) would invoke __long__ instead. */
|
|
3179
|
+
PyObject *normalized = PyNumber_Int(obj);
|
|
3180
|
+
if (normalized == NULL)
|
|
3181
|
+
return -1;
|
|
3182
|
+
/* PyNumber_Int may retain a long subclass. Copy its payload
|
|
3183
|
+
* instead of invoking a second conversion hook. */
|
|
3184
|
+
if (PyInt_Check(normalized))
|
|
3185
|
+
integer = PyLong_FromLong(PyInt_AS_LONG(normalized));
|
|
3186
|
+
else
|
|
3187
|
+
integer = PyLong_Type.tp_as_number->nb_long(normalized);
|
|
3188
|
+
Py_DECREF(normalized);
|
|
3189
|
+
#else
|
|
3190
|
+
integer = PyNumber_Long(obj);
|
|
3191
|
+
#endif
|
|
3192
|
+
}
|
|
3193
|
+
else {
|
|
3194
|
+
integer = obj;
|
|
3195
|
+
Py_INCREF(integer);
|
|
3196
|
+
}
|
|
3197
|
+
if (integer == NULL)
|
|
3198
|
+
return -1;
|
|
3199
|
+
encoded = encoder_long_to_str(integer);
|
|
3125
3200
|
if (encoded != NULL) {
|
|
3126
|
-
encoded = maybe_quote_bigint(s, encoded,
|
|
3201
|
+
encoded = maybe_quote_bigint(s, encoded, integer);
|
|
3127
3202
|
if (encoded != NULL)
|
|
3128
3203
|
rv = _steal_accumulate(state, rval, encoded);
|
|
3129
3204
|
}
|
|
3205
|
+
Py_DECREF(integer);
|
|
3130
3206
|
}
|
|
3131
3207
|
else if (PyFloat_Check(obj)) {
|
|
3132
3208
|
PyObject *encoded = encoder_encode_float(s, obj);
|
|
@@ -3134,10 +3210,10 @@ encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ss
|
|
|
3134
3210
|
rv = _steal_accumulate(state, rval, encoded);
|
|
3135
3211
|
}
|
|
3136
3212
|
else if (s->for_json && _call_json_method(obj, state->JSON_attr_for_json, &newobj)) {
|
|
3137
|
-
rv = encoder_steal_encode(s, rval, newobj, indent_level, /*as_dict=*/0);
|
|
3213
|
+
rv = encoder_steal_encode(s, rval, obj, newobj, indent_level, /*as_dict=*/0);
|
|
3138
3214
|
}
|
|
3139
3215
|
else if (s->namedtuple_as_object && _call_json_method(obj, state->JSON_attr_asdict, &newobj)) {
|
|
3140
|
-
rv = encoder_steal_encode(s, rval, newobj, indent_level, /*as_dict=*/1);
|
|
3216
|
+
rv = encoder_steal_encode(s, rval, obj, newobj, indent_level, /*as_dict=*/1);
|
|
3141
3217
|
}
|
|
3142
3218
|
else if (PyList_Check(obj) || (s->tuple_as_array && PyTuple_Check(obj))) {
|
|
3143
3219
|
if (Py_EnterRecursiveCall(" while encoding a JSON object"))
|
|
@@ -210,7 +210,11 @@ JSON_SCAN_FN(_parse_object)(PyScannerObject *s, PyObject *pystr,
|
|
|
210
210
|
|
|
211
211
|
/* read key */
|
|
212
212
|
if (JSON_SCAN_READ(idx) != '"') {
|
|
213
|
-
|
|
213
|
+
/* '}' is still legal where the first key would go. */
|
|
214
|
+
raise_errmsg(state,
|
|
215
|
+
did_parse ? ERR_OBJECT_PROPERTY
|
|
216
|
+
: ERR_OBJECT_PROPERTY_FIRST,
|
|
217
|
+
pystr, idx);
|
|
214
218
|
goto bail;
|
|
215
219
|
}
|
|
216
220
|
key = JSON_SCAN_SCANSTRING_CALL(idx + 1, &next_idx);
|
|
@@ -516,13 +516,24 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
|
|
|
516
516
|
value = int(value)
|
|
517
517
|
if (
|
|
518
518
|
skip_quoting or
|
|
519
|
-
(
|
|
520
|
-
< value <
|
|
521
|
-
(1 << _int_as_string_bitcount)
|
|
519
|
+
value.bit_length() <= _int_as_string_bitcount
|
|
522
520
|
):
|
|
523
521
|
return str(value)
|
|
524
522
|
return '"' + str(value) + '"'
|
|
525
523
|
|
|
524
|
+
def _iterencode_method(obj, result, _current_indent_level, encode):
|
|
525
|
+
if markers is not None:
|
|
526
|
+
markerid = id(obj)
|
|
527
|
+
if markerid in markers:
|
|
528
|
+
raise ValueError("Circular reference detected")
|
|
529
|
+
markers[markerid] = obj
|
|
530
|
+
try:
|
|
531
|
+
for chunk in encode(result, _current_indent_level):
|
|
532
|
+
yield chunk
|
|
533
|
+
finally:
|
|
534
|
+
if markers is not None:
|
|
535
|
+
del markers[markerid]
|
|
536
|
+
|
|
526
537
|
def _iterencode_list(lst, _current_indent_level):
|
|
527
538
|
if not lst:
|
|
528
539
|
yield '[]'
|
|
@@ -570,15 +581,16 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
|
|
|
570
581
|
yield buf
|
|
571
582
|
for_json = _for_json and call_method(value, 'for_json')
|
|
572
583
|
if for_json:
|
|
573
|
-
chunks =
|
|
584
|
+
chunks = _iterencode_method(value, for_json[0],
|
|
585
|
+
_current_indent_level, _iterencode)
|
|
574
586
|
else:
|
|
575
587
|
_asdict = _namedtuple_as_object and call_method(value, '_asdict')
|
|
576
588
|
if _asdict:
|
|
577
589
|
dct = _asdict[0]
|
|
578
590
|
if not isinstance(dct, dict):
|
|
579
591
|
raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
|
|
580
|
-
chunks =
|
|
581
|
-
|
|
592
|
+
chunks = _iterencode_method(value, dct,
|
|
593
|
+
_current_indent_level, _iterencode_dict)
|
|
582
594
|
elif isinstance(value, list):
|
|
583
595
|
chunks = _iterencode_list(value, _current_indent_level)
|
|
584
596
|
elif _tuple_as_array and isinstance(value, tuple):
|
|
@@ -701,15 +713,16 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
|
|
|
701
713
|
else:
|
|
702
714
|
for_json = _for_json and call_method(value, 'for_json')
|
|
703
715
|
if for_json:
|
|
704
|
-
chunks =
|
|
716
|
+
chunks = _iterencode_method(value, for_json[0],
|
|
717
|
+
_current_indent_level, _iterencode)
|
|
705
718
|
else:
|
|
706
719
|
_asdict = _namedtuple_as_object and call_method(value, '_asdict')
|
|
707
720
|
if _asdict:
|
|
708
721
|
dct = _asdict[0]
|
|
709
722
|
if not isinstance(dct, dict):
|
|
710
723
|
raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
|
|
711
|
-
chunks =
|
|
712
|
-
|
|
724
|
+
chunks = _iterencode_method(value, dct,
|
|
725
|
+
_current_indent_level, _iterencode_dict)
|
|
713
726
|
elif isinstance(value, list):
|
|
714
727
|
chunks = _iterencode_list(value, _current_indent_level)
|
|
715
728
|
elif _tuple_as_array and isinstance(value, tuple):
|
|
@@ -753,7 +766,8 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
|
|
|
753
766
|
else:
|
|
754
767
|
for_json = _for_json and call_method(o, 'for_json')
|
|
755
768
|
if for_json:
|
|
756
|
-
for chunk in
|
|
769
|
+
for chunk in _iterencode_method(o, for_json[0],
|
|
770
|
+
_current_indent_level, _iterencode):
|
|
757
771
|
yield chunk
|
|
758
772
|
else:
|
|
759
773
|
_asdict = _namedtuple_as_object and call_method(o, '_asdict')
|
|
@@ -761,7 +775,8 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
|
|
|
761
775
|
dct = _asdict[0]
|
|
762
776
|
if not isinstance(dct, dict):
|
|
763
777
|
raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
|
|
764
|
-
for chunk in
|
|
778
|
+
for chunk in _iterencode_method(o, dct,
|
|
779
|
+
_current_indent_level, _iterencode_dict):
|
|
765
780
|
yield chunk
|
|
766
781
|
elif isinstance(o, list):
|
|
767
782
|
for chunk in _iterencode_list(o, _current_indent_level):
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from unittest import TestCase
|
|
2
2
|
|
|
3
3
|
import simplejson as json
|
|
4
|
+
from simplejson.compat import PY3, integer_types, long_type
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class TestBitSizeIntAsString(TestCase):
|
|
@@ -118,3 +119,99 @@ class TestBitSizeIntAsString(TestCase):
|
|
|
118
119
|
str(v),
|
|
119
120
|
json.loads(json.dumps(v, int_as_string_bitcount=n)),
|
|
120
121
|
"n=%d v=%d should be stringified" % (n, v))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_large_bitcounts(self):
|
|
125
|
+
for n in (64, 65, 127, 128, 256, 1024):
|
|
126
|
+
boundary = 1 << n
|
|
127
|
+
values = [0, boundary - 1, boundary, boundary + 1,
|
|
128
|
+
-boundary + 1, -boundary, -boundary - 1]
|
|
129
|
+
expected = [0, boundary - 1, str(boundary), str(boundary + 1),
|
|
130
|
+
-boundary + 1, str(-boundary), str(-boundary - 1)]
|
|
131
|
+
for indent in (None, 2):
|
|
132
|
+
self.assertEqual(expected, json.loads(json.dumps(
|
|
133
|
+
values, int_as_string_bitcount=n, indent=indent)))
|
|
134
|
+
self.assertEqual({'value': expected}, json.loads(json.dumps(
|
|
135
|
+
{'value': values}, int_as_string_bitcount=n, indent=indent)))
|
|
136
|
+
|
|
137
|
+
def test_huge_bitcount_does_not_build_boundary(self):
|
|
138
|
+
# A threshold can exceed native integer sizes without allocating 2**n.
|
|
139
|
+
for n in (2 ** 32 + 31, 2 ** 100):
|
|
140
|
+
self.assertEqual('[0, 1, -1]', json.dumps(
|
|
141
|
+
[0, 1, -1], int_as_string_bitcount=n))
|
|
142
|
+
|
|
143
|
+
def test_large_bitcount_normalizes_subclass_once(self):
|
|
144
|
+
for integer_type in integer_types:
|
|
145
|
+
class ChangingInt(integer_type):
|
|
146
|
+
calls = 0
|
|
147
|
+
|
|
148
|
+
def __int__(self):
|
|
149
|
+
self.calls += 1
|
|
150
|
+
return normalized if self.calls == 1 else 0
|
|
151
|
+
|
|
152
|
+
def __long__(self):
|
|
153
|
+
raise AssertionError('must normalize through __int__')
|
|
154
|
+
|
|
155
|
+
for normalized in (1 << 64, -(1 << 64), 1):
|
|
156
|
+
expected = str(normalized)
|
|
157
|
+
if abs(normalized) >= 1 << 64:
|
|
158
|
+
expected = '"' + expected + '"'
|
|
159
|
+
for indent in (None, 2):
|
|
160
|
+
value = ChangingInt(1)
|
|
161
|
+
self.assertEqual(expected, json.dumps(
|
|
162
|
+
value, int_as_string_bitcount=64, indent=indent))
|
|
163
|
+
self.assertEqual(1, value.calls)
|
|
164
|
+
|
|
165
|
+
def test_large_bitcount_normalization_error_propagates(self):
|
|
166
|
+
for integer_type in integer_types:
|
|
167
|
+
class BadInt(integer_type):
|
|
168
|
+
def __int__(self):
|
|
169
|
+
raise RuntimeError('normalization bomb')
|
|
170
|
+
|
|
171
|
+
for indent in (None, 2):
|
|
172
|
+
self.assertRaises(
|
|
173
|
+
RuntimeError, json.dumps, BadInt(1),
|
|
174
|
+
int_as_string_bitcount=64, indent=indent)
|
|
175
|
+
|
|
176
|
+
def _assert_returned_long_is_not_converted(self, returned_type):
|
|
177
|
+
for integer_type in integer_types:
|
|
178
|
+
class OriginalInt(integer_type):
|
|
179
|
+
calls = 0
|
|
180
|
+
|
|
181
|
+
def __int__(self):
|
|
182
|
+
self.calls += 1
|
|
183
|
+
return returned
|
|
184
|
+
|
|
185
|
+
def __long__(self):
|
|
186
|
+
return long_type(7)
|
|
187
|
+
|
|
188
|
+
for normalized in (7, 1 << 64, -(1 << 64)):
|
|
189
|
+
expected = str(normalized)
|
|
190
|
+
if abs(normalized) >= 1 << 64:
|
|
191
|
+
expected = '"' + expected + '"'
|
|
192
|
+
for indent in (None, 2):
|
|
193
|
+
returned = returned_type(normalized)
|
|
194
|
+
value = OriginalInt(7)
|
|
195
|
+
self.assertEqual(expected, json.dumps(
|
|
196
|
+
value, int_as_string_bitcount=64, indent=indent))
|
|
197
|
+
self.assertEqual(1, value.calls)
|
|
198
|
+
|
|
199
|
+
def test_large_bitcount_returned_long_value_preserved(self):
|
|
200
|
+
if PY3:
|
|
201
|
+
self.skipTest('Python 2 int() can return a long subclass')
|
|
202
|
+
|
|
203
|
+
class ReturnedLong(long_type):
|
|
204
|
+
def __long__(self):
|
|
205
|
+
return 1 << 64
|
|
206
|
+
|
|
207
|
+
self._assert_returned_long_is_not_converted(ReturnedLong)
|
|
208
|
+
|
|
209
|
+
def test_large_bitcount_returned_long_hook_not_called(self):
|
|
210
|
+
if PY3:
|
|
211
|
+
self.skipTest('Python 2 int() can return a long subclass')
|
|
212
|
+
|
|
213
|
+
class ReturnedLong(long_type):
|
|
214
|
+
def __long__(self):
|
|
215
|
+
raise RuntimeError('unexpected second conversion')
|
|
216
|
+
|
|
217
|
+
self._assert_returned_long_is_not_converted(ReturnedLong)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from unittest import TestCase, skipIf
|
|
3
|
+
|
|
4
|
+
import simplejson as json
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ForJson:
|
|
8
|
+
def __init__(self, value=None):
|
|
9
|
+
self.value = value
|
|
10
|
+
|
|
11
|
+
def for_json(self):
|
|
12
|
+
return self.value
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AsDict:
|
|
16
|
+
def _asdict(self):
|
|
17
|
+
return {'self': self}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestCustomMethodCycles(TestCase):
|
|
21
|
+
def assert_circular(self, value):
|
|
22
|
+
with self.assertRaises(ValueError) as exc:
|
|
23
|
+
json.dumps(value, for_json=True)
|
|
24
|
+
self.assertEqual(str(exc.exception), 'Circular reference detected')
|
|
25
|
+
|
|
26
|
+
def test_direct_for_json_cycle(self):
|
|
27
|
+
value = ForJson()
|
|
28
|
+
value.value = value
|
|
29
|
+
self.assert_circular(value)
|
|
30
|
+
|
|
31
|
+
def test_indirect_for_json_cycle(self):
|
|
32
|
+
first = ForJson()
|
|
33
|
+
second = ForJson(first)
|
|
34
|
+
first.value = second
|
|
35
|
+
self.assert_circular(first)
|
|
36
|
+
|
|
37
|
+
def test_for_json_cycle_in_list(self):
|
|
38
|
+
value = ForJson()
|
|
39
|
+
value.value = value
|
|
40
|
+
self.assert_circular([value])
|
|
41
|
+
|
|
42
|
+
def test_for_json_cycle_in_dict(self):
|
|
43
|
+
value = ForJson()
|
|
44
|
+
value.value = value
|
|
45
|
+
self.assert_circular({'value': value})
|
|
46
|
+
|
|
47
|
+
def test_asdict_cycle(self):
|
|
48
|
+
self.assert_circular(AsDict())
|
|
49
|
+
|
|
50
|
+
def test_asdict_cycle_in_list(self):
|
|
51
|
+
self.assert_circular([AsDict()])
|
|
52
|
+
|
|
53
|
+
def test_asdict_cycle_in_dict(self):
|
|
54
|
+
self.assert_circular({'value': AsDict()})
|
|
55
|
+
|
|
56
|
+
def test_repeated_reference_is_not_a_cycle(self):
|
|
57
|
+
value = ForJson({'x': 1})
|
|
58
|
+
self.assertEqual(
|
|
59
|
+
json.loads(json.dumps([value, value], for_json=True)),
|
|
60
|
+
[{'x': 1}, {'x': 1}])
|
|
61
|
+
|
|
62
|
+
def test_acyclic_chain(self):
|
|
63
|
+
self.assertEqual(json.loads(json.dumps(ForJson(ForJson(1)), for_json=True)), 1)
|
|
64
|
+
|
|
65
|
+
@skipIf(sys.platform == 'emscripten',
|
|
66
|
+
'Pyodide cannot recover from unbounded recursion')
|
|
67
|
+
def test_circular_checks_can_be_disabled(self):
|
|
68
|
+
value = ForJson()
|
|
69
|
+
value.value = value
|
|
70
|
+
with self.assertRaises(RuntimeError):
|
|
71
|
+
json.dumps(value, for_json=True, check_circular=False)
|
|
@@ -135,6 +135,32 @@ class TestFail(TestCase):
|
|
|
135
135
|
else:
|
|
136
136
|
self.fail("Unexpected success parsing '[,]'")
|
|
137
137
|
|
|
138
|
+
def test_object_property_error_message(self):
|
|
139
|
+
# '}' is legal where the first key would go, but not after a comma.
|
|
140
|
+
first = "Expecting property name enclosed in double quotes or '}'"
|
|
141
|
+
later = 'Expecting property name enclosed in double quotes'
|
|
142
|
+
test_cases = [
|
|
143
|
+
('{:1}', first, 1),
|
|
144
|
+
('{,}', first, 1),
|
|
145
|
+
('{unquoted_key: "keys must be quoted"}', first, 1),
|
|
146
|
+
('{"spam":42,:1}', later, 11),
|
|
147
|
+
('{"spam":42,unquoted_key: 1}', later, 11),
|
|
148
|
+
]
|
|
149
|
+
for data, msg, idx in test_cases:
|
|
150
|
+
try:
|
|
151
|
+
json.loads(data)
|
|
152
|
+
except json.JSONDecodeError:
|
|
153
|
+
e = sys.exc_info()[1]
|
|
154
|
+
self.assertEqual(
|
|
155
|
+
e.msg, msg, "%r != %r for %r" % (e.msg, msg, data))
|
|
156
|
+
self.assertEqual(
|
|
157
|
+
e.pos, idx, "pos %r != %r for %r" % (e.pos, idx, data))
|
|
158
|
+
except Exception:
|
|
159
|
+
e = sys.exc_info()[1]
|
|
160
|
+
self.fail("Unexpected exception raised %r %s" % (e, e))
|
|
161
|
+
else:
|
|
162
|
+
self.fail("Unexpected success parsing %r" % (data,))
|
|
163
|
+
|
|
138
164
|
def test_truncated_input(self):
|
|
139
165
|
test_cases = [
|
|
140
166
|
('', 'Expecting value', 0),
|
|
@@ -4,7 +4,7 @@ from unittest import TestCase
|
|
|
4
4
|
|
|
5
5
|
import simplejson
|
|
6
6
|
from simplejson import encoder, decoder, scanner
|
|
7
|
-
from simplejson.compat import PY3,
|
|
7
|
+
from simplejson.compat import PY3, b
|
|
8
8
|
from simplejson.tests._helpers import has_speedups, skip_if_speedups_missing
|
|
9
9
|
|
|
10
10
|
|
|
@@ -82,13 +82,6 @@ class TestEncode(TestCase):
|
|
|
82
82
|
self.assertRaises(ZeroDivisionError, test, 'ignore_nan')
|
|
83
83
|
self.assertRaises(ZeroDivisionError, test, 'iterable_as_array')
|
|
84
84
|
|
|
85
|
-
@skip_if_speedups_missing
|
|
86
|
-
def test_int_as_string_bitcount_overflow(self):
|
|
87
|
-
long_count = long_type(2)**32+31
|
|
88
|
-
def test():
|
|
89
|
-
encoder.JSONEncoder(int_as_string_bitcount=long_count).encode(0)
|
|
90
|
-
self.assertRaises((TypeError, OverflowError), test)
|
|
91
|
-
|
|
92
85
|
if PY3:
|
|
93
86
|
@skip_if_speedups_missing
|
|
94
87
|
def test_bad_encoding(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simplejson
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Simple, fast, extensible JSON encoder/decoder for Python
|
|
5
5
|
Home-page: https://github.com/simplejson/simplejson
|
|
6
6
|
Author: Bob Ippolito
|
|
@@ -14,18 +14,18 @@ Classifier: Programming Language :: Python
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 2
|
|
15
15
|
Classifier: Programming Language :: Python :: 2.7
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
24
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
25
|
Classifier: Programming Language :: Python :: Implementation :: GraalPy
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
-
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*
|
|
28
|
+
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, !=3.8.*
|
|
29
29
|
License-File: LICENSE.txt
|
|
30
30
|
Dynamic: author
|
|
31
31
|
Dynamic: author-email
|
|
@@ -42,7 +42,7 @@ simplejson
|
|
|
42
42
|
----------
|
|
43
43
|
|
|
44
44
|
simplejson is a simple, fast, complete, correct and extensible
|
|
45
|
-
JSON <http://json.org> encoder and decoder for Python 3.
|
|
45
|
+
JSON <http://json.org> encoder and decoder for Python 3.9+
|
|
46
46
|
with legacy support for Python 2.7. It is pure Python code
|
|
47
47
|
with no dependencies, but includes an optional C extension
|
|
48
48
|
for a serious speed boost.
|
|
@@ -53,7 +53,7 @@ https://simplejson.readthedocs.io/
|
|
|
53
53
|
simplejson is the externally maintained development version of the
|
|
54
54
|
json library included with Python (since 2.6). This version is tested
|
|
55
55
|
with Python 3.14 (including free-threaded builds) and maintains
|
|
56
|
-
backwards compatibility with Python 3.
|
|
56
|
+
backwards compatibility with Python 3.9+. A legacy Python 2.7 wheel
|
|
57
57
|
is also published.
|
|
58
58
|
|
|
59
59
|
The encoder can be specialized to provide serialization in any kind of
|
|
@@ -29,6 +29,7 @@ simplejson/tests/_helpers.py
|
|
|
29
29
|
simplejson/tests/test_bigint_as_string.py
|
|
30
30
|
simplejson/tests/test_bitsize_int_as_string.py
|
|
31
31
|
simplejson/tests/test_check_circular.py
|
|
32
|
+
simplejson/tests/test_custom_method_cycles.py
|
|
32
33
|
simplejson/tests/test_decimal.py
|
|
33
34
|
simplejson/tests/test_decode.py
|
|
34
35
|
simplejson/tests/test_default.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|