xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/json/decoder.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Implementation of JSONDecoder
2*cda5da8dSAndroid Build Coastguard Worker"""
3*cda5da8dSAndroid Build Coastguard Workerimport re
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard Workerfrom json import scanner
6*cda5da8dSAndroid Build Coastguard Workertry:
7*cda5da8dSAndroid Build Coastguard Worker    from _json import scanstring as c_scanstring
8*cda5da8dSAndroid Build Coastguard Workerexcept ImportError:
9*cda5da8dSAndroid Build Coastguard Worker    c_scanstring = None
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Worker__all__ = ['JSONDecoder', 'JSONDecodeError']
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard WorkerFLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard WorkerNaN = float('nan')
16*cda5da8dSAndroid Build Coastguard WorkerPosInf = float('inf')
17*cda5da8dSAndroid Build Coastguard WorkerNegInf = float('-inf')
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker
20*cda5da8dSAndroid Build Coastguard Workerclass JSONDecodeError(ValueError):
21*cda5da8dSAndroid Build Coastguard Worker    """Subclass of ValueError with the following additional properties:
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard Worker    msg: The unformatted error message
24*cda5da8dSAndroid Build Coastguard Worker    doc: The JSON document being parsed
25*cda5da8dSAndroid Build Coastguard Worker    pos: The start index of doc where parsing failed
26*cda5da8dSAndroid Build Coastguard Worker    lineno: The line corresponding to pos
27*cda5da8dSAndroid Build Coastguard Worker    colno: The column corresponding to pos
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker    """
30*cda5da8dSAndroid Build Coastguard Worker    # Note that this exception is used from _json
31*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, msg, doc, pos):
32*cda5da8dSAndroid Build Coastguard Worker        lineno = doc.count('\n', 0, pos) + 1
33*cda5da8dSAndroid Build Coastguard Worker        colno = pos - doc.rfind('\n', 0, pos)
34*cda5da8dSAndroid Build Coastguard Worker        errmsg = '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos)
35*cda5da8dSAndroid Build Coastguard Worker        ValueError.__init__(self, errmsg)
36*cda5da8dSAndroid Build Coastguard Worker        self.msg = msg
37*cda5da8dSAndroid Build Coastguard Worker        self.doc = doc
38*cda5da8dSAndroid Build Coastguard Worker        self.pos = pos
39*cda5da8dSAndroid Build Coastguard Worker        self.lineno = lineno
40*cda5da8dSAndroid Build Coastguard Worker        self.colno = colno
41*cda5da8dSAndroid Build Coastguard Worker
42*cda5da8dSAndroid Build Coastguard Worker    def __reduce__(self):
43*cda5da8dSAndroid Build Coastguard Worker        return self.__class__, (self.msg, self.doc, self.pos)
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Worker_CONSTANTS = {
47*cda5da8dSAndroid Build Coastguard Worker    '-Infinity': NegInf,
48*cda5da8dSAndroid Build Coastguard Worker    'Infinity': PosInf,
49*cda5da8dSAndroid Build Coastguard Worker    'NaN': NaN,
50*cda5da8dSAndroid Build Coastguard Worker}
51*cda5da8dSAndroid Build Coastguard Worker
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard WorkerSTRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
54*cda5da8dSAndroid Build Coastguard WorkerBACKSLASH = {
55*cda5da8dSAndroid Build Coastguard Worker    '"': '"', '\\': '\\', '/': '/',
56*cda5da8dSAndroid Build Coastguard Worker    'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t',
57*cda5da8dSAndroid Build Coastguard Worker}
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Workerdef _decode_uXXXX(s, pos):
60*cda5da8dSAndroid Build Coastguard Worker    esc = s[pos + 1:pos + 5]
61*cda5da8dSAndroid Build Coastguard Worker    if len(esc) == 4 and esc[1] not in 'xX':
62*cda5da8dSAndroid Build Coastguard Worker        try:
63*cda5da8dSAndroid Build Coastguard Worker            return int(esc, 16)
64*cda5da8dSAndroid Build Coastguard Worker        except ValueError:
65*cda5da8dSAndroid Build Coastguard Worker            pass
66*cda5da8dSAndroid Build Coastguard Worker    msg = "Invalid \\uXXXX escape"
67*cda5da8dSAndroid Build Coastguard Worker    raise JSONDecodeError(msg, s, pos)
68*cda5da8dSAndroid Build Coastguard Worker
69*cda5da8dSAndroid Build Coastguard Workerdef py_scanstring(s, end, strict=True,
70*cda5da8dSAndroid Build Coastguard Worker        _b=BACKSLASH, _m=STRINGCHUNK.match):
71*cda5da8dSAndroid Build Coastguard Worker    """Scan the string s for a JSON string. End is the index of the
72*cda5da8dSAndroid Build Coastguard Worker    character in s after the quote that started the JSON string.
73*cda5da8dSAndroid Build Coastguard Worker    Unescapes all valid JSON string escape sequences and raises ValueError
74*cda5da8dSAndroid Build Coastguard Worker    on attempt to decode an invalid string. If strict is False then literal
75*cda5da8dSAndroid Build Coastguard Worker    control characters are allowed in the string.
76*cda5da8dSAndroid Build Coastguard Worker
77*cda5da8dSAndroid Build Coastguard Worker    Returns a tuple of the decoded string and the index of the character in s
78*cda5da8dSAndroid Build Coastguard Worker    after the end quote."""
79*cda5da8dSAndroid Build Coastguard Worker    chunks = []
80*cda5da8dSAndroid Build Coastguard Worker    _append = chunks.append
81*cda5da8dSAndroid Build Coastguard Worker    begin = end - 1
82*cda5da8dSAndroid Build Coastguard Worker    while 1:
83*cda5da8dSAndroid Build Coastguard Worker        chunk = _m(s, end)
84*cda5da8dSAndroid Build Coastguard Worker        if chunk is None:
85*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Unterminated string starting at", s, begin)
86*cda5da8dSAndroid Build Coastguard Worker        end = chunk.end()
87*cda5da8dSAndroid Build Coastguard Worker        content, terminator = chunk.groups()
88*cda5da8dSAndroid Build Coastguard Worker        # Content is contains zero or more unescaped string characters
89*cda5da8dSAndroid Build Coastguard Worker        if content:
90*cda5da8dSAndroid Build Coastguard Worker            _append(content)
91*cda5da8dSAndroid Build Coastguard Worker        # Terminator is the end of string, a literal control character,
92*cda5da8dSAndroid Build Coastguard Worker        # or a backslash denoting that an escape sequence follows
93*cda5da8dSAndroid Build Coastguard Worker        if terminator == '"':
94*cda5da8dSAndroid Build Coastguard Worker            break
95*cda5da8dSAndroid Build Coastguard Worker        elif terminator != '\\':
96*cda5da8dSAndroid Build Coastguard Worker            if strict:
97*cda5da8dSAndroid Build Coastguard Worker                #msg = "Invalid control character %r at" % (terminator,)
98*cda5da8dSAndroid Build Coastguard Worker                msg = "Invalid control character {0!r} at".format(terminator)
99*cda5da8dSAndroid Build Coastguard Worker                raise JSONDecodeError(msg, s, end)
100*cda5da8dSAndroid Build Coastguard Worker            else:
101*cda5da8dSAndroid Build Coastguard Worker                _append(terminator)
102*cda5da8dSAndroid Build Coastguard Worker                continue
103*cda5da8dSAndroid Build Coastguard Worker        try:
104*cda5da8dSAndroid Build Coastguard Worker            esc = s[end]
105*cda5da8dSAndroid Build Coastguard Worker        except IndexError:
106*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Unterminated string starting at",
107*cda5da8dSAndroid Build Coastguard Worker                                  s, begin) from None
108*cda5da8dSAndroid Build Coastguard Worker        # If not a unicode escape sequence, must be in the lookup table
109*cda5da8dSAndroid Build Coastguard Worker        if esc != 'u':
110*cda5da8dSAndroid Build Coastguard Worker            try:
111*cda5da8dSAndroid Build Coastguard Worker                char = _b[esc]
112*cda5da8dSAndroid Build Coastguard Worker            except KeyError:
113*cda5da8dSAndroid Build Coastguard Worker                msg = "Invalid \\escape: {0!r}".format(esc)
114*cda5da8dSAndroid Build Coastguard Worker                raise JSONDecodeError(msg, s, end)
115*cda5da8dSAndroid Build Coastguard Worker            end += 1
116*cda5da8dSAndroid Build Coastguard Worker        else:
117*cda5da8dSAndroid Build Coastguard Worker            uni = _decode_uXXXX(s, end)
118*cda5da8dSAndroid Build Coastguard Worker            end += 5
119*cda5da8dSAndroid Build Coastguard Worker            if 0xd800 <= uni <= 0xdbff and s[end:end + 2] == '\\u':
120*cda5da8dSAndroid Build Coastguard Worker                uni2 = _decode_uXXXX(s, end + 1)
121*cda5da8dSAndroid Build Coastguard Worker                if 0xdc00 <= uni2 <= 0xdfff:
122*cda5da8dSAndroid Build Coastguard Worker                    uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
123*cda5da8dSAndroid Build Coastguard Worker                    end += 6
124*cda5da8dSAndroid Build Coastguard Worker            char = chr(uni)
125*cda5da8dSAndroid Build Coastguard Worker        _append(char)
126*cda5da8dSAndroid Build Coastguard Worker    return ''.join(chunks), end
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Worker# Use speedup if available
130*cda5da8dSAndroid Build Coastguard Workerscanstring = c_scanstring or py_scanstring
131*cda5da8dSAndroid Build Coastguard Worker
132*cda5da8dSAndroid Build Coastguard WorkerWHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
133*cda5da8dSAndroid Build Coastguard WorkerWHITESPACE_STR = ' \t\n\r'
134*cda5da8dSAndroid Build Coastguard Worker
135*cda5da8dSAndroid Build Coastguard Worker
136*cda5da8dSAndroid Build Coastguard Workerdef JSONObject(s_and_end, strict, scan_once, object_hook, object_pairs_hook,
137*cda5da8dSAndroid Build Coastguard Worker               memo=None, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
138*cda5da8dSAndroid Build Coastguard Worker    s, end = s_and_end
139*cda5da8dSAndroid Build Coastguard Worker    pairs = []
140*cda5da8dSAndroid Build Coastguard Worker    pairs_append = pairs.append
141*cda5da8dSAndroid Build Coastguard Worker    # Backwards compatibility
142*cda5da8dSAndroid Build Coastguard Worker    if memo is None:
143*cda5da8dSAndroid Build Coastguard Worker        memo = {}
144*cda5da8dSAndroid Build Coastguard Worker    memo_get = memo.setdefault
145*cda5da8dSAndroid Build Coastguard Worker    # Use a slice to prevent IndexError from being raised, the following
146*cda5da8dSAndroid Build Coastguard Worker    # check will raise a more specific ValueError if the string is empty
147*cda5da8dSAndroid Build Coastguard Worker    nextchar = s[end:end + 1]
148*cda5da8dSAndroid Build Coastguard Worker    # Normally we expect nextchar == '"'
149*cda5da8dSAndroid Build Coastguard Worker    if nextchar != '"':
150*cda5da8dSAndroid Build Coastguard Worker        if nextchar in _ws:
151*cda5da8dSAndroid Build Coastguard Worker            end = _w(s, end).end()
152*cda5da8dSAndroid Build Coastguard Worker            nextchar = s[end:end + 1]
153*cda5da8dSAndroid Build Coastguard Worker        # Trivial empty object
154*cda5da8dSAndroid Build Coastguard Worker        if nextchar == '}':
155*cda5da8dSAndroid Build Coastguard Worker            if object_pairs_hook is not None:
156*cda5da8dSAndroid Build Coastguard Worker                result = object_pairs_hook(pairs)
157*cda5da8dSAndroid Build Coastguard Worker                return result, end + 1
158*cda5da8dSAndroid Build Coastguard Worker            pairs = {}
159*cda5da8dSAndroid Build Coastguard Worker            if object_hook is not None:
160*cda5da8dSAndroid Build Coastguard Worker                pairs = object_hook(pairs)
161*cda5da8dSAndroid Build Coastguard Worker            return pairs, end + 1
162*cda5da8dSAndroid Build Coastguard Worker        elif nextchar != '"':
163*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError(
164*cda5da8dSAndroid Build Coastguard Worker                "Expecting property name enclosed in double quotes", s, end)
165*cda5da8dSAndroid Build Coastguard Worker    end += 1
166*cda5da8dSAndroid Build Coastguard Worker    while True:
167*cda5da8dSAndroid Build Coastguard Worker        key, end = scanstring(s, end, strict)
168*cda5da8dSAndroid Build Coastguard Worker        key = memo_get(key, key)
169*cda5da8dSAndroid Build Coastguard Worker        # To skip some function call overhead we optimize the fast paths where
170*cda5da8dSAndroid Build Coastguard Worker        # the JSON key separator is ": " or just ":".
171*cda5da8dSAndroid Build Coastguard Worker        if s[end:end + 1] != ':':
172*cda5da8dSAndroid Build Coastguard Worker            end = _w(s, end).end()
173*cda5da8dSAndroid Build Coastguard Worker            if s[end:end + 1] != ':':
174*cda5da8dSAndroid Build Coastguard Worker                raise JSONDecodeError("Expecting ':' delimiter", s, end)
175*cda5da8dSAndroid Build Coastguard Worker        end += 1
176*cda5da8dSAndroid Build Coastguard Worker
177*cda5da8dSAndroid Build Coastguard Worker        try:
178*cda5da8dSAndroid Build Coastguard Worker            if s[end] in _ws:
179*cda5da8dSAndroid Build Coastguard Worker                end += 1
180*cda5da8dSAndroid Build Coastguard Worker                if s[end] in _ws:
181*cda5da8dSAndroid Build Coastguard Worker                    end = _w(s, end + 1).end()
182*cda5da8dSAndroid Build Coastguard Worker        except IndexError:
183*cda5da8dSAndroid Build Coastguard Worker            pass
184*cda5da8dSAndroid Build Coastguard Worker
185*cda5da8dSAndroid Build Coastguard Worker        try:
186*cda5da8dSAndroid Build Coastguard Worker            value, end = scan_once(s, end)
187*cda5da8dSAndroid Build Coastguard Worker        except StopIteration as err:
188*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Expecting value", s, err.value) from None
189*cda5da8dSAndroid Build Coastguard Worker        pairs_append((key, value))
190*cda5da8dSAndroid Build Coastguard Worker        try:
191*cda5da8dSAndroid Build Coastguard Worker            nextchar = s[end]
192*cda5da8dSAndroid Build Coastguard Worker            if nextchar in _ws:
193*cda5da8dSAndroid Build Coastguard Worker                end = _w(s, end + 1).end()
194*cda5da8dSAndroid Build Coastguard Worker                nextchar = s[end]
195*cda5da8dSAndroid Build Coastguard Worker        except IndexError:
196*cda5da8dSAndroid Build Coastguard Worker            nextchar = ''
197*cda5da8dSAndroid Build Coastguard Worker        end += 1
198*cda5da8dSAndroid Build Coastguard Worker
199*cda5da8dSAndroid Build Coastguard Worker        if nextchar == '}':
200*cda5da8dSAndroid Build Coastguard Worker            break
201*cda5da8dSAndroid Build Coastguard Worker        elif nextchar != ',':
202*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Expecting ',' delimiter", s, end - 1)
203*cda5da8dSAndroid Build Coastguard Worker        end = _w(s, end).end()
204*cda5da8dSAndroid Build Coastguard Worker        nextchar = s[end:end + 1]
205*cda5da8dSAndroid Build Coastguard Worker        end += 1
206*cda5da8dSAndroid Build Coastguard Worker        if nextchar != '"':
207*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError(
208*cda5da8dSAndroid Build Coastguard Worker                "Expecting property name enclosed in double quotes", s, end - 1)
209*cda5da8dSAndroid Build Coastguard Worker    if object_pairs_hook is not None:
210*cda5da8dSAndroid Build Coastguard Worker        result = object_pairs_hook(pairs)
211*cda5da8dSAndroid Build Coastguard Worker        return result, end
212*cda5da8dSAndroid Build Coastguard Worker    pairs = dict(pairs)
213*cda5da8dSAndroid Build Coastguard Worker    if object_hook is not None:
214*cda5da8dSAndroid Build Coastguard Worker        pairs = object_hook(pairs)
215*cda5da8dSAndroid Build Coastguard Worker    return pairs, end
216*cda5da8dSAndroid Build Coastguard Worker
217*cda5da8dSAndroid Build Coastguard Workerdef JSONArray(s_and_end, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
218*cda5da8dSAndroid Build Coastguard Worker    s, end = s_and_end
219*cda5da8dSAndroid Build Coastguard Worker    values = []
220*cda5da8dSAndroid Build Coastguard Worker    nextchar = s[end:end + 1]
221*cda5da8dSAndroid Build Coastguard Worker    if nextchar in _ws:
222*cda5da8dSAndroid Build Coastguard Worker        end = _w(s, end + 1).end()
223*cda5da8dSAndroid Build Coastguard Worker        nextchar = s[end:end + 1]
224*cda5da8dSAndroid Build Coastguard Worker    # Look-ahead for trivial empty array
225*cda5da8dSAndroid Build Coastguard Worker    if nextchar == ']':
226*cda5da8dSAndroid Build Coastguard Worker        return values, end + 1
227*cda5da8dSAndroid Build Coastguard Worker    _append = values.append
228*cda5da8dSAndroid Build Coastguard Worker    while True:
229*cda5da8dSAndroid Build Coastguard Worker        try:
230*cda5da8dSAndroid Build Coastguard Worker            value, end = scan_once(s, end)
231*cda5da8dSAndroid Build Coastguard Worker        except StopIteration as err:
232*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Expecting value", s, err.value) from None
233*cda5da8dSAndroid Build Coastguard Worker        _append(value)
234*cda5da8dSAndroid Build Coastguard Worker        nextchar = s[end:end + 1]
235*cda5da8dSAndroid Build Coastguard Worker        if nextchar in _ws:
236*cda5da8dSAndroid Build Coastguard Worker            end = _w(s, end + 1).end()
237*cda5da8dSAndroid Build Coastguard Worker            nextchar = s[end:end + 1]
238*cda5da8dSAndroid Build Coastguard Worker        end += 1
239*cda5da8dSAndroid Build Coastguard Worker        if nextchar == ']':
240*cda5da8dSAndroid Build Coastguard Worker            break
241*cda5da8dSAndroid Build Coastguard Worker        elif nextchar != ',':
242*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Expecting ',' delimiter", s, end - 1)
243*cda5da8dSAndroid Build Coastguard Worker        try:
244*cda5da8dSAndroid Build Coastguard Worker            if s[end] in _ws:
245*cda5da8dSAndroid Build Coastguard Worker                end += 1
246*cda5da8dSAndroid Build Coastguard Worker                if s[end] in _ws:
247*cda5da8dSAndroid Build Coastguard Worker                    end = _w(s, end + 1).end()
248*cda5da8dSAndroid Build Coastguard Worker        except IndexError:
249*cda5da8dSAndroid Build Coastguard Worker            pass
250*cda5da8dSAndroid Build Coastguard Worker
251*cda5da8dSAndroid Build Coastguard Worker    return values, end
252*cda5da8dSAndroid Build Coastguard Worker
253*cda5da8dSAndroid Build Coastguard Worker
254*cda5da8dSAndroid Build Coastguard Workerclass JSONDecoder(object):
255*cda5da8dSAndroid Build Coastguard Worker    """Simple JSON <https://json.org> decoder
256*cda5da8dSAndroid Build Coastguard Worker
257*cda5da8dSAndroid Build Coastguard Worker    Performs the following translations in decoding by default:
258*cda5da8dSAndroid Build Coastguard Worker
259*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
260*cda5da8dSAndroid Build Coastguard Worker    | JSON          | Python            |
261*cda5da8dSAndroid Build Coastguard Worker    +===============+===================+
262*cda5da8dSAndroid Build Coastguard Worker    | object        | dict              |
263*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
264*cda5da8dSAndroid Build Coastguard Worker    | array         | list              |
265*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
266*cda5da8dSAndroid Build Coastguard Worker    | string        | str               |
267*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
268*cda5da8dSAndroid Build Coastguard Worker    | number (int)  | int               |
269*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
270*cda5da8dSAndroid Build Coastguard Worker    | number (real) | float             |
271*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
272*cda5da8dSAndroid Build Coastguard Worker    | true          | True              |
273*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
274*cda5da8dSAndroid Build Coastguard Worker    | false         | False             |
275*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
276*cda5da8dSAndroid Build Coastguard Worker    | null          | None              |
277*cda5da8dSAndroid Build Coastguard Worker    +---------------+-------------------+
278*cda5da8dSAndroid Build Coastguard Worker
279*cda5da8dSAndroid Build Coastguard Worker    It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
280*cda5da8dSAndroid Build Coastguard Worker    their corresponding ``float`` values, which is outside the JSON spec.
281*cda5da8dSAndroid Build Coastguard Worker
282*cda5da8dSAndroid Build Coastguard Worker    """
283*cda5da8dSAndroid Build Coastguard Worker
284*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, *, object_hook=None, parse_float=None,
285*cda5da8dSAndroid Build Coastguard Worker            parse_int=None, parse_constant=None, strict=True,
286*cda5da8dSAndroid Build Coastguard Worker            object_pairs_hook=None):
287*cda5da8dSAndroid Build Coastguard Worker        """``object_hook``, if specified, will be called with the result
288*cda5da8dSAndroid Build Coastguard Worker        of every JSON object decoded and its return value will be used in
289*cda5da8dSAndroid Build Coastguard Worker        place of the given ``dict``.  This can be used to provide custom
290*cda5da8dSAndroid Build Coastguard Worker        deserializations (e.g. to support JSON-RPC class hinting).
291*cda5da8dSAndroid Build Coastguard Worker
292*cda5da8dSAndroid Build Coastguard Worker        ``object_pairs_hook``, if specified will be called with the result of
293*cda5da8dSAndroid Build Coastguard Worker        every JSON object decoded with an ordered list of pairs.  The return
294*cda5da8dSAndroid Build Coastguard Worker        value of ``object_pairs_hook`` will be used instead of the ``dict``.
295*cda5da8dSAndroid Build Coastguard Worker        This feature can be used to implement custom decoders.
296*cda5da8dSAndroid Build Coastguard Worker        If ``object_hook`` is also defined, the ``object_pairs_hook`` takes
297*cda5da8dSAndroid Build Coastguard Worker        priority.
298*cda5da8dSAndroid Build Coastguard Worker
299*cda5da8dSAndroid Build Coastguard Worker        ``parse_float``, if specified, will be called with the string
300*cda5da8dSAndroid Build Coastguard Worker        of every JSON float to be decoded. By default this is equivalent to
301*cda5da8dSAndroid Build Coastguard Worker        float(num_str). This can be used to use another datatype or parser
302*cda5da8dSAndroid Build Coastguard Worker        for JSON floats (e.g. decimal.Decimal).
303*cda5da8dSAndroid Build Coastguard Worker
304*cda5da8dSAndroid Build Coastguard Worker        ``parse_int``, if specified, will be called with the string
305*cda5da8dSAndroid Build Coastguard Worker        of every JSON int to be decoded. By default this is equivalent to
306*cda5da8dSAndroid Build Coastguard Worker        int(num_str). This can be used to use another datatype or parser
307*cda5da8dSAndroid Build Coastguard Worker        for JSON integers (e.g. float).
308*cda5da8dSAndroid Build Coastguard Worker
309*cda5da8dSAndroid Build Coastguard Worker        ``parse_constant``, if specified, will be called with one of the
310*cda5da8dSAndroid Build Coastguard Worker        following strings: -Infinity, Infinity, NaN.
311*cda5da8dSAndroid Build Coastguard Worker        This can be used to raise an exception if invalid JSON numbers
312*cda5da8dSAndroid Build Coastguard Worker        are encountered.
313*cda5da8dSAndroid Build Coastguard Worker
314*cda5da8dSAndroid Build Coastguard Worker        If ``strict`` is false (true is the default), then control
315*cda5da8dSAndroid Build Coastguard Worker        characters will be allowed inside strings.  Control characters in
316*cda5da8dSAndroid Build Coastguard Worker        this context are those with character codes in the 0-31 range,
317*cda5da8dSAndroid Build Coastguard Worker        including ``'\\t'`` (tab), ``'\\n'``, ``'\\r'`` and ``'\\0'``.
318*cda5da8dSAndroid Build Coastguard Worker        """
319*cda5da8dSAndroid Build Coastguard Worker        self.object_hook = object_hook
320*cda5da8dSAndroid Build Coastguard Worker        self.parse_float = parse_float or float
321*cda5da8dSAndroid Build Coastguard Worker        self.parse_int = parse_int or int
322*cda5da8dSAndroid Build Coastguard Worker        self.parse_constant = parse_constant or _CONSTANTS.__getitem__
323*cda5da8dSAndroid Build Coastguard Worker        self.strict = strict
324*cda5da8dSAndroid Build Coastguard Worker        self.object_pairs_hook = object_pairs_hook
325*cda5da8dSAndroid Build Coastguard Worker        self.parse_object = JSONObject
326*cda5da8dSAndroid Build Coastguard Worker        self.parse_array = JSONArray
327*cda5da8dSAndroid Build Coastguard Worker        self.parse_string = scanstring
328*cda5da8dSAndroid Build Coastguard Worker        self.memo = {}
329*cda5da8dSAndroid Build Coastguard Worker        self.scan_once = scanner.make_scanner(self)
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker
332*cda5da8dSAndroid Build Coastguard Worker    def decode(self, s, _w=WHITESPACE.match):
333*cda5da8dSAndroid Build Coastguard Worker        """Return the Python representation of ``s`` (a ``str`` instance
334*cda5da8dSAndroid Build Coastguard Worker        containing a JSON document).
335*cda5da8dSAndroid Build Coastguard Worker
336*cda5da8dSAndroid Build Coastguard Worker        """
337*cda5da8dSAndroid Build Coastguard Worker        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
338*cda5da8dSAndroid Build Coastguard Worker        end = _w(s, end).end()
339*cda5da8dSAndroid Build Coastguard Worker        if end != len(s):
340*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Extra data", s, end)
341*cda5da8dSAndroid Build Coastguard Worker        return obj
342*cda5da8dSAndroid Build Coastguard Worker
343*cda5da8dSAndroid Build Coastguard Worker    def raw_decode(self, s, idx=0):
344*cda5da8dSAndroid Build Coastguard Worker        """Decode a JSON document from ``s`` (a ``str`` beginning with
345*cda5da8dSAndroid Build Coastguard Worker        a JSON document) and return a 2-tuple of the Python
346*cda5da8dSAndroid Build Coastguard Worker        representation and the index in ``s`` where the document ended.
347*cda5da8dSAndroid Build Coastguard Worker
348*cda5da8dSAndroid Build Coastguard Worker        This can be used to decode a JSON document from a string that may
349*cda5da8dSAndroid Build Coastguard Worker        have extraneous data at the end.
350*cda5da8dSAndroid Build Coastguard Worker
351*cda5da8dSAndroid Build Coastguard Worker        """
352*cda5da8dSAndroid Build Coastguard Worker        try:
353*cda5da8dSAndroid Build Coastguard Worker            obj, end = self.scan_once(s, idx)
354*cda5da8dSAndroid Build Coastguard Worker        except StopIteration as err:
355*cda5da8dSAndroid Build Coastguard Worker            raise JSONDecodeError("Expecting value", s, err.value) from None
356*cda5da8dSAndroid Build Coastguard Worker        return obj, end
357