xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/json/encoder.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
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