1
"""Implementation of JSONEncoder
6
from _json import encode_basestring_ascii as c_encode_basestring_ascii
8
c_encode_basestring_ascii = None
10
from _json import encode_basestring as c_encode_basestring
12
c_encode_basestring = None
14
from _json import make_encoder as c_make_encoder
18
ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
19
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
20
HAS_UTF8 = re.compile(b'[\x80-\xff]')
31
ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
32
#ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
35
INFINITY = float('inf')
37
def py_encode_basestring(s):
38
"""Return a JSON representation of a Python string
42
return ESCAPE_DCT[match.group(0)]
43
return '"' + ESCAPE.sub(replace, s) + '"'
46
encode_basestring = (c_encode_basestring or py_encode_basestring)
49
def py_encode_basestring_ascii(s):
50
"""Return an ASCII-only JSON representation of a Python string
60
return '\\u{0:04x}'.format(n)
61
#return '\\u%04x' % (n,)
65
s1 = 0xd800 | ((n >> 10) & 0x3ff)
66
s2 = 0xdc00 | (n & 0x3ff)
67
return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
68
return '"' + ESCAPE_ASCII.sub(replace, s) + '"'
71
encode_basestring_ascii = (
72
c_encode_basestring_ascii or py_encode_basestring_ascii)
74
class JSONEncoder(object):
75
"""Extensible JSON <https://json.org> encoder for Python data structures.
77
Supports the following objects and types by default:
79
+-------------------+---------------+
81
+===================+===============+
82
| dict, frozendict | object |
83
+-------------------+---------------+
84
| list, tuple | array |
85
+-------------------+---------------+
87
+-------------------+---------------+
88
| int, float | number |
89
+-------------------+---------------+
91
+-------------------+---------------+
93
+-------------------+---------------+
95
+-------------------+---------------+
97
To extend this to recognize other objects, subclass and implement a
98
``.default()`` method with another method that returns a serializable
99
object for ``o`` if possible, otherwise it should call the superclass
100
implementation (to raise ``TypeError``).
103
item_separator = ', '
105
def __init__(self, *, skipkeys=False, ensure_ascii=True,
106
check_circular=True, allow_nan=True, sort_keys=False,
107
indent=None, separators=None, default=None):
108
"""Constructor for JSONEncoder, with sensible defaults.
110
If skipkeys is false, then it is a TypeError to attempt
111
encoding of keys that are not str, int, float, bool or None.
112
If skipkeys is True, such items are simply skipped.
114
If ensure_ascii is true, the output is guaranteed to be str objects
115
with all incoming non-ASCII and non-printable characters escaped.
116
If ensure_ascii is false, the output can contain non-ASCII and
117
non-printable characters.
119
If check_circular is true, then lists, dicts, and custom encoded
120
objects will be checked for circular references during encoding to
121
prevent an infinite recursion (which would cause an RecursionError).
122
Otherwise, no such check takes place.
124
If allow_nan is true, then NaN, Infinity, and -Infinity will be
125
encoded as such. This behavior is not JSON specification compliant,
126
but is consistent with most JavaScript based encoders and decoders.
127
Otherwise, it will be a ValueError to encode such floats.
129
If sort_keys is true, then the output of dictionaries will be
130
sorted by key; this is useful for regression tests to ensure
131
that JSON serializations can be compared on a day-to-day basis.
133
If indent is a non-negative integer, then JSON array
134
elements and object members will be pretty-printed with that
135
indent level. An indent level of 0 will only insert newlines.
136
None is the most compact representation.
138
If specified, separators should be an (item_separator,
139
key_separator) tuple. The default is (', ', ': ') if *indent* is
140
``None`` and (',', ': ') otherwise. To get the most compact JSON
141
representation, you should specify (',', ':') to eliminate
144
If specified, default is a function that gets called for objects
145
that can't otherwise be serialized. It should return a JSON
146
encodable version of the object or raise a ``TypeError``.
150
self.skipkeys = skipkeys
151
self.ensure_ascii = ensure_ascii
152
self.check_circular = check_circular
153
self.allow_nan = allow_nan
154
self.sort_keys = sort_keys
156
if separators is not None:
157
self.item_separator, self.key_separator = separators
158
elif indent is not None:
159
self.item_separator = ','
160
if default is not None:
161
self.default = default
163
def default(self, o):
164
"""Implement this method in a subclass such that it returns
165
a serializable object for ``o``, or calls the base implementation
166
(to raise a ``TypeError``).
168
For example, to support arbitrary iterators, you could
169
implement default like this::
171
def default(self, o):
177
return list(iterable)
178
# Let the base class default method raise the TypeError
179
return super().default(o)
182
raise TypeError(f'Object of type {o.__class__.__name__} '
183
f'is not JSON serializable')
186
"""Return a JSON string representation of a Python data structure.
188
>>> from json.encoder import JSONEncoder
189
>>> JSONEncoder().encode({"foo": ["bar", "baz"]})
190
'{"foo": ["bar", "baz"]}'
193
# This is for extremely simple cases and benchmarks.
194
if isinstance(o, str):
195
if self.ensure_ascii:
196
return encode_basestring_ascii(o)
198
return encode_basestring(o)
199
# This doesn't pass the iterator directly to ''.join() because the
200
# exceptions aren't as detailed. The list call should be roughly
201
# equivalent to the PySequence_Fast that ''.join() would do.
202
530
chunks = self.iterencode(o, _one_shot=True)
203
if not isinstance(chunks, (list, tuple)):
204
chunks = list(chunks)
205
return ''.join(chunks)
207
def iterencode(self, o, _one_shot=False):
208
"""Encode the given object and yield each string
209
representation as available.
213
for chunk in JSONEncoder().iterencode(bigobject):
214
mysocket.write(chunk)
217
if self.check_circular:
221
if self.ensure_ascii:
222
_encoder = encode_basestring_ascii
224
_encoder = encode_basestring
226
def floatstr(o, allow_nan=self.allow_nan,
227
_repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
228
# Check for specials. Note that this type of test is processor
229
# and/or platform-specific, so do tests which don't depend on the
243
"Out of range float values are not JSON compliant: " +
249
if self.indent is None or isinstance(self.indent, str):
252
indent = ' ' * self.indent
253
if _one_shot and c_make_encoder is not None:
254
_iterencode = c_make_encoder(
255
markers, self.default, _encoder, indent,
256
self.key_separator, self.item_separator, self.sort_keys,
257
self.skipkeys, self.allow_nan)
259
_iterencode = _make_iterencode(
260
markers, self.default, _encoder, indent, floatstr,
261
self.key_separator, self.item_separator, self.sort_keys,
262
self.skipkeys, _one_shot)
263
530
530
return _iterencode(o, 0)
265
def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
266
_key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
269
def _iterencode_list(lst, _current_indent_level):
273
if markers is not None:
275
if markerid in markers:
276
raise ValueError("Circular reference detected")
277
markers[markerid] = lst
279
if _indent is not None:
280
_current_indent_level += 1
281
newline_indent = '\n' + _indent * _current_indent_level
282
separator = _item_separator + newline_indent
283
buf += newline_indent
285
newline_indent = None
286
separator = _item_separator
287
for i, value in enumerate(lst):
291
if isinstance(value, str):
292
yield buf + _encoder(value)
299
elif isinstance(value, int):
300
# Subclasses of int/float may override __repr__, but we still
301
# want to encode them as integers/floats in JSON. One example
302
# within the standard library is IntEnum.
303
yield buf + int.__repr__(value)
304
elif isinstance(value, float):
305
# see comment above for int
306
yield buf + _floatstr(value)
309
if isinstance(value, (list, tuple)):
310
chunks = _iterencode_list(value, _current_indent_level)
311
elif isinstance(value, (dict, frozendict)):
312
chunks = _iterencode_dict(value, _current_indent_level)
314
chunks = _iterencode(value, _current_indent_level)
316
except GeneratorExit:
318
except BaseException as exc:
319
exc.add_note(f'when serializing {type(lst).__name__} item {i}')
321
if newline_indent is not None:
322
_current_indent_level -= 1
323
yield '\n' + _indent * _current_indent_level
325
if markers is not None:
326
del markers[markerid]
328
def _iterencode_dict(dct, _current_indent_level):
332
if markers is not None:
334
if markerid in markers:
335
raise ValueError("Circular reference detected")
336
markers[markerid] = dct
338
if _indent is not None:
339
_current_indent_level += 1
340
newline_indent = '\n' + _indent * _current_indent_level
341
item_separator = _item_separator + newline_indent
343
newline_indent = None
344
item_separator = _item_separator
347
items = sorted(dct.items())
350
for key, value in items:
351
if isinstance(key, str):
353
# JavaScript is weakly typed for these, so it makes sense to
354
# also allow them. Many encoders seem to do something like this.
355
elif isinstance(key, float):
356
# see comment for int/float in _make_iterencode
364
elif isinstance(key, int):
365
# see comment for int/float in _make_iterencode
366
key = int.__repr__(key)
370
raise TypeError(f'keys must be str, int, float, bool or None, '
371
f'not {key.__class__.__name__}')
374
if newline_indent is not None:
381
if isinstance(value, str):
382
yield _encoder(value)
389
elif isinstance(value, int):
390
# see comment for int/float in _make_iterencode
391
yield int.__repr__(value)
392
elif isinstance(value, float):
393
# see comment for int/float in _make_iterencode
394
yield _floatstr(value)
396
if isinstance(value, (list, tuple)):
397
chunks = _iterencode_list(value, _current_indent_level)
398
elif isinstance(value, (dict, frozendict)):
399
chunks = _iterencode_dict(value, _current_indent_level)
401
chunks = _iterencode(value, _current_indent_level)
403
except GeneratorExit:
405
except BaseException as exc:
406
exc.add_note(f'when serializing {type(dct).__name__} item {key!r}')
408
if not first and newline_indent is not None:
409
_current_indent_level -= 1
410
yield '\n' + _indent * _current_indent_level
412
if markers is not None:
413
del markers[markerid]
415
def _iterencode(o, _current_indent_level):
416
if isinstance(o, str):
424
elif isinstance(o, int):
425
# see comment for int/float in _make_iterencode
426
yield int.__repr__(o)
427
elif isinstance(o, float):
428
# see comment for int/float in _make_iterencode
430
elif isinstance(o, (list, tuple)):
431
yield from _iterencode_list(o, _current_indent_level)
432
elif isinstance(o, (dict, frozendict)):
433
yield from _iterencode_dict(o, _current_indent_level)
435
if markers is not None:
437
if markerid in markers:
438
raise ValueError("Circular reference detected")
439
markers[markerid] = o
442
yield from _iterencode(newobj, _current_indent_level)
443
except GeneratorExit:
445
except BaseException as exc:
446
exc.add_note(f'when serializing {type(o).__name__} object')
448
if markers is not None:
449
del markers[markerid]
451
def _iterencode_once(o, _current_indent_level):
452
nonlocal _iterencode, _iterencode_dict, _iterencode_list
454
yield from _iterencode(o, _current_indent_level)
456
# Break reference cycles due to mutually recursive closures:
457
del _iterencode, _iterencode_dict, _iterencode_list
459
return _iterencode_once