github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/json/encoder.py (about)

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