ยปCore Development>Code coverage>Lib/json/decoder.py

Python code coverage for Lib/json/decoder.py

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