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