1"""Implementation of JSONEncoder
2"""
3from __future__ import absolute_import
4import re
5from operator import itemgetter
6# Do not import Decimal directly to avoid reload issues
7import decimal
8import sys
9from .compat import binary_type, text_type, string_types, integer_types, PY3
10
11# PEP 678 add_note() is available on Python 3.11+
12_HAS_ADD_NOTE = sys.version_info >= (3, 11)
13
14def _import_speedups():
15 try:
16 from . import _speedups
17 return (_speedups.encode_basestring_ascii,
18 _speedups.encode_basestring,
19 _speedups.make_encoder)
20 except ImportError:
21 return None, None, None
22c_encode_basestring_ascii, c_encode_basestring, c_make_encoder = (
23 _import_speedups())
24
25from .decoder import PosInf
26from .raw_json import RawJSON
27
28ESCAPE = re.compile(r'[\x00-\x1f\\"]')
29ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
30HAS_UTF8 = re.compile(r'[\x80-\xff]')
31ESCAPE_DCT = {
32 '\\': '\\\\',
33 '"': '\\"',
34 '\b': '\\b',
35 '\f': '\\f',
36 '\n': '\\n',
37 '\r': '\\r',
38 '\t': '\\t',
39}
40for i in range(0x20):
41 ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
42del i
43
44FLOAT_REPR = repr
45
46# dict-like types that should be encoded as JSON objects.
47# frozendict is a builtin added in CPython 3.15 (PEP 814).
48if sys.version_info >= (3, 15):
49 _dict_types = (dict, frozendict)
50else:
51 _dict_types = dict
52
53def py_encode_basestring(s, _PY3=PY3, _q=u'"'):
54 """Return a JSON representation of a Python string
55
56 """
57 if _PY3:
58 if isinstance(s, bytes):
59 s = str(s, 'utf-8')
60 elif type(s) is not str:
61 # convert an str subclass instance to exact str
62 # raise a TypeError otherwise
63 s = str.__str__(s)
64 else:
65 if isinstance(s, str) and HAS_UTF8.search(s) is not None:
66 s = unicode(s, 'utf-8')
67 elif type(s) not in (str, unicode):
68 # convert an str subclass instance to exact str
69 # convert a unicode subclass instance to exact unicode
70 # raise a TypeError otherwise
71 if isinstance(s, str):
72 s = str.__str__(s)
73 else:
74 s = unicode.__getnewargs__(s)[0]
75 def replace(match):
76 return ESCAPE_DCT[match.group(0)]
77 return _q + ESCAPE.sub(replace, s) + _q
78
79
80def py_encode_basestring_ascii(s, _PY3=PY3):
81 """Return an ASCII-only JSON representation of a Python string
82
83 """
84 if _PY3:
85 if isinstance(s, bytes):
86 s = str(s, 'utf-8')
87 elif type(s) is not str:
88 # convert an str subclass instance to exact str
89 # raise a TypeError otherwise
90 s = str.__str__(s)
91 else:
92 if isinstance(s, str) and HAS_UTF8.search(s) is not None:
93 s = unicode(s, 'utf-8')
94 elif type(s) not in (str, unicode):
95 # convert an str subclass instance to exact str
96 # convert a unicode subclass instance to exact unicode
97 # raise a TypeError otherwise
98 if isinstance(s, str):
99 s = str.__str__(s)
100 else:
101 s = unicode.__getnewargs__(s)[0]
102 def replace(match):
103 s = match.group(0)
104 try:
105 return ESCAPE_DCT[s]
106 except KeyError:
107 n = ord(s)
108 if n < 0x10000:
109 return '\\u%04x' % (n,)
110 else:
111 # surrogate pair
112 n -= 0x10000
113 s1 = 0xd800 | ((n >> 10) & 0x3ff)
114 s2 = 0xdc00 | (n & 0x3ff)
115 return '\\u%04x\\u%04x' % (s1, s2)
116 return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
117
118
119encode_basestring_ascii = (
120 c_encode_basestring_ascii or py_encode_basestring_ascii)
121
122encode_basestring = (
123 c_encode_basestring or py_encode_basestring)
124
125class JSONEncoder(object):
126 """Extensible JSON <http://json.org> encoder for Python data structures.
127
128 Supports the following objects and types by default:
129
130 +-------------------+---------------+
131 | Python | JSON |
132 +===================+===============+
133 | dict, namedtuple | object |
134 +-------------------+---------------+
135 | list, tuple | array |
136 +-------------------+---------------+
137 | str, unicode | string |
138 +-------------------+---------------+
139 | int, long, float | number |
140 +-------------------+---------------+
141 | True | true |
142 +-------------------+---------------+
143 | False | false |
144 +-------------------+---------------+
145 | None | null |
146 +-------------------+---------------+
147
148 To extend this to recognize other objects, subclass and implement a
149 ``.default()`` method with another method that returns a serializable
150 object for ``o`` if possible, otherwise it should call the superclass
151 implementation (to raise ``TypeError``).
152
153 """
154 item_separator = ', '
155 key_separator = ': '
156
157 def __init__(self, skipkeys=False, ensure_ascii=True,
158 check_circular=True, allow_nan=False, sort_keys=False,
159 indent=None, separators=None, encoding='utf-8', default=None,
160 use_decimal=True, namedtuple_as_object=True,
161 tuple_as_array=True, bigint_as_string=False,
162 item_sort_key=None, for_json=False, ignore_nan=False,
163 int_as_string_bitcount=None, iterable_as_array=False):
164 """Constructor for JSONEncoder, with sensible defaults.
165
166 If skipkeys is false, then it is a TypeError to attempt
167 encoding of keys that are not str, int, long, float or None. If
168 skipkeys is True, such items are simply skipped.
169
170 If ensure_ascii is true, the output is guaranteed to be str
171 objects with all incoming unicode characters escaped. If
172 ensure_ascii is false, the output will be unicode object.
173
174 If check_circular is true, then lists, dicts, and custom encoded
175 objects will be checked for circular references during encoding to
176 prevent an infinite recursion (which would cause an OverflowError).
177 Otherwise, no such check takes place.
178
179 If allow_nan is true (default: False), then out of range float
180 values (nan, inf, -inf) will be serialized to
181 their JavaScript equivalents (NaN, Infinity, -Infinity)
182 instead of raising a ValueError. See
183 ignore_nan for ECMA-262 compliant behavior.
184
185 If sort_keys is true, then the output of dictionaries will be
186 sorted by key; this is useful for regression tests to ensure
187 that JSON serializations can be compared on a day-to-day basis.
188
189 If indent is a string, then JSON array elements and object members
190 will be pretty-printed with a newline followed by that string repeated
191 for each level of nesting. ``None`` (the default) selects the most compact
192 representation without any newlines. For backwards compatibility with
193 versions of simplejson earlier than 2.1.0, an integer is also accepted
194 and is converted to a string with that many spaces.
195
196 If specified, separators should be an (item_separator, key_separator)
197 tuple. The default is (', ', ': ') if *indent* is ``None`` and
198 (',', ': ') otherwise. To get the most compact JSON representation,
199 you should specify (',', ':') to eliminate whitespace.
200
201 If specified, default is a function that gets called for objects
202 that can't otherwise be serialized. It should return a JSON encodable
203 version of the object or raise a ``TypeError``.
204
205 If encoding is not None, then all input strings will be
206 transformed into unicode using that encoding prior to JSON-encoding.
207 The default is UTF-8.
208
209 If use_decimal is true (default: ``True``), ``decimal.Decimal`` will
210 be supported directly by the encoder. For the inverse, decode JSON
211 with ``parse_float=decimal.Decimal``.
212
213 If namedtuple_as_object is true (the default), objects with
214 ``_asdict()`` methods will be encoded as JSON objects.
215
216 If tuple_as_array is true (the default), tuple (and subclasses) will
217 be encoded as JSON arrays.
218
219 If *iterable_as_array* is true (default: ``False``),
220 any object not in the above table that implements ``__iter__()``
221 will be encoded as a JSON array.
222
223 If bigint_as_string is true (not the default), ints 2**53 and higher
224 or lower than -2**53 will be encoded as strings. This is to avoid the
225 rounding that happens in Javascript otherwise.
226
227 If int_as_string_bitcount is a positive number (n), then int of size
228 greater than or equal to 2**n or lower than or equal to -2**n will be
229 encoded as strings.
230
231 If specified, item_sort_key is a callable used to sort the items in
232 each dictionary. This is useful if you want to sort items other than
233 in alphabetical order by key.
234
235 If for_json is true (not the default), objects with a ``for_json()``
236 method will use the return value of that method for encoding as JSON
237 instead of the object.
238
239 If *ignore_nan* is true (default: ``False``), then out of range
240 :class:`float` values (``nan``, ``inf``, ``-inf``) will be serialized
241 as ``null`` in compliance with the ECMA-262 specification. If true,
242 this will override *allow_nan*.
243
244 """
245
246 self.skipkeys = skipkeys
247 self.ensure_ascii = ensure_ascii
248 self.check_circular = check_circular
249 self.allow_nan = allow_nan
250 self.sort_keys = sort_keys
251 self.use_decimal = use_decimal
252 self.namedtuple_as_object = namedtuple_as_object
253 self.tuple_as_array = tuple_as_array
254 self.iterable_as_array = iterable_as_array
255 self.bigint_as_string = bigint_as_string
256 self.item_sort_key = item_sort_key
257 self.for_json = for_json
258 self.ignore_nan = ignore_nan
259 self.int_as_string_bitcount = int_as_string_bitcount
260 if indent is not None and not isinstance(indent, string_types):
261 indent = indent * ' '
262 self.indent = indent
263 if separators is not None:
264 self.item_separator, self.key_separator = separators
265 elif indent is not None:
266 self.item_separator = ','
267 if default is not None:
268 self.default = default
269 self.encoding = encoding
270
271 def default(self, o):
272 """Implement this method in a subclass such that it returns
273 a serializable object for ``o``, or calls the base implementation
274 (to raise a ``TypeError``).
275
276 For example, to support arbitrary iterators, you could
277 implement default like this::
278
279 def default(self, o):
280 try:
281 iterable = iter(o)
282 except TypeError:
283 pass
284 else:
285 return list(iterable)
286 return JSONEncoder.default(self, o)
287
288 """
289 raise TypeError('Object of type %s is not JSON serializable' %
290 o.__class__.__name__)
291
292 def encode(self, o):
293 """Return a JSON string representation of a Python data structure.
294
295 >>> from simplejson import JSONEncoder
296 >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
297 '{"foo": ["bar", "baz"]}'
298
299 """
300 # This is for extremely simple cases and benchmarks.
301 if isinstance(o, binary_type):
302 _encoding = self.encoding
303 if (_encoding is not None and not (_encoding == 'utf-8')):
304 o = text_type(o, _encoding)
305 if isinstance(o, string_types):
306 if self.ensure_ascii:
307 return encode_basestring_ascii(o)
308 else:
309 return encode_basestring(o)
310 # This doesn't pass the iterator directly to ''.join() because the
311 # exceptions aren't as detailed. The list call should be roughly
312 # equivalent to the PySequence_Fast that ''.join() would do.
313 chunks = self.iterencode(o)
314 if not isinstance(chunks, (list, tuple)):
315 chunks = list(chunks)
316 if self.ensure_ascii:
317 return ''.join(chunks)
318 else:
319 return u''.join(chunks)
320
321 def iterencode(self, o):
322 """Encode the given object and yield each string
323 representation as available.
324
325 For example::
326
327 for chunk in JSONEncoder().iterencode(bigobject):
328 mysocket.write(chunk)
329
330 """
331 if self.check_circular:
332 markers = {}
333 else:
334 markers = None
335 if self.ensure_ascii:
336 _encoder = encode_basestring_ascii
337 else:
338 _encoder = encode_basestring
339 if self.encoding != 'utf-8' and self.encoding is not None:
340 def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
341 if isinstance(o, binary_type):
342 o = text_type(o, _encoding)
343 return _orig_encoder(o)
344
345 def floatstr(o, allow_nan=self.allow_nan, ignore_nan=self.ignore_nan,
346 _repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf):
347 # Check for specials. Note that this type of test is processor
348 # and/or platform-specific, so do tests which don't depend on
349 # the internals.
350
351 if o != o:
352 text = 'NaN'
353 elif o == _inf:
354 text = 'Infinity'
355 elif o == _neginf:
356 text = '-Infinity'
357 else:
358 if type(o) != float:
359 # See #118, do not trust custom str/repr
360 o = float(o)
361 return _repr(o)
362
363 if ignore_nan:
364 text = 'null'
365 elif not allow_nan:
366 raise ValueError(
367 "Out of range float values are not JSON compliant: " +
368 repr(o))
369
370 return text
371
372 key_memo = {}
373 int_as_string_bitcount = (
374 53 if self.bigint_as_string else self.int_as_string_bitcount)
375 if c_make_encoder is not None:
376 _iterencode = c_make_encoder(
377 markers, self.default, _encoder, self.indent,
378 self.key_separator, self.item_separator, self.sort_keys,
379 self.skipkeys, self.allow_nan, key_memo, self.use_decimal,
380 self.namedtuple_as_object, self.tuple_as_array,
381 int_as_string_bitcount,
382 self.item_sort_key, self.encoding, self.for_json,
383 self.ignore_nan, decimal.Decimal, self.iterable_as_array)
384 else:
385 _iterencode = _make_iterencode(
386 markers, self.default, _encoder, self.indent, floatstr,
387 self.key_separator, self.item_separator, self.sort_keys,
388 self.skipkeys, self.use_decimal,
389 self.namedtuple_as_object, self.tuple_as_array,
390 int_as_string_bitcount,
391 self.item_sort_key, self.encoding, self.for_json,
392 self.iterable_as_array, Decimal=decimal.Decimal)
393 try:
394 return _iterencode(o, 0)
395 finally:
396 key_memo.clear()
397
398
399class JSONEncoderForHTML(JSONEncoder):
400 """An encoder that produces JSON safe to embed in HTML.
401
402 To embed JSON content in, say, a script tag on a web page, the
403 characters &, < and > should be escaped. They cannot be escaped
404 with the usual entities (e.g. &) because they are not expanded
405 within <script> tags.
406
407 This class also escapes the line separator and paragraph separator
408 characters U+2028 and U+2029, irrespective of the ensure_ascii setting,
409 as these characters are not valid in JavaScript strings (see
410 http://timelessrepo.com/json-isnt-a-javascript-subset).
411 """
412
413 def encode(self, o):
414 # Override JSONEncoder.encode because it has hacks for
415 # performance that make things more complicated.
416 chunks = self.iterencode(o)
417 if self.ensure_ascii:
418 return ''.join(chunks)
419 else:
420 return u''.join(chunks)
421
422 def iterencode(self, o):
423 chunks = super(JSONEncoderForHTML, self).iterencode(o)
424 for chunk in chunks:
425 chunk = chunk.replace('&', '\\u0026')
426 chunk = chunk.replace('<', '\\u003c')
427 chunk = chunk.replace('>', '\\u003e')
428
429 if not self.ensure_ascii:
430 chunk = chunk.replace(u'\u2028', '\\u2028')
431 chunk = chunk.replace(u'\u2029', '\\u2029')
432
433 yield chunk
434
435
436def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
437 _key_separator, _item_separator, _sort_keys, _skipkeys,
438 _use_decimal, _namedtuple_as_object, _tuple_as_array,
439 _int_as_string_bitcount, _item_sort_key,
440 _encoding,_for_json,
441 _iterable_as_array,
442 ## HACK: hand-optimized bytecode; turn globals into locals
443 _PY3=PY3,
444 ValueError=ValueError,
445 string_types=string_types,
446 Decimal=None,
447 dict=dict,
448 _dict_types=_dict_types,
449 float=float,
450 id=id,
451 integer_types=integer_types,
452 isinstance=isinstance,
453 list=list,
454 str=str,
455 tuple=tuple,
456 iter=iter,
457 ):
458 if _use_decimal and Decimal is None:
459 Decimal = decimal.Decimal
460 if _item_sort_key and not callable(_item_sort_key):
461 raise TypeError("item_sort_key must be None or callable")
462 elif _sort_keys and not _item_sort_key:
463 _item_sort_key = itemgetter(0)
464
465 if (_int_as_string_bitcount is not None and
466 (_int_as_string_bitcount <= 0 or
467 not isinstance(_int_as_string_bitcount, integer_types))):
468 raise TypeError("int_as_string_bitcount must be a positive integer")
469
470 def call_method(obj, method_name):
471 method = getattr(obj, method_name, None)
472 if callable(method):
473 try:
474 return (method(),)
475 except TypeError:
476 pass
477 return None
478
479 def _encode_int(value):
480 skip_quoting = (
481 _int_as_string_bitcount is None
482 or
483 _int_as_string_bitcount < 1
484 )
485 if type(value) not in integer_types:
486 # See #118, do not trust custom str/repr
487 value = int(value)
488 if (
489 skip_quoting or
490 (-1 << _int_as_string_bitcount)
491 < value <
492 (1 << _int_as_string_bitcount)
493 ):
494 return str(value)
495 return '"' + str(value) + '"'
496
497 def _iterencode_list(lst, _current_indent_level):
498 if not lst:
499 yield '[]'
500 return
501 if markers is not None:
502 markerid = id(lst)
503 if markerid in markers:
504 raise ValueError("Circular reference detected")
505 markers[markerid] = lst
506 buf = '['
507 if _indent is not None:
508 _current_indent_level += 1
509 newline_indent = '\n' + (_indent * _current_indent_level)
510 separator = _item_separator + newline_indent
511 buf += newline_indent
512 else:
513 newline_indent = None
514 separator = _item_separator
515 first = True
516 for i, value in enumerate(lst):
517 if first:
518 first = False
519 else:
520 buf = separator
521 try:
522 if isinstance(value, string_types):
523 yield buf + _encoder(value)
524 elif _PY3 and isinstance(value, bytes) and _encoding is not None:
525 yield buf + _encoder(value)
526 elif isinstance(value, RawJSON):
527 yield buf + value.encoded_json
528 elif value is None:
529 yield buf + 'null'
530 elif value is True:
531 yield buf + 'true'
532 elif value is False:
533 yield buf + 'false'
534 elif isinstance(value, integer_types):
535 yield buf + _encode_int(value)
536 elif isinstance(value, float):
537 yield buf + _floatstr(value)
538 elif _use_decimal and isinstance(value, Decimal):
539 yield buf + str(value)
540 else:
541 yield buf
542 for_json = _for_json and call_method(value, 'for_json')
543 if for_json:
544 chunks = _iterencode(for_json[0], _current_indent_level)
545 else:
546 _asdict = _namedtuple_as_object and call_method(value, '_asdict')
547 if _asdict:
548 dct = _asdict[0]
549 if not isinstance(dct, dict):
550 raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
551 chunks = _iterencode_dict(dct,
552 _current_indent_level)
553 elif isinstance(value, list):
554 chunks = _iterencode_list(value, _current_indent_level)
555 elif _tuple_as_array and isinstance(value, tuple):
556 chunks = _iterencode_list(value, _current_indent_level)
557 elif isinstance(value, _dict_types):
558 chunks = _iterencode_dict(value, _current_indent_level)
559 else:
560 chunks = _iterencode(value, _current_indent_level)
561 for chunk in chunks:
562 yield chunk
563 except BaseException as exc:
564 if _HAS_ADD_NOTE:
565 exc.add_note(
566 'when serializing %s item %d'
567 % (type(lst).__name__, i))
568 raise
569 if first:
570 # iterable_as_array misses the fast path at the top
571 yield '[]'
572 else:
573 if newline_indent is not None:
574 _current_indent_level -= 1
575 yield '\n' + (_indent * _current_indent_level)
576 yield ']'
577 if markers is not None:
578 del markers[markerid]
579
580 def _stringify_key(key):
581 if isinstance(key, string_types): # pragma: no cover
582 pass
583 elif _PY3 and isinstance(key, bytes) and _encoding is not None:
584 key = str(key, _encoding)
585 elif isinstance(key, float):
586 key = _floatstr(key)
587 elif key is True:
588 key = 'true'
589 elif key is False:
590 key = 'false'
591 elif key is None:
592 key = 'null'
593 elif isinstance(key, integer_types):
594 if type(key) not in integer_types:
595 # See #118, do not trust custom str/repr
596 key = int(key)
597 key = str(key)
598 elif _use_decimal and isinstance(key, Decimal):
599 key = str(key)
600 elif _skipkeys:
601 key = None
602 else:
603 raise TypeError('keys must be str, int, float, bool or None, '
604 'not %s' % key.__class__.__name__)
605 return key
606
607 def _iterencode_dict(dct, _current_indent_level):
608 if not dct:
609 yield '{}'
610 return
611 if markers is not None:
612 markerid = id(dct)
613 if markerid in markers:
614 raise ValueError("Circular reference detected")
615 markers[markerid] = dct
616 yield '{'
617 if _indent is not None:
618 _current_indent_level += 1
619 newline_indent = '\n' + (_indent * _current_indent_level)
620 item_separator = _item_separator + newline_indent
621 yield newline_indent
622 else:
623 newline_indent = None
624 item_separator = _item_separator
625 first = True
626 if _PY3:
627 iteritems = dct.items()
628 else:
629 iteritems = dct.iteritems()
630 if _item_sort_key:
631 items = []
632 for k, v in dct.items():
633 if not isinstance(k, string_types):
634 k = _stringify_key(k)
635 if k is None:
636 continue
637 items.append((k, v))
638 items.sort(key=_item_sort_key)
639 else:
640 items = iteritems
641 for key, value in items:
642 if not (_item_sort_key or isinstance(key, string_types)):
643 key = _stringify_key(key)
644 if key is None:
645 # _skipkeys must be True
646 continue
647 if first:
648 first = False
649 else:
650 yield item_separator
651 yield _encoder(key)
652 yield _key_separator
653 try:
654 if isinstance(value, string_types):
655 yield _encoder(value)
656 elif _PY3 and isinstance(value, bytes) and _encoding is not None:
657 yield _encoder(value)
658 elif isinstance(value, RawJSON):
659 yield value.encoded_json
660 elif value is None:
661 yield 'null'
662 elif value is True:
663 yield 'true'
664 elif value is False:
665 yield 'false'
666 elif isinstance(value, integer_types):
667 yield _encode_int(value)
668 elif isinstance(value, float):
669 yield _floatstr(value)
670 elif _use_decimal and isinstance(value, Decimal):
671 yield str(value)
672 else:
673 for_json = _for_json and call_method(value, 'for_json')
674 if for_json:
675 chunks = _iterencode(for_json[0], _current_indent_level)
676 else:
677 _asdict = _namedtuple_as_object and call_method(value, '_asdict')
678 if _asdict:
679 dct = _asdict[0]
680 if not isinstance(dct, dict):
681 raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
682 chunks = _iterencode_dict(dct,
683 _current_indent_level)
684 elif isinstance(value, list):
685 chunks = _iterencode_list(value, _current_indent_level)
686 elif _tuple_as_array and isinstance(value, tuple):
687 chunks = _iterencode_list(value, _current_indent_level)
688 elif isinstance(value, _dict_types):
689 chunks = _iterencode_dict(value, _current_indent_level)
690 else:
691 chunks = _iterencode(value, _current_indent_level)
692 for chunk in chunks:
693 yield chunk
694 except BaseException as exc:
695 if _HAS_ADD_NOTE:
696 exc.add_note(
697 'when serializing %s item %r'
698 % (type(dct).__name__, key))
699 raise
700 if newline_indent is not None:
701 _current_indent_level -= 1
702 yield '\n' + (_indent * _current_indent_level)
703 yield '}'
704 if markers is not None:
705 del markers[markerid]
706
707 def _iterencode(o, _current_indent_level):
708 if isinstance(o, string_types):
709 yield _encoder(o)
710 elif _PY3 and isinstance(o, bytes) and _encoding is not None:
711 yield _encoder(o)
712 elif isinstance(o, RawJSON):
713 yield o.encoded_json
714 elif o is None:
715 yield 'null'
716 elif o is True:
717 yield 'true'
718 elif o is False:
719 yield 'false'
720 elif isinstance(o, integer_types):
721 yield _encode_int(o)
722 elif isinstance(o, float):
723 yield _floatstr(o)
724 else:
725 for_json = _for_json and call_method(o, 'for_json')
726 if for_json:
727 for chunk in _iterencode(for_json[0], _current_indent_level):
728 yield chunk
729 else:
730 _asdict = _namedtuple_as_object and call_method(o, '_asdict')
731 if _asdict:
732 dct = _asdict[0]
733 if not isinstance(dct, dict):
734 raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,))
735 for chunk in _iterencode_dict(dct, _current_indent_level):
736 yield chunk
737 elif isinstance(o, list):
738 for chunk in _iterencode_list(o, _current_indent_level):
739 yield chunk
740 elif (_tuple_as_array and isinstance(o, tuple)):
741 for chunk in _iterencode_list(o, _current_indent_level):
742 yield chunk
743 elif isinstance(o, _dict_types):
744 for chunk in _iterencode_dict(o, _current_indent_level):
745 yield chunk
746 elif _use_decimal and isinstance(o, Decimal):
747 yield str(o)
748 else:
749 while _iterable_as_array:
750 # Markers are not checked here because it is valid for
751 # an iterable to return self.
752 try:
753 o = iter(o)
754 except TypeError:
755 break
756 for chunk in _iterencode_list(o, _current_indent_level):
757 yield chunk
758 return
759 if markers is not None:
760 markerid = id(o)
761 if markerid in markers:
762 raise ValueError("Circular reference detected")
763 markers[markerid] = o
764 try:
765 o = _default(o)
766 for chunk in _iterencode(o, _current_indent_level):
767 yield chunk
768 except BaseException as exc:
769 if _HAS_ADD_NOTE:
770 exc.add_note(
771 'when serializing %s object'
772 % type(o).__name__)
773 raise
774 if markers is not None:
775 del markers[markerid]
776
777 return _iterencode