simplejson 4.2.0__tar.gz → 4.3.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.2.0 → simplejson-4.3.0}/CHANGES.txt +33 -0
- {simplejson-4.2.0/simplejson.egg-info → simplejson-4.3.0}/PKG-INFO +1 -1
- {simplejson-4.2.0 → simplejson-4.3.0}/conf.py +2 -2
- {simplejson-4.2.0 → simplejson-4.3.0}/index.rst +9 -6
- {simplejson-4.2.0 → simplejson-4.3.0}/setup.py +1 -1
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/__init__.py +6 -5
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/_speedups.c +205 -42
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/decoder.py +5 -3
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/encoder.py +223 -177
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/scanner.py +3 -3
- simplejson-4.3.0/simplejson/tests/test_check_circular.py +158 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_decimal.py +16 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_decode.py +66 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_dump.py +111 -0
- simplejson-4.3.0/simplejson/tests/test_errors.py +247 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_float.py +13 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_for_json.py +20 -0
- simplejson-4.3.0/simplejson/tests/test_item_sort_key.py +68 -0
- simplejson-4.3.0/simplejson/tests/test_iterable.py +263 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_speedups.py +11 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_tool.py +35 -2
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tool.py +2 -2
- {simplejson-4.2.0 → simplejson-4.3.0/simplejson.egg-info}/PKG-INFO +1 -1
- simplejson-4.2.0/simplejson/tests/test_check_circular.py +0 -50
- simplejson-4.2.0/simplejson/tests/test_errors.py +0 -108
- simplejson-4.2.0/simplejson/tests/test_item_sort_key.py +0 -27
- simplejson-4.2.0/simplejson/tests/test_iterable.py +0 -61
- {simplejson-4.2.0 → simplejson-4.3.0}/LICENSE.txt +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/MANIFEST.in +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/README.rst +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/pyproject.toml +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/scripts/make_docs.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/setup.cfg +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/_speedups_scan.h +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/compat.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/errors.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/ordered_dict.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/raw_json.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/__init__.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/_cibw_runner.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/_helpers.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_bigint_as_string.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_bitsize_int_as_string.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_custom_method_cycles.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_default.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_encode_basestring_ascii.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_encode_for_html.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_fail.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_free_threading.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_indent.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_namedtuple.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_pass1.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_pass2.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_pass3.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_raw_json.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_recursion.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_scanstring.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_separators.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_str_subclass.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_subclass.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_subinterpreters.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_tuple.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson/tests/test_unicode.py +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson.egg-info/SOURCES.txt +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson.egg-info/dependency_links.txt +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/simplejson.egg-info/top_level.txt +0 -0
- {simplejson-4.2.0 → simplejson-4.3.0}/tsan_stress_simplejson.py +0 -0
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
Version 4.3.0 released 2026-11-10
|
|
2
|
+
|
|
3
|
+
* The C encoder no longer crashes when ``default()`` or ``for_json()``
|
|
4
|
+
shrinks or grows the list being encoded, and no longer reads a freed
|
|
5
|
+
key when encoding a dict value removes its entry. Both encoders now
|
|
6
|
+
raise ``RuntimeError("dictionary changed size during iteration")``
|
|
7
|
+
when a dict is resized while it is being encoded. ``make_encoder()``
|
|
8
|
+
raises ``TypeError`` for an invalid ``markers`` argument instead of
|
|
9
|
+
crashing, and C and pure Python error messages now match
|
|
10
|
+
https://github.com/simplejson/simplejson/pull/395
|
|
11
|
+
* Circular references are now detected through re-iterable objects
|
|
12
|
+
encoded with ``iterable_as_array=True``, in both encoders
|
|
13
|
+
https://github.com/simplejson/simplejson/pull/391
|
|
14
|
+
* A failure while adding a PEP 678 context note no longer replaces the
|
|
15
|
+
original serialization error
|
|
16
|
+
https://github.com/simplejson/simplejson/pull/392
|
|
17
|
+
* Explicitly supplied ``parse_float``, ``parse_int`` and
|
|
18
|
+
``parse_constant`` callbacks are now used even when they are falsy
|
|
19
|
+
https://github.com/simplejson/simplejson/pull/394
|
|
20
|
+
* An explicit ``item_sort_key`` is now honored even when it is falsy
|
|
21
|
+
https://github.com/simplejson/simplejson/pull/396
|
|
22
|
+
* ``python -m simplejson.tool`` now reads input files as UTF-8
|
|
23
|
+
regardless of the locale
|
|
24
|
+
https://github.com/simplejson/simplejson/pull/397
|
|
25
|
+
* With ``allow_nan=False`` the C encoder's ``ValueError`` now names the
|
|
26
|
+
out-of-range value, matching the pure Python encoder
|
|
27
|
+
https://github.com/simplejson/simplejson/pull/399
|
|
28
|
+
* Build and test native Windows arm64 wheels
|
|
29
|
+
https://github.com/simplejson/simplejson/pull/401
|
|
30
|
+
* Wheels for CPython 3.15 are now built against the final 3.15 release
|
|
31
|
+
via cibuildwheel v4.3.5, and CI uses astral-sh/setup-uv v10.3.3
|
|
32
|
+
https://github.com/simplejson/simplejson/pull/405
|
|
33
|
+
|
|
1
34
|
Version 4.2.0 released 2026-10-02
|
|
2
35
|
|
|
3
36
|
* Start building wheels for Python 3.15 and drop Python 3.8 support
|
|
@@ -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.3'
|
|
46
46
|
# The full version, including alpha/beta/rc tags.
|
|
47
|
-
release = '4.
|
|
47
|
+
release = '4.3.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:
|
|
@@ -215,8 +215,10 @@ Basic Usage
|
|
|
215
215
|
optimization, the result would be a :class:`str` object.
|
|
216
216
|
|
|
217
217
|
If *check_circular* is false (default: ``True``), then the circular
|
|
218
|
-
reference check for container types
|
|
219
|
-
|
|
218
|
+
reference check for container types (including iterables encoded with
|
|
219
|
+
*iterable_as_array*) will be skipped and a circular reference will
|
|
220
|
+
result in a :exc:`RecursionError` (:exc:`RuntimeError` on Python 2) or
|
|
221
|
+
worse.
|
|
220
222
|
|
|
221
223
|
If *allow_nan* is false (default: ``False``), then it will be a
|
|
222
224
|
:exc:`ValueError` to serialize out of range :class:`float` values
|
|
@@ -632,10 +634,11 @@ Encoders and decoders
|
|
|
632
634
|
:class:`str` objects with all incoming unicode characters escaped. If
|
|
633
635
|
*ensure_ascii* is false, the output will be a unicode object.
|
|
634
636
|
|
|
635
|
-
If *check_circular* is true (the default), then lists, dicts,
|
|
636
|
-
encoded
|
|
637
|
-
|
|
638
|
-
|
|
637
|
+
If *check_circular* is true (the default), then lists, dicts, iterables
|
|
638
|
+
encoded with *iterable_as_array*, and custom encoded objects will be checked
|
|
639
|
+
for circular references during encoding to prevent an infinite recursion
|
|
640
|
+
(which would cause a :exc:`RecursionError`, or :exc:`RuntimeError` on
|
|
641
|
+
Python 2). Otherwise, no such check takes place.
|
|
639
642
|
|
|
640
643
|
If *allow_nan* is true (not the default), then ``NaN``, ``Infinity``, and
|
|
641
644
|
``-Infinity`` will be encoded as such. This behavior is not JSON
|
|
@@ -12,7 +12,7 @@ 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.3.0'
|
|
16
16
|
DESCRIPTION = "Simple, fast, extensible JSON encoder/decoder for Python"
|
|
17
17
|
|
|
18
18
|
with open('README.rst', 'r') as f:
|
|
@@ -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.3.0'
|
|
122
122
|
__all__ = [
|
|
123
123
|
'dump', 'dumps', 'load', 'loads',
|
|
124
124
|
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
|
|
@@ -246,7 +246,7 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
|
|
|
246
246
|
encoding == 'utf-8' and default is None and use_decimal
|
|
247
247
|
and namedtuple_as_object and tuple_as_array and not iterable_as_array
|
|
248
248
|
and not bigint_as_string and not sort_keys
|
|
249
|
-
and
|
|
249
|
+
and item_sort_key is None and not for_json
|
|
250
250
|
and not ignore_nan and int_as_string_bitcount is None
|
|
251
251
|
and not kw
|
|
252
252
|
):
|
|
@@ -292,8 +292,9 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
|
|
|
292
292
|
by JSON. When it is true, all non-ASCII characters are escaped.
|
|
293
293
|
|
|
294
294
|
If ``check_circular`` is false, then the circular reference check
|
|
295
|
-
for container types
|
|
296
|
-
|
|
295
|
+
for container types (including iterables encoded with
|
|
296
|
+
``iterable_as_array``) will be skipped and a circular reference will
|
|
297
|
+
result in a ``RecursionError`` (``RuntimeError`` on Python 2) or worse.
|
|
297
298
|
|
|
298
299
|
If *allow_nan* is true (default: ``False``), then out of range ``float``
|
|
299
300
|
values (``nan``, ``inf``, ``-inf``) will be serialized to
|
|
@@ -372,7 +373,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
|
|
|
372
373
|
encoding == 'utf-8' and default is None and use_decimal
|
|
373
374
|
and namedtuple_as_object and tuple_as_array and not iterable_as_array
|
|
374
375
|
and not bigint_as_string and not sort_keys
|
|
375
|
-
and
|
|
376
|
+
and item_sort_key is None and not for_json
|
|
376
377
|
and not ignore_nan and int_as_string_bitcount is None
|
|
377
378
|
and not kw
|
|
378
379
|
):
|
|
@@ -414,7 +414,8 @@ is_raw_json(_speedups_state *state, PyObject *obj);
|
|
|
414
414
|
static PyObject *
|
|
415
415
|
encoder_stringify_key(PyEncoderObject *s, PyObject *key);
|
|
416
416
|
static int
|
|
417
|
-
encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq,
|
|
417
|
+
encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq,
|
|
418
|
+
PyObject *origin, Py_ssize_t indent_level);
|
|
418
419
|
static int
|
|
419
420
|
encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ssize_t indent_level);
|
|
420
421
|
static int
|
|
@@ -491,6 +492,31 @@ json_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result)
|
|
|
491
492
|
#endif
|
|
492
493
|
}
|
|
493
494
|
|
|
495
|
+
/* The type name used in error messages and exception notes, matching
|
|
496
|
+
* the pure-Python encoder's type(obj).__name__, which is what type's
|
|
497
|
+
* __name__ getter returns: ht_name for heap types, and tp_name after its
|
|
498
|
+
* module prefix ("collections.deque") for static types. Nothing here can
|
|
499
|
+
* fail, since a note is formatted while an exception is set. */
|
|
500
|
+
static const char *
|
|
501
|
+
json_type_name(PyObject *obj)
|
|
502
|
+
{
|
|
503
|
+
PyTypeObject *tp = Py_TYPE(obj);
|
|
504
|
+
const char *dot;
|
|
505
|
+
if (PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
|
|
506
|
+
#if PY_MAJOR_VERSION >= 3
|
|
507
|
+
/* A spec-created type keeps its module prefix in tp_name only.
|
|
508
|
+
* For a class, tp_name is the UTF-8 of ht_name, which may itself
|
|
509
|
+
* contain dots, so it is the fallback for non-ASCII names. */
|
|
510
|
+
PyObject *ht_name = ((PyHeapTypeObject *)tp)->ht_name;
|
|
511
|
+
if (PyUnicode_IS_ASCII(ht_name))
|
|
512
|
+
return (const char *)PyUnicode_DATA(ht_name);
|
|
513
|
+
#endif
|
|
514
|
+
return tp->tp_name;
|
|
515
|
+
}
|
|
516
|
+
dot = strrchr(tp->tp_name, '.');
|
|
517
|
+
return dot == NULL ? tp->tp_name : dot + 1;
|
|
518
|
+
}
|
|
519
|
+
|
|
494
520
|
static inline int
|
|
495
521
|
json_memo_intern_key(PyObject *memo, PyObject **key_ptr)
|
|
496
522
|
{
|
|
@@ -1098,7 +1124,7 @@ encoder_stringify_key(PyEncoderObject *s, PyObject *key)
|
|
|
1098
1124
|
}
|
|
1099
1125
|
PyErr_Format(PyExc_TypeError,
|
|
1100
1126
|
"keys must be str, int, float, bool or None, "
|
|
1101
|
-
"not %.100s", key
|
|
1127
|
+
"not %.100s", json_type_name(key));
|
|
1102
1128
|
return NULL;
|
|
1103
1129
|
}
|
|
1104
1130
|
|
|
@@ -1151,6 +1177,18 @@ encoder_dict_iteritems(PyEncoderObject *s, PyObject *dct)
|
|
|
1151
1177
|
items = PyMapping_Items(dct);
|
|
1152
1178
|
if (items == NULL)
|
|
1153
1179
|
return NULL;
|
|
1180
|
+
#if PY_MAJOR_VERSION < 3
|
|
1181
|
+
/* Python 3's PyMapping_Items always makes a list, but Python 2's
|
|
1182
|
+
* returns whatever items() returned, and the sort below reads it as
|
|
1183
|
+
* a list. */
|
|
1184
|
+
if (!PyList_CheckExact(items)) {
|
|
1185
|
+
PyObject *items_list = PySequence_List(items);
|
|
1186
|
+
Py_DECREF(items);
|
|
1187
|
+
if (items_list == NULL)
|
|
1188
|
+
return NULL;
|
|
1189
|
+
items = items_list;
|
|
1190
|
+
}
|
|
1191
|
+
#endif
|
|
1154
1192
|
|
|
1155
1193
|
/* Unsorted path: return iter(items) directly. */
|
|
1156
1194
|
if (s->item_sort_kw == Py_None) {
|
|
@@ -2606,6 +2644,15 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
2606
2644
|
&ignore_nan, &Decimal, &iterable_as_array))
|
|
2607
2645
|
return NULL;
|
|
2608
2646
|
|
|
2647
|
+
/* markers goes straight to PyDict_Contains, PyDict_SetItem and
|
|
2648
|
+
* PyDict_DelItem, which do not check the type of their argument. */
|
|
2649
|
+
if (markers != Py_None && !PyDict_Check(markers)) {
|
|
2650
|
+
PyErr_Format(PyExc_TypeError,
|
|
2651
|
+
"make_encoder() argument 1 must be dict or None, not %.80s",
|
|
2652
|
+
json_type_name(markers));
|
|
2653
|
+
return NULL;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2609
2656
|
s = (PyEncoderObject *)type->tp_alloc(type, 0);
|
|
2610
2657
|
if (s == NULL)
|
|
2611
2658
|
return NULL;
|
|
@@ -2829,7 +2876,14 @@ encoder_encode_nonfinite(PyEncoderObject *s, int sign)
|
|
|
2829
2876
|
_speedups_state *state = get_speedups_state(s->module_ref);
|
|
2830
2877
|
|
|
2831
2878
|
if (!s->allow_or_ignore_nan) {
|
|
2832
|
-
|
|
2879
|
+
const char *msg;
|
|
2880
|
+
if (sign > 0)
|
|
2881
|
+
msg = "Out of range float values are not JSON compliant: inf";
|
|
2882
|
+
else if (sign < 0)
|
|
2883
|
+
msg = "Out of range float values are not JSON compliant: -inf";
|
|
2884
|
+
else
|
|
2885
|
+
msg = "Out of range float values are not JSON compliant: nan";
|
|
2886
|
+
PyErr_SetString(PyExc_ValueError, msg);
|
|
2833
2887
|
return NULL;
|
|
2834
2888
|
}
|
|
2835
2889
|
if (s->allow_or_ignore_nan & JSON_IGNORE_NAN) {
|
|
@@ -2965,9 +3019,10 @@ _steal_accumulate(_speedups_state *state, JSON_Accu *accu, PyObject *stolen)
|
|
|
2965
3019
|
/* Push a reference to `obj` into the encoder's circular-reference marker
|
|
2966
3020
|
* dict, keyed by the object's address. Allocates a fresh PyLong ident and
|
|
2967
3021
|
* stores it in *ident_ptr (caller owns the reference, and must pass it to
|
|
2968
|
-
* encoder_markers_pop
|
|
3022
|
+
* encoder_markers_pop on success, or encoder_markers_discard on an error
|
|
3023
|
+
* path, to remove the entry). If markers tracking is off
|
|
2969
3024
|
* (s->markers == Py_None), stores NULL in *ident_ptr and returns 0 with
|
|
2970
|
-
* no side effects — that NULL is the sentinel
|
|
3025
|
+
* no side effects — that NULL is the sentinel both of those understand.
|
|
2971
3026
|
* On circular reference sets the ValueError; on any other failure sets
|
|
2972
3027
|
* the corresponding exception. Returns 0 on success, -1 on error. */
|
|
2973
3028
|
static int
|
|
@@ -3013,6 +3068,52 @@ encoder_markers_pop(PyEncoderObject *s, PyObject *ident)
|
|
|
3013
3068
|
return rv;
|
|
3014
3069
|
}
|
|
3015
3070
|
|
|
3071
|
+
/* Error-path counterpart to encoder_markers_pop. Removes the ident
|
|
3072
|
+
* entry while an exception is propagating, so an encoder whose markers
|
|
3073
|
+
* dict is reused after a failed call does not report a false circular
|
|
3074
|
+
* reference, and drops the caller's reference. The in-flight exception
|
|
3075
|
+
* is preserved; a failure to delete the entry is swallowed. Passing
|
|
3076
|
+
* NULL is a no-op. */
|
|
3077
|
+
static void
|
|
3078
|
+
encoder_markers_discard(PyEncoderObject *s, PyObject *ident)
|
|
3079
|
+
{
|
|
3080
|
+
PyObject *exc_type;
|
|
3081
|
+
PyObject *exc_value;
|
|
3082
|
+
PyObject *exc_tb;
|
|
3083
|
+
if (ident == NULL)
|
|
3084
|
+
return;
|
|
3085
|
+
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
|
|
3086
|
+
if (PyDict_DelItem(s->markers, ident) < 0)
|
|
3087
|
+
PyErr_Clear();
|
|
3088
|
+
PyErr_Restore(exc_type, exc_value, exc_tb);
|
|
3089
|
+
Py_DECREF(ident);
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
/* Raise ValueError if obj is already in the markers dict, i.e. it is
|
|
3093
|
+
* currently being encoded further up the stack. Used where a side-
|
|
3094
|
+
* effecting call (such as __iter__) has to run before the marker can
|
|
3095
|
+
* be pushed. Returns 0 when obj is not marked or tracking is off, -1
|
|
3096
|
+
* with an exception set otherwise. */
|
|
3097
|
+
static int
|
|
3098
|
+
encoder_markers_check(PyEncoderObject *s, PyObject *obj)
|
|
3099
|
+
{
|
|
3100
|
+
PyObject *ident;
|
|
3101
|
+
int has_key;
|
|
3102
|
+
if (s->markers == Py_None)
|
|
3103
|
+
return 0;
|
|
3104
|
+
ident = PyLong_FromVoidPtr(obj);
|
|
3105
|
+
if (ident == NULL)
|
|
3106
|
+
return -1;
|
|
3107
|
+
has_key = PyDict_Contains(s->markers, ident);
|
|
3108
|
+
Py_DECREF(ident);
|
|
3109
|
+
if (has_key) {
|
|
3110
|
+
if (has_key != -1)
|
|
3111
|
+
PyErr_SetString(PyExc_ValueError, "Circular reference detected");
|
|
3112
|
+
return -1;
|
|
3113
|
+
}
|
|
3114
|
+
return 0;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3016
3117
|
/* Helper for the for_json / _asdict paths in encoder_listencode_obj.
|
|
3017
3118
|
* Steals the reference to `newobj` (returned by _call_json_method),
|
|
3018
3119
|
* tracks the original object's circular-reference marker and recursion
|
|
@@ -3040,7 +3141,7 @@ encoder_steal_encode(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3040
3141
|
}
|
|
3041
3142
|
if (Py_EnterRecursiveCall(" while encoding a JSON object")) {
|
|
3042
3143
|
Py_DECREF(newobj);
|
|
3043
|
-
|
|
3144
|
+
encoder_markers_discard(s, ident);
|
|
3044
3145
|
return -1;
|
|
3045
3146
|
}
|
|
3046
3147
|
if (as_dict) {
|
|
@@ -3049,7 +3150,7 @@ encoder_steal_encode(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3049
3150
|
} else {
|
|
3050
3151
|
PyErr_Format(PyExc_TypeError,
|
|
3051
3152
|
"_asdict() must return a dict, not %.80s",
|
|
3052
|
-
|
|
3153
|
+
json_type_name(newobj));
|
|
3053
3154
|
rv = -1;
|
|
3054
3155
|
}
|
|
3055
3156
|
} else {
|
|
@@ -3061,7 +3162,7 @@ encoder_steal_encode(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3061
3162
|
if (encoder_markers_pop(s, ident) < 0)
|
|
3062
3163
|
rv = -1;
|
|
3063
3164
|
} else {
|
|
3064
|
-
|
|
3165
|
+
encoder_markers_discard(s, ident);
|
|
3065
3166
|
}
|
|
3066
3167
|
return rv;
|
|
3067
3168
|
}
|
|
@@ -3072,6 +3173,9 @@ encoder_steal_encode(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3072
3173
|
* three sub-cases in order:
|
|
3073
3174
|
* 1. RawJSON — emit the already-encoded string verbatim.
|
|
3074
3175
|
* 2. iterable_as_array — treat any iterable object as a JSON array.
|
|
3176
|
+
* obj itself (not its iterator, which may be fresh on every
|
|
3177
|
+
* visit) is the circular-reference marker, and the recursion
|
|
3178
|
+
* depth is tracked.
|
|
3075
3179
|
* 3. default(obj) — call the user-supplied default hook and recurse
|
|
3076
3180
|
* on its result, with circular-reference tracking via markers.
|
|
3077
3181
|
* Returns 0 on success, -1 on error. */
|
|
@@ -3096,13 +3200,22 @@ encoder_listencode_default(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3096
3200
|
}
|
|
3097
3201
|
|
|
3098
3202
|
if (s->iterable_as_array) {
|
|
3203
|
+
/* Reject a revisited iterable before its __iter__ runs again;
|
|
3204
|
+
* encoder_listencode_list pushes the marker for obj. */
|
|
3205
|
+
if (encoder_markers_check(s, obj))
|
|
3206
|
+
return -1;
|
|
3099
3207
|
newobj = PyObject_GetIter(obj);
|
|
3100
3208
|
if (newobj == NULL) {
|
|
3101
3209
|
if (!PyErr_ExceptionMatches(PyExc_TypeError))
|
|
3102
3210
|
return -1;
|
|
3103
3211
|
PyErr_Clear();
|
|
3104
3212
|
} else {
|
|
3105
|
-
|
|
3213
|
+
if (Py_EnterRecursiveCall(" while encoding a JSON object")) {
|
|
3214
|
+
Py_DECREF(newobj);
|
|
3215
|
+
return -1;
|
|
3216
|
+
}
|
|
3217
|
+
rv = encoder_listencode_list(s, rval, newobj, obj, indent_level);
|
|
3218
|
+
Py_LeaveRecursiveCall();
|
|
3106
3219
|
Py_DECREF(newobj);
|
|
3107
3220
|
return rv;
|
|
3108
3221
|
}
|
|
@@ -3111,7 +3224,7 @@ encoder_listencode_default(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3111
3224
|
if (encoder_markers_push(s, obj, &ident))
|
|
3112
3225
|
return -1;
|
|
3113
3226
|
if (Py_EnterRecursiveCall(" while encoding a JSON object")) {
|
|
3114
|
-
|
|
3227
|
+
encoder_markers_discard(s, ident);
|
|
3115
3228
|
return -1;
|
|
3116
3229
|
}
|
|
3117
3230
|
newobj = PyObject_CallOneArg(s->defaultfn, obj);
|
|
@@ -3122,10 +3235,10 @@ encoder_listencode_default(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3122
3235
|
* encoder which binds type(o).__name__ before `o = default(o)`
|
|
3123
3236
|
* runs. */
|
|
3124
3237
|
encoder_annotate_exception(state,
|
|
3125
|
-
"when serializing %s object",
|
|
3238
|
+
"when serializing %s object", json_type_name(obj));
|
|
3126
3239
|
#endif
|
|
3127
3240
|
Py_LeaveRecursiveCall();
|
|
3128
|
-
|
|
3241
|
+
encoder_markers_discard(s, ident);
|
|
3129
3242
|
return -1;
|
|
3130
3243
|
}
|
|
3131
3244
|
rv = encoder_listencode_obj(s, rval, newobj, indent_level);
|
|
@@ -3136,7 +3249,7 @@ encoder_listencode_default(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3136
3249
|
* the Python encoder `o` has been rebound to newobj at this
|
|
3137
3250
|
* point, so the note reflects that type. */
|
|
3138
3251
|
encoder_annotate_exception(state,
|
|
3139
|
-
"when serializing %s object",
|
|
3252
|
+
"when serializing %s object", json_type_name(newobj));
|
|
3140
3253
|
#endif
|
|
3141
3254
|
}
|
|
3142
3255
|
Py_DECREF(newobj);
|
|
@@ -3144,7 +3257,7 @@ encoder_listencode_default(PyEncoderObject *s, JSON_Accu *rval,
|
|
|
3144
3257
|
if (encoder_markers_pop(s, ident) < 0)
|
|
3145
3258
|
rv = -1;
|
|
3146
3259
|
} else {
|
|
3147
|
-
|
|
3260
|
+
encoder_markers_discard(s, ident);
|
|
3148
3261
|
}
|
|
3149
3262
|
return rv;
|
|
3150
3263
|
}
|
|
@@ -3218,7 +3331,7 @@ encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ss
|
|
|
3218
3331
|
else if (PyList_Check(obj) || (s->tuple_as_array && PyTuple_Check(obj))) {
|
|
3219
3332
|
if (Py_EnterRecursiveCall(" while encoding a JSON object"))
|
|
3220
3333
|
return rv;
|
|
3221
|
-
rv = encoder_listencode_list(s, rval, obj, indent_level);
|
|
3334
|
+
rv = encoder_listencode_list(s, rval, obj, obj, indent_level);
|
|
3222
3335
|
Py_LeaveRecursiveCall();
|
|
3223
3336
|
}
|
|
3224
3337
|
else if (JSON_AnyDict_Check(obj)) {
|
|
@@ -3396,6 +3509,7 @@ encoder_listencode_dict(PyEncoderObject *s, JSON_Accu *rval, PyObject *dct, Py_s
|
|
|
3396
3509
|
int indented = (s->indent != Py_None);
|
|
3397
3510
|
Py_ssize_t inner_indent_level = indented ? indent_level + 1 : indent_level;
|
|
3398
3511
|
Py_ssize_t idx;
|
|
3512
|
+
int popped;
|
|
3399
3513
|
|
|
3400
3514
|
{
|
|
3401
3515
|
Py_ssize_t dct_size = PyDict_Check(dct) ? PyDict_Size(dct)
|
|
@@ -3424,51 +3538,86 @@ encoder_listencode_dict(PyEncoderObject *s, JSON_Accu *rval, PyObject *dct, Py_s
|
|
|
3424
3538
|
if (s->item_sort_kw == Py_None && PyDict_CheckExact(dct)) {
|
|
3425
3539
|
Py_ssize_t pos = 0;
|
|
3426
3540
|
PyObject *key, *value;
|
|
3541
|
+
Py_ssize_t size;
|
|
3542
|
+
#if PY_MAJOR_VERSION >= 3
|
|
3543
|
+
Py_ssize_t remaining;
|
|
3544
|
+
#endif
|
|
3427
3545
|
int err = 0;
|
|
3428
3546
|
|
|
3429
3547
|
idx = 0;
|
|
3430
3548
|
Py_BEGIN_CRITICAL_SECTION(dct);
|
|
3549
|
+
size = PyDict_Size(dct);
|
|
3550
|
+
#if PY_MAJOR_VERSION >= 3
|
|
3551
|
+
remaining = size;
|
|
3552
|
+
#endif
|
|
3431
3553
|
while (PyDict_Next(dct, &pos, &key, &value)) {
|
|
3554
|
+
#if PY_MAJOR_VERSION >= 3
|
|
3555
|
+
/* User code that replaced keys without changing the size
|
|
3556
|
+
* (pop and re-add a key) leaves entries past the original
|
|
3557
|
+
* ones. Fail the way Python 3's dict iterator does rather
|
|
3558
|
+
* than encode keys twice. */
|
|
3559
|
+
if (remaining == 0) {
|
|
3560
|
+
PyErr_SetString(PyExc_RuntimeError,
|
|
3561
|
+
"dictionary keys changed during iteration");
|
|
3562
|
+
err = 1;
|
|
3563
|
+
break;
|
|
3564
|
+
}
|
|
3565
|
+
remaining--;
|
|
3566
|
+
#endif
|
|
3567
|
+
/* Hold key until the value is encoded: encoding the value
|
|
3568
|
+
* can run user code (default, for_json, ...) that removes
|
|
3569
|
+
* the entry, and the error note below still needs key. */
|
|
3432
3570
|
Py_INCREF(key);
|
|
3433
3571
|
Py_INCREF(value);
|
|
3434
3572
|
|
|
3435
3573
|
encoded = encoder_encode_dict_key(s, key);
|
|
3436
|
-
Py_DECREF(key);
|
|
3437
3574
|
if (encoded == NULL) {
|
|
3438
|
-
Py_DECREF(value); err = 1; break;
|
|
3575
|
+
Py_DECREF(key); Py_DECREF(value); err = 1; break;
|
|
3439
3576
|
}
|
|
3440
3577
|
if (encoded == Py_None) {
|
|
3441
3578
|
/* skipkeys */
|
|
3442
3579
|
encoded = NULL;
|
|
3580
|
+
Py_DECREF(key);
|
|
3443
3581
|
Py_DECREF(value);
|
|
3444
3582
|
continue;
|
|
3445
3583
|
}
|
|
3446
3584
|
if (idx) {
|
|
3447
3585
|
if (JSON_Accu_Accumulate(state, rval, s->item_separator)) {
|
|
3448
|
-
Py_DECREF(value); err = 1; break;
|
|
3586
|
+
Py_DECREF(key); Py_DECREF(value); err = 1; break;
|
|
3449
3587
|
}
|
|
3450
3588
|
if (indented && encoder_accumulate_newline_indent(
|
|
3451
3589
|
s, state, rval, inner_indent_level)) {
|
|
3452
|
-
Py_DECREF(value); err = 1; break;
|
|
3590
|
+
Py_DECREF(key); Py_DECREF(value); err = 1; break;
|
|
3453
3591
|
}
|
|
3454
3592
|
}
|
|
3455
3593
|
if (JSON_Accu_Accumulate(state, rval, encoded)) {
|
|
3456
|
-
Py_DECREF(value); err = 1; break;
|
|
3594
|
+
Py_DECREF(key); Py_DECREF(value); err = 1; break;
|
|
3457
3595
|
}
|
|
3458
3596
|
Py_CLEAR(encoded);
|
|
3459
3597
|
if (JSON_Accu_Accumulate(state, rval, s->key_separator)) {
|
|
3460
|
-
Py_DECREF(value); err = 1; break;
|
|
3598
|
+
Py_DECREF(key); Py_DECREF(value); err = 1; break;
|
|
3461
3599
|
}
|
|
3462
3600
|
if (encoder_listencode_obj(s, rval, value, inner_indent_level)) {
|
|
3463
3601
|
#if PY_VERSION_HEX >= 0x030B0000
|
|
3464
3602
|
encoder_annotate_exception(state,
|
|
3465
3603
|
"when serializing %s item %R",
|
|
3466
|
-
|
|
3604
|
+
json_type_name(dct), key);
|
|
3467
3605
|
#endif
|
|
3468
|
-
Py_DECREF(value); err = 1; break;
|
|
3606
|
+
Py_DECREF(key); Py_DECREF(value); err = 1; break;
|
|
3469
3607
|
}
|
|
3608
|
+
Py_DECREF(key);
|
|
3470
3609
|
Py_DECREF(value);
|
|
3471
3610
|
idx++;
|
|
3611
|
+
/* PyDict_Next walks entry slots, so a dict resized by that
|
|
3612
|
+
* user code would have entries skipped or repeated. Fail
|
|
3613
|
+
* the way the pure-Python encoder's dict iteration does,
|
|
3614
|
+
* which on Python 2 is only this check. */
|
|
3615
|
+
if (PyDict_Size(dct) != size) {
|
|
3616
|
+
PyErr_SetString(PyExc_RuntimeError,
|
|
3617
|
+
"dictionary changed size during iteration");
|
|
3618
|
+
err = 1;
|
|
3619
|
+
break;
|
|
3620
|
+
}
|
|
3472
3621
|
}
|
|
3473
3622
|
Py_END_CRITICAL_SECTION();
|
|
3474
3623
|
|
|
@@ -3517,7 +3666,7 @@ encoder_listencode_dict(PyEncoderObject *s, JSON_Accu *rval, PyObject *dct, Py_s
|
|
|
3517
3666
|
#if PY_VERSION_HEX >= 0x030B0000
|
|
3518
3667
|
encoder_annotate_exception(state,
|
|
3519
3668
|
"when serializing %s item %R",
|
|
3520
|
-
|
|
3669
|
+
json_type_name(dct), key);
|
|
3521
3670
|
#endif
|
|
3522
3671
|
goto bail;
|
|
3523
3672
|
}
|
|
@@ -3529,9 +3678,12 @@ encoder_listencode_dict(PyEncoderObject *s, JSON_Accu *rval, PyObject *dct, Py_s
|
|
|
3529
3678
|
goto bail;
|
|
3530
3679
|
}
|
|
3531
3680
|
|
|
3532
|
-
|
|
3533
|
-
|
|
3681
|
+
/* encoder_markers_pop releases ident even when it fails, so clear
|
|
3682
|
+
* it before bail can see it. */
|
|
3683
|
+
popped = encoder_markers_pop(s, ident);
|
|
3534
3684
|
ident = NULL;
|
|
3685
|
+
if (popped)
|
|
3686
|
+
goto bail;
|
|
3535
3687
|
if (indented) {
|
|
3536
3688
|
if (encoder_accumulate_newline_indent(s, state, rval, indent_level))
|
|
3537
3689
|
goto bail;
|
|
@@ -3544,15 +3696,19 @@ bail:
|
|
|
3544
3696
|
Py_XDECREF(encoded);
|
|
3545
3697
|
Py_XDECREF(item);
|
|
3546
3698
|
Py_XDECREF(iter);
|
|
3547
|
-
|
|
3699
|
+
encoder_markers_discard(s, ident);
|
|
3548
3700
|
return -1;
|
|
3549
3701
|
}
|
|
3550
3702
|
|
|
3551
3703
|
|
|
3552
3704
|
static int
|
|
3553
|
-
encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq,
|
|
3705
|
+
encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq,
|
|
3706
|
+
PyObject *origin, Py_ssize_t indent_level)
|
|
3554
3707
|
{
|
|
3555
|
-
/* Encode
|
|
3708
|
+
/* Encode the items of seq as a JSON array. origin is the object
|
|
3709
|
+
* being encoded: seq itself for a list or tuple, or the iterable
|
|
3710
|
+
* that produced the iterator seq under iterable_as_array. origin is
|
|
3711
|
+
* the circular-reference marker and is named in error notes. */
|
|
3556
3712
|
_speedups_state *state = get_speedups_state(s->module_ref);
|
|
3557
3713
|
PyObject *ident = NULL;
|
|
3558
3714
|
PyObject *iter = NULL;
|
|
@@ -3564,6 +3720,7 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3564
3720
|
Py_ssize_t inner_indent_level = indented ? indent_level + 1 : indent_level;
|
|
3565
3721
|
Py_ssize_t i = 0;
|
|
3566
3722
|
int is_exact_fast;
|
|
3723
|
+
int popped;
|
|
3567
3724
|
|
|
3568
3725
|
/* Emptiness check: use direct size for exact types to skip the
|
|
3569
3726
|
* __bool__/__len__ method dispatch of PyObject_IsTrue. */
|
|
@@ -3580,14 +3737,14 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3580
3737
|
else {
|
|
3581
3738
|
/* For non-exact types (list/tuple subclasses or other iterables)
|
|
3582
3739
|
* we cannot short-circuit on emptiness without consuming the
|
|
3583
|
-
* iterator. iterable_as_array in particular reaches us with
|
|
3584
|
-
*
|
|
3585
|
-
* emptiness is only discovered on the
|
|
3586
|
-
* inside the slow path below. */
|
|
3740
|
+
* iterator. iterable_as_array in particular reaches us with an
|
|
3741
|
+
* iterator, whose truth value says nothing about whether it
|
|
3742
|
+
* will yield items, so the emptiness is only discovered on the
|
|
3743
|
+
* first PyIter_Next call inside the slow path below. */
|
|
3587
3744
|
is_exact_fast = 0;
|
|
3588
3745
|
}
|
|
3589
3746
|
|
|
3590
|
-
if (encoder_markers_push(s,
|
|
3747
|
+
if (encoder_markers_push(s, origin, &ident))
|
|
3591
3748
|
goto bail;
|
|
3592
3749
|
|
|
3593
3750
|
if (is_exact_fast) {
|
|
@@ -3603,7 +3760,6 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3603
3760
|
* the bail handler's Py_XDECREF(obj) stays a no-op for this
|
|
3604
3761
|
* path. */
|
|
3605
3762
|
PyObject *item;
|
|
3606
|
-
Py_ssize_t size;
|
|
3607
3763
|
int is_list = PyList_CheckExact(seq);
|
|
3608
3764
|
int err = 0;
|
|
3609
3765
|
|
|
@@ -3616,8 +3772,12 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3616
3772
|
}
|
|
3617
3773
|
|
|
3618
3774
|
Py_BEGIN_CRITICAL_SECTION(seq);
|
|
3619
|
-
size
|
|
3620
|
-
|
|
3775
|
+
/* Re-read the size on every iteration, as a list iterator does:
|
|
3776
|
+
* encoding an item can run user code (default, for_json, ...)
|
|
3777
|
+
* that resizes the list, and on free-threaded builds the
|
|
3778
|
+
* critical section can be released while that code runs. */
|
|
3779
|
+
for (i = 0; i < (is_list ? PyList_GET_SIZE(seq)
|
|
3780
|
+
: PyTuple_GET_SIZE(seq)); i++) {
|
|
3621
3781
|
item = is_list ? PyList_GET_ITEM(seq, i)
|
|
3622
3782
|
: PyTuple_GET_ITEM(seq, i);
|
|
3623
3783
|
Py_INCREF(item);
|
|
@@ -3634,7 +3794,7 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3634
3794
|
#if PY_VERSION_HEX >= 0x030B0000
|
|
3635
3795
|
encoder_annotate_exception(state,
|
|
3636
3796
|
"when serializing %s item %zd",
|
|
3637
|
-
|
|
3797
|
+
json_type_name(origin), i);
|
|
3638
3798
|
#endif
|
|
3639
3799
|
Py_DECREF(item); err = 1; break;
|
|
3640
3800
|
}
|
|
@@ -3682,7 +3842,7 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3682
3842
|
#if PY_VERSION_HEX >= 0x030B0000
|
|
3683
3843
|
encoder_annotate_exception(state,
|
|
3684
3844
|
"when serializing %s item %zd",
|
|
3685
|
-
|
|
3845
|
+
json_type_name(origin), i);
|
|
3686
3846
|
#endif
|
|
3687
3847
|
goto bail;
|
|
3688
3848
|
}
|
|
@@ -3707,15 +3867,18 @@ encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_s
|
|
|
3707
3867
|
}
|
|
3708
3868
|
}
|
|
3709
3869
|
|
|
3710
|
-
|
|
3711
|
-
|
|
3870
|
+
/* encoder_markers_pop releases ident even when it fails, so clear
|
|
3871
|
+
* it before bail can see it. */
|
|
3872
|
+
popped = encoder_markers_pop(s, ident);
|
|
3712
3873
|
ident = NULL;
|
|
3874
|
+
if (popped)
|
|
3875
|
+
goto bail;
|
|
3713
3876
|
return 0;
|
|
3714
3877
|
|
|
3715
3878
|
bail:
|
|
3716
3879
|
Py_XDECREF(obj);
|
|
3717
3880
|
Py_XDECREF(iter);
|
|
3718
|
-
|
|
3881
|
+
encoder_markers_discard(s, ident);
|
|
3719
3882
|
return -1;
|
|
3720
3883
|
}
|
|
3721
3884
|
|
|
@@ -377,9 +377,11 @@ class JSONDecoder(object):
|
|
|
377
377
|
self.encoding = encoding
|
|
378
378
|
self.object_hook = object_hook
|
|
379
379
|
self.object_pairs_hook = object_pairs_hook
|
|
380
|
-
self.parse_float = parse_float
|
|
381
|
-
self.parse_int = parse_int
|
|
382
|
-
|
|
380
|
+
self.parse_float = float if parse_float is None else parse_float
|
|
381
|
+
self.parse_int = bounded_int if parse_int is None else parse_int
|
|
382
|
+
if parse_constant is None:
|
|
383
|
+
parse_constant = allow_nan and _CONSTANTS.__getitem__ or None
|
|
384
|
+
self.parse_constant = parse_constant
|
|
383
385
|
self.strict = strict
|
|
384
386
|
self.array_hook = array_hook
|
|
385
387
|
self.parse_object = JSONObject
|