1*cda5da8dSAndroid Build Coastguard Worker"""Implementation of JSONEncoder 2*cda5da8dSAndroid Build Coastguard Worker""" 3*cda5da8dSAndroid Build Coastguard Workerimport re 4*cda5da8dSAndroid Build Coastguard Worker 5*cda5da8dSAndroid Build Coastguard Workertry: 6*cda5da8dSAndroid Build Coastguard Worker from _json import encode_basestring_ascii as c_encode_basestring_ascii 7*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 8*cda5da8dSAndroid Build Coastguard Worker c_encode_basestring_ascii = None 9*cda5da8dSAndroid Build Coastguard Workertry: 10*cda5da8dSAndroid Build Coastguard Worker from _json import encode_basestring as c_encode_basestring 11*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 12*cda5da8dSAndroid Build Coastguard Worker c_encode_basestring = None 13*cda5da8dSAndroid Build Coastguard Workertry: 14*cda5da8dSAndroid Build Coastguard Worker from _json import make_encoder as c_make_encoder 15*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 16*cda5da8dSAndroid Build Coastguard Worker c_make_encoder = None 17*cda5da8dSAndroid Build Coastguard Worker 18*cda5da8dSAndroid Build Coastguard WorkerESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') 19*cda5da8dSAndroid Build Coastguard WorkerESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') 20*cda5da8dSAndroid Build Coastguard WorkerHAS_UTF8 = re.compile(b'[\x80-\xff]') 21*cda5da8dSAndroid Build Coastguard WorkerESCAPE_DCT = { 22*cda5da8dSAndroid Build Coastguard Worker '\\': '\\\\', 23*cda5da8dSAndroid Build Coastguard Worker '"': '\\"', 24*cda5da8dSAndroid Build Coastguard Worker '\b': '\\b', 25*cda5da8dSAndroid Build Coastguard Worker '\f': '\\f', 26*cda5da8dSAndroid Build Coastguard Worker '\n': '\\n', 27*cda5da8dSAndroid Build Coastguard Worker '\r': '\\r', 28*cda5da8dSAndroid Build Coastguard Worker '\t': '\\t', 29*cda5da8dSAndroid Build Coastguard Worker} 30*cda5da8dSAndroid Build Coastguard Workerfor i in range(0x20): 31*cda5da8dSAndroid Build Coastguard Worker ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) 32*cda5da8dSAndroid Build Coastguard Worker #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) 33*cda5da8dSAndroid Build Coastguard Workerdel i 34*cda5da8dSAndroid Build Coastguard Worker 35*cda5da8dSAndroid Build Coastguard WorkerINFINITY = float('inf') 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Workerdef py_encode_basestring(s): 38*cda5da8dSAndroid Build Coastguard Worker """Return a JSON representation of a Python string 39*cda5da8dSAndroid Build Coastguard Worker 40*cda5da8dSAndroid Build Coastguard Worker """ 41*cda5da8dSAndroid Build Coastguard Worker def replace(match): 42*cda5da8dSAndroid Build Coastguard Worker return ESCAPE_DCT[match.group(0)] 43*cda5da8dSAndroid Build Coastguard Worker return '"' + ESCAPE.sub(replace, s) + '"' 44*cda5da8dSAndroid Build Coastguard Worker 45*cda5da8dSAndroid Build Coastguard Worker 46*cda5da8dSAndroid Build Coastguard Workerencode_basestring = (c_encode_basestring or py_encode_basestring) 47*cda5da8dSAndroid Build Coastguard Worker 48*cda5da8dSAndroid Build Coastguard Worker 49*cda5da8dSAndroid Build Coastguard Workerdef py_encode_basestring_ascii(s): 50*cda5da8dSAndroid Build Coastguard Worker """Return an ASCII-only JSON representation of a Python string 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker """ 53*cda5da8dSAndroid Build Coastguard Worker def replace(match): 54*cda5da8dSAndroid Build Coastguard Worker s = match.group(0) 55*cda5da8dSAndroid Build Coastguard Worker try: 56*cda5da8dSAndroid Build Coastguard Worker return ESCAPE_DCT[s] 57*cda5da8dSAndroid Build Coastguard Worker except KeyError: 58*cda5da8dSAndroid Build Coastguard Worker n = ord(s) 59*cda5da8dSAndroid Build Coastguard Worker if n < 0x10000: 60*cda5da8dSAndroid Build Coastguard Worker return '\\u{0:04x}'.format(n) 61*cda5da8dSAndroid Build Coastguard Worker #return '\\u%04x' % (n,) 62*cda5da8dSAndroid Build Coastguard Worker else: 63*cda5da8dSAndroid Build Coastguard Worker # surrogate pair 64*cda5da8dSAndroid Build Coastguard Worker n -= 0x10000 65*cda5da8dSAndroid Build Coastguard Worker s1 = 0xd800 | ((n >> 10) & 0x3ff) 66*cda5da8dSAndroid Build Coastguard Worker s2 = 0xdc00 | (n & 0x3ff) 67*cda5da8dSAndroid Build Coastguard Worker return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) 68*cda5da8dSAndroid Build Coastguard Worker return '"' + ESCAPE_ASCII.sub(replace, s) + '"' 69*cda5da8dSAndroid Build Coastguard Worker 70*cda5da8dSAndroid Build Coastguard Worker 71*cda5da8dSAndroid Build Coastguard Workerencode_basestring_ascii = ( 72*cda5da8dSAndroid Build Coastguard Worker c_encode_basestring_ascii or py_encode_basestring_ascii) 73*cda5da8dSAndroid Build Coastguard Worker 74*cda5da8dSAndroid Build Coastguard Workerclass JSONEncoder(object): 75*cda5da8dSAndroid Build Coastguard Worker """Extensible JSON <https://json.org> encoder for Python data structures. 76*cda5da8dSAndroid Build Coastguard Worker 77*cda5da8dSAndroid Build Coastguard Worker Supports the following objects and types by default: 78*cda5da8dSAndroid Build Coastguard Worker 79*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 80*cda5da8dSAndroid Build Coastguard Worker | Python | JSON | 81*cda5da8dSAndroid Build Coastguard Worker +===================+===============+ 82*cda5da8dSAndroid Build Coastguard Worker | dict | object | 83*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 84*cda5da8dSAndroid Build Coastguard Worker | list, tuple | array | 85*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 86*cda5da8dSAndroid Build Coastguard Worker | str | string | 87*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 88*cda5da8dSAndroid Build Coastguard Worker | int, float | number | 89*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 90*cda5da8dSAndroid Build Coastguard Worker | True | true | 91*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 92*cda5da8dSAndroid Build Coastguard Worker | False | false | 93*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 94*cda5da8dSAndroid Build Coastguard Worker | None | null | 95*cda5da8dSAndroid Build Coastguard Worker +-------------------+---------------+ 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker To extend this to recognize other objects, subclass and implement a 98*cda5da8dSAndroid Build Coastguard Worker ``.default()`` method with another method that returns a serializable 99*cda5da8dSAndroid Build Coastguard Worker object for ``o`` if possible, otherwise it should call the superclass 100*cda5da8dSAndroid Build Coastguard Worker implementation (to raise ``TypeError``). 101*cda5da8dSAndroid Build Coastguard Worker 102*cda5da8dSAndroid Build Coastguard Worker """ 103*cda5da8dSAndroid Build Coastguard Worker item_separator = ', ' 104*cda5da8dSAndroid Build Coastguard Worker key_separator = ': ' 105*cda5da8dSAndroid Build Coastguard Worker def __init__(self, *, skipkeys=False, ensure_ascii=True, 106*cda5da8dSAndroid Build Coastguard Worker check_circular=True, allow_nan=True, sort_keys=False, 107*cda5da8dSAndroid Build Coastguard Worker indent=None, separators=None, default=None): 108*cda5da8dSAndroid Build Coastguard Worker """Constructor for JSONEncoder, with sensible defaults. 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Worker If skipkeys is false, then it is a TypeError to attempt 111*cda5da8dSAndroid Build Coastguard Worker encoding of keys that are not str, int, float or None. If 112*cda5da8dSAndroid Build Coastguard Worker skipkeys is True, such items are simply skipped. 113*cda5da8dSAndroid Build Coastguard Worker 114*cda5da8dSAndroid Build Coastguard Worker If ensure_ascii is true, the output is guaranteed to be str 115*cda5da8dSAndroid Build Coastguard Worker objects with all incoming non-ASCII characters escaped. If 116*cda5da8dSAndroid Build Coastguard Worker ensure_ascii is false, the output can contain non-ASCII characters. 117*cda5da8dSAndroid Build Coastguard Worker 118*cda5da8dSAndroid Build Coastguard Worker If check_circular is true, then lists, dicts, and custom encoded 119*cda5da8dSAndroid Build Coastguard Worker objects will be checked for circular references during encoding to 120*cda5da8dSAndroid Build Coastguard Worker prevent an infinite recursion (which would cause an RecursionError). 121*cda5da8dSAndroid Build Coastguard Worker Otherwise, no such check takes place. 122*cda5da8dSAndroid Build Coastguard Worker 123*cda5da8dSAndroid Build Coastguard Worker If allow_nan is true, then NaN, Infinity, and -Infinity will be 124*cda5da8dSAndroid Build Coastguard Worker encoded as such. This behavior is not JSON specification compliant, 125*cda5da8dSAndroid Build Coastguard Worker but is consistent with most JavaScript based encoders and decoders. 126*cda5da8dSAndroid Build Coastguard Worker Otherwise, it will be a ValueError to encode such floats. 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker If sort_keys is true, then the output of dictionaries will be 129*cda5da8dSAndroid Build Coastguard Worker sorted by key; this is useful for regression tests to ensure 130*cda5da8dSAndroid Build Coastguard Worker that JSON serializations can be compared on a day-to-day basis. 131*cda5da8dSAndroid Build Coastguard Worker 132*cda5da8dSAndroid Build Coastguard Worker If indent is a non-negative integer, then JSON array 133*cda5da8dSAndroid Build Coastguard Worker elements and object members will be pretty-printed with that 134*cda5da8dSAndroid Build Coastguard Worker indent level. An indent level of 0 will only insert newlines. 135*cda5da8dSAndroid Build Coastguard Worker None is the most compact representation. 136*cda5da8dSAndroid Build Coastguard Worker 137*cda5da8dSAndroid Build Coastguard Worker If specified, separators should be an (item_separator, key_separator) 138*cda5da8dSAndroid Build Coastguard Worker tuple. The default is (', ', ': ') if *indent* is ``None`` and 139*cda5da8dSAndroid Build Coastguard Worker (',', ': ') otherwise. To get the most compact JSON representation, 140*cda5da8dSAndroid Build Coastguard Worker you should specify (',', ':') to eliminate whitespace. 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Worker If specified, default is a function that gets called for objects 143*cda5da8dSAndroid Build Coastguard Worker that can't otherwise be serialized. It should return a JSON encodable 144*cda5da8dSAndroid Build Coastguard Worker version of the object or raise a ``TypeError``. 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker """ 147*cda5da8dSAndroid Build Coastguard Worker 148*cda5da8dSAndroid Build Coastguard Worker self.skipkeys = skipkeys 149*cda5da8dSAndroid Build Coastguard Worker self.ensure_ascii = ensure_ascii 150*cda5da8dSAndroid Build Coastguard Worker self.check_circular = check_circular 151*cda5da8dSAndroid Build Coastguard Worker self.allow_nan = allow_nan 152*cda5da8dSAndroid Build Coastguard Worker self.sort_keys = sort_keys 153*cda5da8dSAndroid Build Coastguard Worker self.indent = indent 154*cda5da8dSAndroid Build Coastguard Worker if separators is not None: 155*cda5da8dSAndroid Build Coastguard Worker self.item_separator, self.key_separator = separators 156*cda5da8dSAndroid Build Coastguard Worker elif indent is not None: 157*cda5da8dSAndroid Build Coastguard Worker self.item_separator = ',' 158*cda5da8dSAndroid Build Coastguard Worker if default is not None: 159*cda5da8dSAndroid Build Coastguard Worker self.default = default 160*cda5da8dSAndroid Build Coastguard Worker 161*cda5da8dSAndroid Build Coastguard Worker def default(self, o): 162*cda5da8dSAndroid Build Coastguard Worker """Implement this method in a subclass such that it returns 163*cda5da8dSAndroid Build Coastguard Worker a serializable object for ``o``, or calls the base implementation 164*cda5da8dSAndroid Build Coastguard Worker (to raise a ``TypeError``). 165*cda5da8dSAndroid Build Coastguard Worker 166*cda5da8dSAndroid Build Coastguard Worker For example, to support arbitrary iterators, you could 167*cda5da8dSAndroid Build Coastguard Worker implement default like this:: 168*cda5da8dSAndroid Build Coastguard Worker 169*cda5da8dSAndroid Build Coastguard Worker def default(self, o): 170*cda5da8dSAndroid Build Coastguard Worker try: 171*cda5da8dSAndroid Build Coastguard Worker iterable = iter(o) 172*cda5da8dSAndroid Build Coastguard Worker except TypeError: 173*cda5da8dSAndroid Build Coastguard Worker pass 174*cda5da8dSAndroid Build Coastguard Worker else: 175*cda5da8dSAndroid Build Coastguard Worker return list(iterable) 176*cda5da8dSAndroid Build Coastguard Worker # Let the base class default method raise the TypeError 177*cda5da8dSAndroid Build Coastguard Worker return JSONEncoder.default(self, o) 178*cda5da8dSAndroid Build Coastguard Worker 179*cda5da8dSAndroid Build Coastguard Worker """ 180*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'Object of type {o.__class__.__name__} ' 181*cda5da8dSAndroid Build Coastguard Worker f'is not JSON serializable') 182*cda5da8dSAndroid Build Coastguard Worker 183*cda5da8dSAndroid Build Coastguard Worker def encode(self, o): 184*cda5da8dSAndroid Build Coastguard Worker """Return a JSON string representation of a Python data structure. 185*cda5da8dSAndroid Build Coastguard Worker 186*cda5da8dSAndroid Build Coastguard Worker >>> from json.encoder import JSONEncoder 187*cda5da8dSAndroid Build Coastguard Worker >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) 188*cda5da8dSAndroid Build Coastguard Worker '{"foo": ["bar", "baz"]}' 189*cda5da8dSAndroid Build Coastguard Worker 190*cda5da8dSAndroid Build Coastguard Worker """ 191*cda5da8dSAndroid Build Coastguard Worker # This is for extremely simple cases and benchmarks. 192*cda5da8dSAndroid Build Coastguard Worker if isinstance(o, str): 193*cda5da8dSAndroid Build Coastguard Worker if self.ensure_ascii: 194*cda5da8dSAndroid Build Coastguard Worker return encode_basestring_ascii(o) 195*cda5da8dSAndroid Build Coastguard Worker else: 196*cda5da8dSAndroid Build Coastguard Worker return encode_basestring(o) 197*cda5da8dSAndroid Build Coastguard Worker # This doesn't pass the iterator directly to ''.join() because the 198*cda5da8dSAndroid Build Coastguard Worker # exceptions aren't as detailed. The list call should be roughly 199*cda5da8dSAndroid Build Coastguard Worker # equivalent to the PySequence_Fast that ''.join() would do. 200*cda5da8dSAndroid Build Coastguard Worker chunks = self.iterencode(o, _one_shot=True) 201*cda5da8dSAndroid Build Coastguard Worker if not isinstance(chunks, (list, tuple)): 202*cda5da8dSAndroid Build Coastguard Worker chunks = list(chunks) 203*cda5da8dSAndroid Build Coastguard Worker return ''.join(chunks) 204*cda5da8dSAndroid Build Coastguard Worker 205*cda5da8dSAndroid Build Coastguard Worker def iterencode(self, o, _one_shot=False): 206*cda5da8dSAndroid Build Coastguard Worker """Encode the given object and yield each string 207*cda5da8dSAndroid Build Coastguard Worker representation as available. 208*cda5da8dSAndroid Build Coastguard Worker 209*cda5da8dSAndroid Build Coastguard Worker For example:: 210*cda5da8dSAndroid Build Coastguard Worker 211*cda5da8dSAndroid Build Coastguard Worker for chunk in JSONEncoder().iterencode(bigobject): 212*cda5da8dSAndroid Build Coastguard Worker mysocket.write(chunk) 213*cda5da8dSAndroid Build Coastguard Worker 214*cda5da8dSAndroid Build Coastguard Worker """ 215*cda5da8dSAndroid Build Coastguard Worker if self.check_circular: 216*cda5da8dSAndroid Build Coastguard Worker markers = {} 217*cda5da8dSAndroid Build Coastguard Worker else: 218*cda5da8dSAndroid Build Coastguard Worker markers = None 219*cda5da8dSAndroid Build Coastguard Worker if self.ensure_ascii: 220*cda5da8dSAndroid Build Coastguard Worker _encoder = encode_basestring_ascii 221*cda5da8dSAndroid Build Coastguard Worker else: 222*cda5da8dSAndroid Build Coastguard Worker _encoder = encode_basestring 223*cda5da8dSAndroid Build Coastguard Worker 224*cda5da8dSAndroid Build Coastguard Worker def floatstr(o, allow_nan=self.allow_nan, 225*cda5da8dSAndroid Build Coastguard Worker _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY): 226*cda5da8dSAndroid Build Coastguard Worker # Check for specials. Note that this type of test is processor 227*cda5da8dSAndroid Build Coastguard Worker # and/or platform-specific, so do tests which don't depend on the 228*cda5da8dSAndroid Build Coastguard Worker # internals. 229*cda5da8dSAndroid Build Coastguard Worker 230*cda5da8dSAndroid Build Coastguard Worker if o != o: 231*cda5da8dSAndroid Build Coastguard Worker text = 'NaN' 232*cda5da8dSAndroid Build Coastguard Worker elif o == _inf: 233*cda5da8dSAndroid Build Coastguard Worker text = 'Infinity' 234*cda5da8dSAndroid Build Coastguard Worker elif o == _neginf: 235*cda5da8dSAndroid Build Coastguard Worker text = '-Infinity' 236*cda5da8dSAndroid Build Coastguard Worker else: 237*cda5da8dSAndroid Build Coastguard Worker return _repr(o) 238*cda5da8dSAndroid Build Coastguard Worker 239*cda5da8dSAndroid Build Coastguard Worker if not allow_nan: 240*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 241*cda5da8dSAndroid Build Coastguard Worker "Out of range float values are not JSON compliant: " + 242*cda5da8dSAndroid Build Coastguard Worker repr(o)) 243*cda5da8dSAndroid Build Coastguard Worker 244*cda5da8dSAndroid Build Coastguard Worker return text 245*cda5da8dSAndroid Build Coastguard Worker 246*cda5da8dSAndroid Build Coastguard Worker 247*cda5da8dSAndroid Build Coastguard Worker if (_one_shot and c_make_encoder is not None 248*cda5da8dSAndroid Build Coastguard Worker and self.indent is None): 249*cda5da8dSAndroid Build Coastguard Worker _iterencode = c_make_encoder( 250*cda5da8dSAndroid Build Coastguard Worker markers, self.default, _encoder, self.indent, 251*cda5da8dSAndroid Build Coastguard Worker self.key_separator, self.item_separator, self.sort_keys, 252*cda5da8dSAndroid Build Coastguard Worker self.skipkeys, self.allow_nan) 253*cda5da8dSAndroid Build Coastguard Worker else: 254*cda5da8dSAndroid Build Coastguard Worker _iterencode = _make_iterencode( 255*cda5da8dSAndroid Build Coastguard Worker markers, self.default, _encoder, self.indent, floatstr, 256*cda5da8dSAndroid Build Coastguard Worker self.key_separator, self.item_separator, self.sort_keys, 257*cda5da8dSAndroid Build Coastguard Worker self.skipkeys, _one_shot) 258*cda5da8dSAndroid Build Coastguard Worker return _iterencode(o, 0) 259*cda5da8dSAndroid Build Coastguard Worker 260*cda5da8dSAndroid Build Coastguard Workerdef _make_iterencode(markers, _default, _encoder, _indent, _floatstr, 261*cda5da8dSAndroid Build Coastguard Worker _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, 262*cda5da8dSAndroid Build Coastguard Worker ## HACK: hand-optimized bytecode; turn globals into locals 263*cda5da8dSAndroid Build Coastguard Worker ValueError=ValueError, 264*cda5da8dSAndroid Build Coastguard Worker dict=dict, 265*cda5da8dSAndroid Build Coastguard Worker float=float, 266*cda5da8dSAndroid Build Coastguard Worker id=id, 267*cda5da8dSAndroid Build Coastguard Worker int=int, 268*cda5da8dSAndroid Build Coastguard Worker isinstance=isinstance, 269*cda5da8dSAndroid Build Coastguard Worker list=list, 270*cda5da8dSAndroid Build Coastguard Worker str=str, 271*cda5da8dSAndroid Build Coastguard Worker tuple=tuple, 272*cda5da8dSAndroid Build Coastguard Worker _intstr=int.__repr__, 273*cda5da8dSAndroid Build Coastguard Worker ): 274*cda5da8dSAndroid Build Coastguard Worker 275*cda5da8dSAndroid Build Coastguard Worker if _indent is not None and not isinstance(_indent, str): 276*cda5da8dSAndroid Build Coastguard Worker _indent = ' ' * _indent 277*cda5da8dSAndroid Build Coastguard Worker 278*cda5da8dSAndroid Build Coastguard Worker def _iterencode_list(lst, _current_indent_level): 279*cda5da8dSAndroid Build Coastguard Worker if not lst: 280*cda5da8dSAndroid Build Coastguard Worker yield '[]' 281*cda5da8dSAndroid Build Coastguard Worker return 282*cda5da8dSAndroid Build Coastguard Worker if markers is not None: 283*cda5da8dSAndroid Build Coastguard Worker markerid = id(lst) 284*cda5da8dSAndroid Build Coastguard Worker if markerid in markers: 285*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Circular reference detected") 286*cda5da8dSAndroid Build Coastguard Worker markers[markerid] = lst 287*cda5da8dSAndroid Build Coastguard Worker buf = '[' 288*cda5da8dSAndroid Build Coastguard Worker if _indent is not None: 289*cda5da8dSAndroid Build Coastguard Worker _current_indent_level += 1 290*cda5da8dSAndroid Build Coastguard Worker newline_indent = '\n' + _indent * _current_indent_level 291*cda5da8dSAndroid Build Coastguard Worker separator = _item_separator + newline_indent 292*cda5da8dSAndroid Build Coastguard Worker buf += newline_indent 293*cda5da8dSAndroid Build Coastguard Worker else: 294*cda5da8dSAndroid Build Coastguard Worker newline_indent = None 295*cda5da8dSAndroid Build Coastguard Worker separator = _item_separator 296*cda5da8dSAndroid Build Coastguard Worker first = True 297*cda5da8dSAndroid Build Coastguard Worker for value in lst: 298*cda5da8dSAndroid Build Coastguard Worker if first: 299*cda5da8dSAndroid Build Coastguard Worker first = False 300*cda5da8dSAndroid Build Coastguard Worker else: 301*cda5da8dSAndroid Build Coastguard Worker buf = separator 302*cda5da8dSAndroid Build Coastguard Worker if isinstance(value, str): 303*cda5da8dSAndroid Build Coastguard Worker yield buf + _encoder(value) 304*cda5da8dSAndroid Build Coastguard Worker elif value is None: 305*cda5da8dSAndroid Build Coastguard Worker yield buf + 'null' 306*cda5da8dSAndroid Build Coastguard Worker elif value is True: 307*cda5da8dSAndroid Build Coastguard Worker yield buf + 'true' 308*cda5da8dSAndroid Build Coastguard Worker elif value is False: 309*cda5da8dSAndroid Build Coastguard Worker yield buf + 'false' 310*cda5da8dSAndroid Build Coastguard Worker elif isinstance(value, int): 311*cda5da8dSAndroid Build Coastguard Worker # Subclasses of int/float may override __repr__, but we still 312*cda5da8dSAndroid Build Coastguard Worker # want to encode them as integers/floats in JSON. One example 313*cda5da8dSAndroid Build Coastguard Worker # within the standard library is IntEnum. 314*cda5da8dSAndroid Build Coastguard Worker yield buf + _intstr(value) 315*cda5da8dSAndroid Build Coastguard Worker elif isinstance(value, float): 316*cda5da8dSAndroid Build Coastguard Worker # see comment above for int 317*cda5da8dSAndroid Build Coastguard Worker yield buf + _floatstr(value) 318*cda5da8dSAndroid Build Coastguard Worker else: 319*cda5da8dSAndroid Build Coastguard Worker yield buf 320*cda5da8dSAndroid Build Coastguard Worker if isinstance(value, (list, tuple)): 321*cda5da8dSAndroid Build Coastguard Worker chunks = _iterencode_list(value, _current_indent_level) 322*cda5da8dSAndroid Build Coastguard Worker elif isinstance(value, dict): 323*cda5da8dSAndroid Build Coastguard Worker chunks = _iterencode_dict(value, _current_indent_level) 324*cda5da8dSAndroid Build Coastguard Worker else: 325*cda5da8dSAndroid Build Coastguard Worker chunks = _iterencode(value, _current_indent_level) 326*cda5da8dSAndroid Build Coastguard Worker yield from chunks 327*cda5da8dSAndroid Build Coastguard Worker if newline_indent is not None: 328*cda5da8dSAndroid Build Coastguard Worker _current_indent_level -= 1 329*cda5da8dSAndroid Build Coastguard Worker yield '\n' + _indent * _current_indent_level 330*cda5da8dSAndroid Build Coastguard Worker yield ']' 331*cda5da8dSAndroid Build Coastguard Worker if markers is not None: 332*cda5da8dSAndroid Build Coastguard Worker del markers[markerid] 333*cda5da8dSAndroid Build Coastguard Worker 334*cda5da8dSAndroid Build Coastguard Worker def _iterencode_dict(dct, _current_indent_level): 335*cda5da8dSAndroid Build Coastguard Worker if not dct: 336*cda5da8dSAndroid Build Coastguard Worker yield '{}' 337*cda5da8dSAndroid Build Coastguard Worker return 338*cda5da8dSAndroid Build Coastguard Worker if markers is not None: 339*cda5da8dSAndroid Build Coastguard Worker markerid = id(dct) 340*cda5da8dSAndroid Build Coastguard Worker if markerid in markers: 341*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Circular reference detected") 342*cda5da8dSAndroid Build Coastguard Worker markers[markerid] = dct 343*cda5da8dSAndroid Build Coastguard Worker yield '{' 344*cda5da8dSAndroid Build Coastguard Worker if _indent is not None: 345*cda5da8dSAndroid Build Coastguard Worker _current_indent_level += 1 346*cda5da8dSAndroid Build Coastguard Worker newline_indent = '\n' + _indent * _current_indent_level 347*cda5da8dSAndroid Build Coastguard Worker item_separator = _item_separator + newline_indent 348*cda5da8dSAndroid Build Coastguard Worker yield newline_indent 349*cda5da8dSAndroid Build Coastguard Worker else: 350*cda5da8dSAndroid Build Coastguard Worker newline_indent = None 351*cda5da8dSAndroid Build Coastguard Worker item_separator = _item_separator 352*cda5da8dSAndroid Build Coastguard Worker first = True 353*cda5da8dSAndroid Build Coastguard Worker if _sort_keys: 354*cda5da8dSAndroid Build Coastguard Worker items = sorted(dct.items()) 355*cda5da8dSAndroid Build Coastguard Worker else: 356*cda5da8dSAndroid Build Coastguard Worker items = dct.items() 357*cda5da8dSAndroid Build Coastguard Worker for key, value in items: 358*cda5da8dSAndroid Build Coastguard Worker if isinstance(key, str): 359*cda5da8dSAndroid Build Coastguard Worker pass 360*cda5da8dSAndroid Build Coastguard Worker # JavaScript is weakly typed for these, so it makes sense to 361*cda5da8dSAndroid Build Coastguard Worker # also allow them. Many encoders seem to do something like this. 362*cda5da8dSAndroid Build Coastguard Worker elif isinstance(key, float): 363*cda5da8dSAndroid Build Coastguard Worker # see comment for int/float in _make_iterencode 364*cda5da8dSAndroid Build Coastguard Worker key = _floatstr(key) 365*cda5da8dSAndroid Build Coastguard Worker elif key is True: 366*cda5da8dSAndroid Build Coastguard Worker key = 'true' 367*cda5da8dSAndroid Build Coastguard Worker elif key is False: 368*cda5da8dSAndroid Build Coastguard Worker key = 'false' 369*cda5da8dSAndroid Build Coastguard Worker elif key is None: 370*cda5da8dSAndroid Build Coastguard Worker key = 'null' 371*cda5da8dSAndroid Build Coastguard Worker elif isinstance(key, int): 372*cda5da8dSAndroid Build Coastguard Worker # see comment for int/float in _make_iterencode 373*cda5da8dSAndroid Build Coastguard Worker key = _intstr(key) 374*cda5da8dSAndroid Build Coastguard Worker elif _skipkeys: 375*cda5da8dSAndroid Build Coastguard Worker continue 376*cda5da8dSAndroid Build Coastguard Worker else: 377*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'keys must be str, int, float, bool or None, ' 378*cda5da8dSAndroid Build Coastguard Worker f'not {key.__class__.__name__}') 379*cda5da8dSAndroid Build Coastguard Worker if first: 380*cda5da8dSAndroid Build Coastguard Worker first = False 381*cda5da8dSAndroid Build Coastguard Worker else: 382*cda5da8dSAndroid Build Coastguard Worker yield item_separator 383*cda5da8dSAndroid Build Coastguard Worker yield _encoder(key) 384*cda5da8dSAndroid Build Coastguard Worker yield _key_separator 385*cda5da8dSAndroid Build Coastguard Worker if isinstance(value, str): 386*cda5da8dSAndroid Build Coastguard Worker yield _encoder(value) 387*cda5da8dSAndroid Build Coastguard Worker elif value is None: 388*cda5da8dSAndroid Build Coastguard Worker yield 'null' 389*cda5da8dSAndroid Build Coastguard Worker elif value is True: 390*cda5da8dSAndroid Build Coastguard Worker yield 'true' 391*cda5da8dSAndroid Build Coastguard Worker elif value is False: 392*cda5da8dSAndroid Build Coastguard Worker yield 'false' 393*cda5da8dSAndroid Build Coastguard Worker elif isinstance(value, int): 394*cda5da8dSAndroid Build Coastguard Worker # see comment for int/float in _make_iterencode 395*cda5da8dSAndroid Build Coastguard Worker yield _intstr(value) 396*cda5da8dSAndroid Build Coastguard Worker elif isinstance(value, float): 397*cda5da8dSAndroid Build Coastguard Worker # see comment for int/float in _make_iterencode 398*cda5da8dSAndroid Build Coastguard Worker yield _floatstr(value) 399*cda5da8dSAndroid Build Coastguard Worker else: 400*cda5da8dSAndroid Build Coastguard Worker if isinstance(value, (list, tuple)): 401*cda5da8dSAndroid Build Coastguard Worker chunks = _iterencode_list(value, _current_indent_level) 402*cda5da8dSAndroid Build Coastguard Worker elif isinstance(value, dict): 403*cda5da8dSAndroid Build Coastguard Worker chunks = _iterencode_dict(value, _current_indent_level) 404*cda5da8dSAndroid Build Coastguard Worker else: 405*cda5da8dSAndroid Build Coastguard Worker chunks = _iterencode(value, _current_indent_level) 406*cda5da8dSAndroid Build Coastguard Worker yield from chunks 407*cda5da8dSAndroid Build Coastguard Worker if newline_indent is not None: 408*cda5da8dSAndroid Build Coastguard Worker _current_indent_level -= 1 409*cda5da8dSAndroid Build Coastguard Worker yield '\n' + _indent * _current_indent_level 410*cda5da8dSAndroid Build Coastguard Worker yield '}' 411*cda5da8dSAndroid Build Coastguard Worker if markers is not None: 412*cda5da8dSAndroid Build Coastguard Worker del markers[markerid] 413*cda5da8dSAndroid Build Coastguard Worker 414*cda5da8dSAndroid Build Coastguard Worker def _iterencode(o, _current_indent_level): 415*cda5da8dSAndroid Build Coastguard Worker if isinstance(o, str): 416*cda5da8dSAndroid Build Coastguard Worker yield _encoder(o) 417*cda5da8dSAndroid Build Coastguard Worker elif o is None: 418*cda5da8dSAndroid Build Coastguard Worker yield 'null' 419*cda5da8dSAndroid Build Coastguard Worker elif o is True: 420*cda5da8dSAndroid Build Coastguard Worker yield 'true' 421*cda5da8dSAndroid Build Coastguard Worker elif o is False: 422*cda5da8dSAndroid Build Coastguard Worker yield 'false' 423*cda5da8dSAndroid Build Coastguard Worker elif isinstance(o, int): 424*cda5da8dSAndroid Build Coastguard Worker # see comment for int/float in _make_iterencode 425*cda5da8dSAndroid Build Coastguard Worker yield _intstr(o) 426*cda5da8dSAndroid Build Coastguard Worker elif isinstance(o, float): 427*cda5da8dSAndroid Build Coastguard Worker # see comment for int/float in _make_iterencode 428*cda5da8dSAndroid Build Coastguard Worker yield _floatstr(o) 429*cda5da8dSAndroid Build Coastguard Worker elif isinstance(o, (list, tuple)): 430*cda5da8dSAndroid Build Coastguard Worker yield from _iterencode_list(o, _current_indent_level) 431*cda5da8dSAndroid Build Coastguard Worker elif isinstance(o, dict): 432*cda5da8dSAndroid Build Coastguard Worker yield from _iterencode_dict(o, _current_indent_level) 433*cda5da8dSAndroid Build Coastguard Worker else: 434*cda5da8dSAndroid Build Coastguard Worker if markers is not None: 435*cda5da8dSAndroid Build Coastguard Worker markerid = id(o) 436*cda5da8dSAndroid Build Coastguard Worker if markerid in markers: 437*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Circular reference detected") 438*cda5da8dSAndroid Build Coastguard Worker markers[markerid] = o 439*cda5da8dSAndroid Build Coastguard Worker o = _default(o) 440*cda5da8dSAndroid Build Coastguard Worker yield from _iterencode(o, _current_indent_level) 441*cda5da8dSAndroid Build Coastguard Worker if markers is not None: 442*cda5da8dSAndroid Build Coastguard Worker del markers[markerid] 443*cda5da8dSAndroid Build Coastguard Worker return _iterencode 444