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