Advertisement
Guest User

Untitled

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