17db96d56Sopenharmony_ci"""Implementation of JSONEncoder 27db96d56Sopenharmony_ci""" 37db96d56Sopenharmony_ciimport re 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_citry: 67db96d56Sopenharmony_ci from _json import encode_basestring_ascii as c_encode_basestring_ascii 77db96d56Sopenharmony_ciexcept ImportError: 87db96d56Sopenharmony_ci c_encode_basestring_ascii = None 97db96d56Sopenharmony_citry: 107db96d56Sopenharmony_ci from _json import encode_basestring as c_encode_basestring 117db96d56Sopenharmony_ciexcept ImportError: 127db96d56Sopenharmony_ci c_encode_basestring = None 137db96d56Sopenharmony_citry: 147db96d56Sopenharmony_ci from _json import make_encoder as c_make_encoder 157db96d56Sopenharmony_ciexcept ImportError: 167db96d56Sopenharmony_ci c_make_encoder = None 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ciESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') 197db96d56Sopenharmony_ciESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') 207db96d56Sopenharmony_ciHAS_UTF8 = re.compile(b'[\x80-\xff]') 217db96d56Sopenharmony_ciESCAPE_DCT = { 227db96d56Sopenharmony_ci '\\': '\\\\', 237db96d56Sopenharmony_ci '"': '\\"', 247db96d56Sopenharmony_ci '\b': '\\b', 257db96d56Sopenharmony_ci '\f': '\\f', 267db96d56Sopenharmony_ci '\n': '\\n', 277db96d56Sopenharmony_ci '\r': '\\r', 287db96d56Sopenharmony_ci '\t': '\\t', 297db96d56Sopenharmony_ci} 307db96d56Sopenharmony_cifor i in range(0x20): 317db96d56Sopenharmony_ci ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) 327db96d56Sopenharmony_ci #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) 337db96d56Sopenharmony_cidel i 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ciINFINITY = float('inf') 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_cidef py_encode_basestring(s): 387db96d56Sopenharmony_ci """Return a JSON representation of a Python string 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ci """ 417db96d56Sopenharmony_ci def replace(match): 427db96d56Sopenharmony_ci return ESCAPE_DCT[match.group(0)] 437db96d56Sopenharmony_ci return '"' + ESCAPE.sub(replace, s) + '"' 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ciencode_basestring = (c_encode_basestring or py_encode_basestring) 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_cidef py_encode_basestring_ascii(s): 507db96d56Sopenharmony_ci """Return an ASCII-only JSON representation of a Python string 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci """ 537db96d56Sopenharmony_ci def replace(match): 547db96d56Sopenharmony_ci s = match.group(0) 557db96d56Sopenharmony_ci try: 567db96d56Sopenharmony_ci return ESCAPE_DCT[s] 577db96d56Sopenharmony_ci except KeyError: 587db96d56Sopenharmony_ci n = ord(s) 597db96d56Sopenharmony_ci if n < 0x10000: 607db96d56Sopenharmony_ci return '\\u{0:04x}'.format(n) 617db96d56Sopenharmony_ci #return '\\u%04x' % (n,) 627db96d56Sopenharmony_ci else: 637db96d56Sopenharmony_ci # surrogate pair 647db96d56Sopenharmony_ci n -= 0x10000 657db96d56Sopenharmony_ci s1 = 0xd800 | ((n >> 10) & 0x3ff) 667db96d56Sopenharmony_ci s2 = 0xdc00 | (n & 0x3ff) 677db96d56Sopenharmony_ci return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) 687db96d56Sopenharmony_ci return '"' + ESCAPE_ASCII.sub(replace, s) + '"' 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ciencode_basestring_ascii = ( 727db96d56Sopenharmony_ci c_encode_basestring_ascii or py_encode_basestring_ascii) 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ciclass JSONEncoder(object): 757db96d56Sopenharmony_ci """Extensible JSON <https://json.org> encoder for Python data structures. 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci Supports the following objects and types by default: 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci +-------------------+---------------+ 807db96d56Sopenharmony_ci | Python | JSON | 817db96d56Sopenharmony_ci +===================+===============+ 827db96d56Sopenharmony_ci | dict | object | 837db96d56Sopenharmony_ci +-------------------+---------------+ 847db96d56Sopenharmony_ci | list, tuple | array | 857db96d56Sopenharmony_ci +-------------------+---------------+ 867db96d56Sopenharmony_ci | str | string | 877db96d56Sopenharmony_ci +-------------------+---------------+ 887db96d56Sopenharmony_ci | int, float | number | 897db96d56Sopenharmony_ci +-------------------+---------------+ 907db96d56Sopenharmony_ci | True | true | 917db96d56Sopenharmony_ci +-------------------+---------------+ 927db96d56Sopenharmony_ci | False | false | 937db96d56Sopenharmony_ci +-------------------+---------------+ 947db96d56Sopenharmony_ci | None | null | 957db96d56Sopenharmony_ci +-------------------+---------------+ 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci To extend this to recognize other objects, subclass and implement a 987db96d56Sopenharmony_ci ``.default()`` method with another method that returns a serializable 997db96d56Sopenharmony_ci object for ``o`` if possible, otherwise it should call the superclass 1007db96d56Sopenharmony_ci implementation (to raise ``TypeError``). 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci """ 1037db96d56Sopenharmony_ci item_separator = ', ' 1047db96d56Sopenharmony_ci key_separator = ': ' 1057db96d56Sopenharmony_ci def __init__(self, *, skipkeys=False, ensure_ascii=True, 1067db96d56Sopenharmony_ci check_circular=True, allow_nan=True, sort_keys=False, 1077db96d56Sopenharmony_ci indent=None, separators=None, default=None): 1087db96d56Sopenharmony_ci """Constructor for JSONEncoder, with sensible defaults. 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_ci If skipkeys is false, then it is a TypeError to attempt 1117db96d56Sopenharmony_ci encoding of keys that are not str, int, float or None. If 1127db96d56Sopenharmony_ci skipkeys is True, such items are simply skipped. 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ci If ensure_ascii is true, the output is guaranteed to be str 1157db96d56Sopenharmony_ci objects with all incoming non-ASCII characters escaped. If 1167db96d56Sopenharmony_ci ensure_ascii is false, the output can contain non-ASCII characters. 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci If check_circular is true, then lists, dicts, and custom encoded 1197db96d56Sopenharmony_ci objects will be checked for circular references during encoding to 1207db96d56Sopenharmony_ci prevent an infinite recursion (which would cause an RecursionError). 1217db96d56Sopenharmony_ci Otherwise, no such check takes place. 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci If allow_nan is true, then NaN, Infinity, and -Infinity will be 1247db96d56Sopenharmony_ci encoded as such. This behavior is not JSON specification compliant, 1257db96d56Sopenharmony_ci but is consistent with most JavaScript based encoders and decoders. 1267db96d56Sopenharmony_ci Otherwise, it will be a ValueError to encode such floats. 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci If sort_keys is true, then the output of dictionaries will be 1297db96d56Sopenharmony_ci sorted by key; this is useful for regression tests to ensure 1307db96d56Sopenharmony_ci that JSON serializations can be compared on a day-to-day basis. 1317db96d56Sopenharmony_ci 1327db96d56Sopenharmony_ci If indent is a non-negative integer, then JSON array 1337db96d56Sopenharmony_ci elements and object members will be pretty-printed with that 1347db96d56Sopenharmony_ci indent level. An indent level of 0 will only insert newlines. 1357db96d56Sopenharmony_ci None is the most compact representation. 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci If specified, separators should be an (item_separator, key_separator) 1387db96d56Sopenharmony_ci tuple. The default is (', ', ': ') if *indent* is ``None`` and 1397db96d56Sopenharmony_ci (',', ': ') otherwise. To get the most compact JSON representation, 1407db96d56Sopenharmony_ci you should specify (',', ':') to eliminate whitespace. 1417db96d56Sopenharmony_ci 1427db96d56Sopenharmony_ci If specified, default is a function that gets called for objects 1437db96d56Sopenharmony_ci that can't otherwise be serialized. It should return a JSON encodable 1447db96d56Sopenharmony_ci version of the object or raise a ``TypeError``. 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci """ 1477db96d56Sopenharmony_ci 1487db96d56Sopenharmony_ci self.skipkeys = skipkeys 1497db96d56Sopenharmony_ci self.ensure_ascii = ensure_ascii 1507db96d56Sopenharmony_ci self.check_circular = check_circular 1517db96d56Sopenharmony_ci self.allow_nan = allow_nan 1527db96d56Sopenharmony_ci self.sort_keys = sort_keys 1537db96d56Sopenharmony_ci self.indent = indent 1547db96d56Sopenharmony_ci if separators is not None: 1557db96d56Sopenharmony_ci self.item_separator, self.key_separator = separators 1567db96d56Sopenharmony_ci elif indent is not None: 1577db96d56Sopenharmony_ci self.item_separator = ',' 1587db96d56Sopenharmony_ci if default is not None: 1597db96d56Sopenharmony_ci self.default = default 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ci def default(self, o): 1627db96d56Sopenharmony_ci """Implement this method in a subclass such that it returns 1637db96d56Sopenharmony_ci a serializable object for ``o``, or calls the base implementation 1647db96d56Sopenharmony_ci (to raise a ``TypeError``). 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci For example, to support arbitrary iterators, you could 1677db96d56Sopenharmony_ci implement default like this:: 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci def default(self, o): 1707db96d56Sopenharmony_ci try: 1717db96d56Sopenharmony_ci iterable = iter(o) 1727db96d56Sopenharmony_ci except TypeError: 1737db96d56Sopenharmony_ci pass 1747db96d56Sopenharmony_ci else: 1757db96d56Sopenharmony_ci return list(iterable) 1767db96d56Sopenharmony_ci # Let the base class default method raise the TypeError 1777db96d56Sopenharmony_ci return JSONEncoder.default(self, o) 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci """ 1807db96d56Sopenharmony_ci raise TypeError(f'Object of type {o.__class__.__name__} ' 1817db96d56Sopenharmony_ci f'is not JSON serializable') 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci def encode(self, o): 1847db96d56Sopenharmony_ci """Return a JSON string representation of a Python data structure. 1857db96d56Sopenharmony_ci 1867db96d56Sopenharmony_ci >>> from json.encoder import JSONEncoder 1877db96d56Sopenharmony_ci >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) 1887db96d56Sopenharmony_ci '{"foo": ["bar", "baz"]}' 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci """ 1917db96d56Sopenharmony_ci # This is for extremely simple cases and benchmarks. 1927db96d56Sopenharmony_ci if isinstance(o, str): 1937db96d56Sopenharmony_ci if self.ensure_ascii: 1947db96d56Sopenharmony_ci return encode_basestring_ascii(o) 1957db96d56Sopenharmony_ci else: 1967db96d56Sopenharmony_ci return encode_basestring(o) 1977db96d56Sopenharmony_ci # This doesn't pass the iterator directly to ''.join() because the 1987db96d56Sopenharmony_ci # exceptions aren't as detailed. The list call should be roughly 1997db96d56Sopenharmony_ci # equivalent to the PySequence_Fast that ''.join() would do. 2007db96d56Sopenharmony_ci chunks = self.iterencode(o, _one_shot=True) 2017db96d56Sopenharmony_ci if not isinstance(chunks, (list, tuple)): 2027db96d56Sopenharmony_ci chunks = list(chunks) 2037db96d56Sopenharmony_ci return ''.join(chunks) 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci def iterencode(self, o, _one_shot=False): 2067db96d56Sopenharmony_ci """Encode the given object and yield each string 2077db96d56Sopenharmony_ci representation as available. 2087db96d56Sopenharmony_ci 2097db96d56Sopenharmony_ci For example:: 2107db96d56Sopenharmony_ci 2117db96d56Sopenharmony_ci for chunk in JSONEncoder().iterencode(bigobject): 2127db96d56Sopenharmony_ci mysocket.write(chunk) 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci """ 2157db96d56Sopenharmony_ci if self.check_circular: 2167db96d56Sopenharmony_ci markers = {} 2177db96d56Sopenharmony_ci else: 2187db96d56Sopenharmony_ci markers = None 2197db96d56Sopenharmony_ci if self.ensure_ascii: 2207db96d56Sopenharmony_ci _encoder = encode_basestring_ascii 2217db96d56Sopenharmony_ci else: 2227db96d56Sopenharmony_ci _encoder = encode_basestring 2237db96d56Sopenharmony_ci 2247db96d56Sopenharmony_ci def floatstr(o, allow_nan=self.allow_nan, 2257db96d56Sopenharmony_ci _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY): 2267db96d56Sopenharmony_ci # Check for specials. Note that this type of test is processor 2277db96d56Sopenharmony_ci # and/or platform-specific, so do tests which don't depend on the 2287db96d56Sopenharmony_ci # internals. 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ci if o != o: 2317db96d56Sopenharmony_ci text = 'NaN' 2327db96d56Sopenharmony_ci elif o == _inf: 2337db96d56Sopenharmony_ci text = 'Infinity' 2347db96d56Sopenharmony_ci elif o == _neginf: 2357db96d56Sopenharmony_ci text = '-Infinity' 2367db96d56Sopenharmony_ci else: 2377db96d56Sopenharmony_ci return _repr(o) 2387db96d56Sopenharmony_ci 2397db96d56Sopenharmony_ci if not allow_nan: 2407db96d56Sopenharmony_ci raise ValueError( 2417db96d56Sopenharmony_ci "Out of range float values are not JSON compliant: " + 2427db96d56Sopenharmony_ci repr(o)) 2437db96d56Sopenharmony_ci 2447db96d56Sopenharmony_ci return text 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_ci if (_one_shot and c_make_encoder is not None 2487db96d56Sopenharmony_ci and self.indent is None): 2497db96d56Sopenharmony_ci _iterencode = c_make_encoder( 2507db96d56Sopenharmony_ci markers, self.default, _encoder, self.indent, 2517db96d56Sopenharmony_ci self.key_separator, self.item_separator, self.sort_keys, 2527db96d56Sopenharmony_ci self.skipkeys, self.allow_nan) 2537db96d56Sopenharmony_ci else: 2547db96d56Sopenharmony_ci _iterencode = _make_iterencode( 2557db96d56Sopenharmony_ci markers, self.default, _encoder, self.indent, floatstr, 2567db96d56Sopenharmony_ci self.key_separator, self.item_separator, self.sort_keys, 2577db96d56Sopenharmony_ci self.skipkeys, _one_shot) 2587db96d56Sopenharmony_ci return _iterencode(o, 0) 2597db96d56Sopenharmony_ci 2607db96d56Sopenharmony_cidef _make_iterencode(markers, _default, _encoder, _indent, _floatstr, 2617db96d56Sopenharmony_ci _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, 2627db96d56Sopenharmony_ci ## HACK: hand-optimized bytecode; turn globals into locals 2637db96d56Sopenharmony_ci ValueError=ValueError, 2647db96d56Sopenharmony_ci dict=dict, 2657db96d56Sopenharmony_ci float=float, 2667db96d56Sopenharmony_ci id=id, 2677db96d56Sopenharmony_ci int=int, 2687db96d56Sopenharmony_ci isinstance=isinstance, 2697db96d56Sopenharmony_ci list=list, 2707db96d56Sopenharmony_ci str=str, 2717db96d56Sopenharmony_ci tuple=tuple, 2727db96d56Sopenharmony_ci _intstr=int.__repr__, 2737db96d56Sopenharmony_ci ): 2747db96d56Sopenharmony_ci 2757db96d56Sopenharmony_ci if _indent is not None and not isinstance(_indent, str): 2767db96d56Sopenharmony_ci _indent = ' ' * _indent 2777db96d56Sopenharmony_ci 2787db96d56Sopenharmony_ci def _iterencode_list(lst, _current_indent_level): 2797db96d56Sopenharmony_ci if not lst: 2807db96d56Sopenharmony_ci yield '[]' 2817db96d56Sopenharmony_ci return 2827db96d56Sopenharmony_ci if markers is not None: 2837db96d56Sopenharmony_ci markerid = id(lst) 2847db96d56Sopenharmony_ci if markerid in markers: 2857db96d56Sopenharmony_ci raise ValueError("Circular reference detected") 2867db96d56Sopenharmony_ci markers[markerid] = lst 2877db96d56Sopenharmony_ci buf = '[' 2887db96d56Sopenharmony_ci if _indent is not None: 2897db96d56Sopenharmony_ci _current_indent_level += 1 2907db96d56Sopenharmony_ci newline_indent = '\n' + _indent * _current_indent_level 2917db96d56Sopenharmony_ci separator = _item_separator + newline_indent 2927db96d56Sopenharmony_ci buf += newline_indent 2937db96d56Sopenharmony_ci else: 2947db96d56Sopenharmony_ci newline_indent = None 2957db96d56Sopenharmony_ci separator = _item_separator 2967db96d56Sopenharmony_ci first = True 2977db96d56Sopenharmony_ci for value in lst: 2987db96d56Sopenharmony_ci if first: 2997db96d56Sopenharmony_ci first = False 3007db96d56Sopenharmony_ci else: 3017db96d56Sopenharmony_ci buf = separator 3027db96d56Sopenharmony_ci if isinstance(value, str): 3037db96d56Sopenharmony_ci yield buf + _encoder(value) 3047db96d56Sopenharmony_ci elif value is None: 3057db96d56Sopenharmony_ci yield buf + 'null' 3067db96d56Sopenharmony_ci elif value is True: 3077db96d56Sopenharmony_ci yield buf + 'true' 3087db96d56Sopenharmony_ci elif value is False: 3097db96d56Sopenharmony_ci yield buf + 'false' 3107db96d56Sopenharmony_ci elif isinstance(value, int): 3117db96d56Sopenharmony_ci # Subclasses of int/float may override __repr__, but we still 3127db96d56Sopenharmony_ci # want to encode them as integers/floats in JSON. One example 3137db96d56Sopenharmony_ci # within the standard library is IntEnum. 3147db96d56Sopenharmony_ci yield buf + _intstr(value) 3157db96d56Sopenharmony_ci elif isinstance(value, float): 3167db96d56Sopenharmony_ci # see comment above for int 3177db96d56Sopenharmony_ci yield buf + _floatstr(value) 3187db96d56Sopenharmony_ci else: 3197db96d56Sopenharmony_ci yield buf 3207db96d56Sopenharmony_ci if isinstance(value, (list, tuple)): 3217db96d56Sopenharmony_ci chunks = _iterencode_list(value, _current_indent_level) 3227db96d56Sopenharmony_ci elif isinstance(value, dict): 3237db96d56Sopenharmony_ci chunks = _iterencode_dict(value, _current_indent_level) 3247db96d56Sopenharmony_ci else: 3257db96d56Sopenharmony_ci chunks = _iterencode(value, _current_indent_level) 3267db96d56Sopenharmony_ci yield from chunks 3277db96d56Sopenharmony_ci if newline_indent is not None: 3287db96d56Sopenharmony_ci _current_indent_level -= 1 3297db96d56Sopenharmony_ci yield '\n' + _indent * _current_indent_level 3307db96d56Sopenharmony_ci yield ']' 3317db96d56Sopenharmony_ci if markers is not None: 3327db96d56Sopenharmony_ci del markers[markerid] 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci def _iterencode_dict(dct, _current_indent_level): 3357db96d56Sopenharmony_ci if not dct: 3367db96d56Sopenharmony_ci yield '{}' 3377db96d56Sopenharmony_ci return 3387db96d56Sopenharmony_ci if markers is not None: 3397db96d56Sopenharmony_ci markerid = id(dct) 3407db96d56Sopenharmony_ci if markerid in markers: 3417db96d56Sopenharmony_ci raise ValueError("Circular reference detected") 3427db96d56Sopenharmony_ci markers[markerid] = dct 3437db96d56Sopenharmony_ci yield '{' 3447db96d56Sopenharmony_ci if _indent is not None: 3457db96d56Sopenharmony_ci _current_indent_level += 1 3467db96d56Sopenharmony_ci newline_indent = '\n' + _indent * _current_indent_level 3477db96d56Sopenharmony_ci item_separator = _item_separator + newline_indent 3487db96d56Sopenharmony_ci yield newline_indent 3497db96d56Sopenharmony_ci else: 3507db96d56Sopenharmony_ci newline_indent = None 3517db96d56Sopenharmony_ci item_separator = _item_separator 3527db96d56Sopenharmony_ci first = True 3537db96d56Sopenharmony_ci if _sort_keys: 3547db96d56Sopenharmony_ci items = sorted(dct.items()) 3557db96d56Sopenharmony_ci else: 3567db96d56Sopenharmony_ci items = dct.items() 3577db96d56Sopenharmony_ci for key, value in items: 3587db96d56Sopenharmony_ci if isinstance(key, str): 3597db96d56Sopenharmony_ci pass 3607db96d56Sopenharmony_ci # JavaScript is weakly typed for these, so it makes sense to 3617db96d56Sopenharmony_ci # also allow them. Many encoders seem to do something like this. 3627db96d56Sopenharmony_ci elif isinstance(key, float): 3637db96d56Sopenharmony_ci # see comment for int/float in _make_iterencode 3647db96d56Sopenharmony_ci key = _floatstr(key) 3657db96d56Sopenharmony_ci elif key is True: 3667db96d56Sopenharmony_ci key = 'true' 3677db96d56Sopenharmony_ci elif key is False: 3687db96d56Sopenharmony_ci key = 'false' 3697db96d56Sopenharmony_ci elif key is None: 3707db96d56Sopenharmony_ci key = 'null' 3717db96d56Sopenharmony_ci elif isinstance(key, int): 3727db96d56Sopenharmony_ci # see comment for int/float in _make_iterencode 3737db96d56Sopenharmony_ci key = _intstr(key) 3747db96d56Sopenharmony_ci elif _skipkeys: 3757db96d56Sopenharmony_ci continue 3767db96d56Sopenharmony_ci else: 3777db96d56Sopenharmony_ci raise TypeError(f'keys must be str, int, float, bool or None, ' 3787db96d56Sopenharmony_ci f'not {key.__class__.__name__}') 3797db96d56Sopenharmony_ci if first: 3807db96d56Sopenharmony_ci first = False 3817db96d56Sopenharmony_ci else: 3827db96d56Sopenharmony_ci yield item_separator 3837db96d56Sopenharmony_ci yield _encoder(key) 3847db96d56Sopenharmony_ci yield _key_separator 3857db96d56Sopenharmony_ci if isinstance(value, str): 3867db96d56Sopenharmony_ci yield _encoder(value) 3877db96d56Sopenharmony_ci elif value is None: 3887db96d56Sopenharmony_ci yield 'null' 3897db96d56Sopenharmony_ci elif value is True: 3907db96d56Sopenharmony_ci yield 'true' 3917db96d56Sopenharmony_ci elif value is False: 3927db96d56Sopenharmony_ci yield 'false' 3937db96d56Sopenharmony_ci elif isinstance(value, int): 3947db96d56Sopenharmony_ci # see comment for int/float in _make_iterencode 3957db96d56Sopenharmony_ci yield _intstr(value) 3967db96d56Sopenharmony_ci elif isinstance(value, float): 3977db96d56Sopenharmony_ci # see comment for int/float in _make_iterencode 3987db96d56Sopenharmony_ci yield _floatstr(value) 3997db96d56Sopenharmony_ci else: 4007db96d56Sopenharmony_ci if isinstance(value, (list, tuple)): 4017db96d56Sopenharmony_ci chunks = _iterencode_list(value, _current_indent_level) 4027db96d56Sopenharmony_ci elif isinstance(value, dict): 4037db96d56Sopenharmony_ci chunks = _iterencode_dict(value, _current_indent_level) 4047db96d56Sopenharmony_ci else: 4057db96d56Sopenharmony_ci chunks = _iterencode(value, _current_indent_level) 4067db96d56Sopenharmony_ci yield from chunks 4077db96d56Sopenharmony_ci if newline_indent is not None: 4087db96d56Sopenharmony_ci _current_indent_level -= 1 4097db96d56Sopenharmony_ci yield '\n' + _indent * _current_indent_level 4107db96d56Sopenharmony_ci yield '}' 4117db96d56Sopenharmony_ci if markers is not None: 4127db96d56Sopenharmony_ci del markers[markerid] 4137db96d56Sopenharmony_ci 4147db96d56Sopenharmony_ci def _iterencode(o, _current_indent_level): 4157db96d56Sopenharmony_ci if isinstance(o, str): 4167db96d56Sopenharmony_ci yield _encoder(o) 4177db96d56Sopenharmony_ci elif o is None: 4187db96d56Sopenharmony_ci yield 'null' 4197db96d56Sopenharmony_ci elif o is True: 4207db96d56Sopenharmony_ci yield 'true' 4217db96d56Sopenharmony_ci elif o is False: 4227db96d56Sopenharmony_ci yield 'false' 4237db96d56Sopenharmony_ci elif isinstance(o, int): 4247db96d56Sopenharmony_ci # see comment for int/float in _make_iterencode 4257db96d56Sopenharmony_ci yield _intstr(o) 4267db96d56Sopenharmony_ci elif isinstance(o, float): 4277db96d56Sopenharmony_ci # see comment for int/float in _make_iterencode 4287db96d56Sopenharmony_ci yield _floatstr(o) 4297db96d56Sopenharmony_ci elif isinstance(o, (list, tuple)): 4307db96d56Sopenharmony_ci yield from _iterencode_list(o, _current_indent_level) 4317db96d56Sopenharmony_ci elif isinstance(o, dict): 4327db96d56Sopenharmony_ci yield from _iterencode_dict(o, _current_indent_level) 4337db96d56Sopenharmony_ci else: 4347db96d56Sopenharmony_ci if markers is not None: 4357db96d56Sopenharmony_ci markerid = id(o) 4367db96d56Sopenharmony_ci if markerid in markers: 4377db96d56Sopenharmony_ci raise ValueError("Circular reference detected") 4387db96d56Sopenharmony_ci markers[markerid] = o 4397db96d56Sopenharmony_ci o = _default(o) 4407db96d56Sopenharmony_ci yield from _iterencode(o, _current_indent_level) 4417db96d56Sopenharmony_ci if markers is not None: 4427db96d56Sopenharmony_ci del markers[markerid] 4437db96d56Sopenharmony_ci return _iterencode 444