Package gozerbot :: Package contrib :: Package simplejson :: Module encoder
[hide private]
[frames] | no frames]

Source Code for Module gozerbot.contrib.simplejson.encoder

  1  """ 
  2  Implementation of JSONEncoder 
  3  """ 
  4  import re 
  5  try: 
  6      from simplejson import _speedups 
  7  except ImportError: 
  8      _speedups = None 
  9   
 10  ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') 
 11  ESCAPE_ASCII = re.compile(r'([\\"/]|[^\ -~])') 
 12  ESCAPE_DCT = { 
 13      '\\': '\\\\', 
 14      '"': '\\"', 
 15      '\b': '\\b', 
 16      '\f': '\\f', 
 17      '\n': '\\n', 
 18      '\r': '\\r', 
 19      '\t': '\\t', 
 20  } 
 21  for i in range(0x20): 
 22      ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) 
 23   
 24  # assume this produces an infinity on all machines (probably not guaranteed) 
 25  INFINITY = float('1e66666') 
 26  FLOAT_REPR = repr 
 27   
28 -def floatstr(o, allow_nan=True):
29 # Check for specials. Note that this type of test is processor- and/or 30 # platform-specific, so do tests which don't depend on the internals. 31 32 if o != o: 33 text = 'NaN' 34 elif o == INFINITY: 35 text = 'Infinity' 36 elif o == -INFINITY: 37 text = '-Infinity' 38 else: 39 return FLOAT_REPR(o) 40 41 if not allow_nan: 42 raise ValueError("Out of range float values are not JSON compliant: %r" 43 % (o,)) 44 45 return text
46 47
48 -def encode_basestring(s):
49 """ 50 Return a JSON representation of a Python string 51 """ 52 def replace(match): 53 return ESCAPE_DCT[match.group(0)]
54 return '"' + ESCAPE.sub(replace, s) + '"' 55
56 -def encode_basestring_ascii(s):
57 def replace(match): 58 s = match.group(0) 59 try: 60 return ESCAPE_DCT[s] 61 except KeyError: 62 n = ord(s) 63 if n < 0x10000: 64 return '\\u%04x' % (n,) 65 else: 66 # surrogate pair 67 n -= 0x10000 68 s1 = 0xd800 | ((n >> 10) & 0x3ff) 69 s2 = 0xdc00 | (n & 0x3ff) 70 return '\\u%04x\\u%04x' % (s1, s2)
71 return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' 72 73 try: 74 encode_basestring_ascii = _speedups.encode_basestring_ascii 75 _need_utf8 = True 76 except AttributeError: 77 _need_utf8 = False 78
79 -class JSONEncoder(object):
80 """ 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 __all__ = ['__init__', 'default', 'encode', 'iterencode'] 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 """ 115 Constructor for JSONEncoder, with sensible defaults. 116 117 If skipkeys is False, then it is a TypeError to attempt 118 encoding of keys that are not str, int, long, float or None. If 119 skipkeys is True, such items are simply skipped. 120 121 If ensure_ascii is True, the output is guaranteed to be str 122 objects with all incoming unicode characters escaped. If 123 ensure_ascii is false, the output will be unicode object. 124 125 If check_circular is True, then lists, dicts, and custom encoded 126 objects will be checked for circular references during encoding to 127 prevent an infinite recursion (which would cause an OverflowError). 128 Otherwise, no such check takes place. 129 130 If allow_nan is True, then NaN, Infinity, and -Infinity will be 131 encoded as such. This behavior is not JSON specification compliant, 132 but is consistent with most JavaScript based encoders and decoders. 133 Otherwise, it will be a ValueError to encode such floats. 134 135 If sort_keys is True, then the output of dictionaries will be 136 sorted by key; this is useful for regression tests to ensure 137 that JSON serializations can be compared on a day-to-day basis. 138 139 If indent is a non-negative integer, then JSON array 140 elements and object members will be pretty-printed with that 141 indent level. An indent level of 0 will only insert newlines. 142 None is the most compact representation. 143 144 If specified, separators should be a (item_separator, key_separator) 145 tuple. The default is (', ', ': '). To get the most compact JSON 146 representation you should specify (',', ':') to eliminate whitespace. 147 148 If specified, default is a function that gets called for objects 149 that can't otherwise be serialized. It should return a JSON encodable 150 version of the object or raise a ``TypeError``. 151 152 If encoding is not None, then all input strings will be 153 transformed into unicode using that encoding prior to JSON-encoding. 154 The default is UTF-8. 155 """ 156 157 self.skipkeys = skipkeys 158 self.ensure_ascii = ensure_ascii 159 self.check_circular = check_circular 160 self.allow_nan = allow_nan 161 self.sort_keys = sort_keys 162 self.indent = indent 163 self.current_indent_level = 0 164 if separators is not None: 165 self.item_separator, self.key_separator = separators 166 if default is not None: 167 self.default = default 168 self.encoding = encoding
169
170 - def _newline_indent(self):
171 return '\n' + (' ' * (self.indent * self.current_indent_level))
172
173 - def _iterencode_list(self, lst, markers=None):
174 if not lst: 175 yield '[]' 176 return 177 if markers is not None: 178 markerid = id(lst) 179 if markerid in markers: 180 raise ValueError("Circular reference detected") 181 markers[markerid] = lst 182 yield '[' 183 if self.indent is not None: 184 self.current_indent_level += 1 185 newline_indent = self._newline_indent() 186 separator = self.item_separator + newline_indent 187 yield newline_indent 188 else: 189 newline_indent = None 190 separator = self.item_separator 191 first = True 192 for value in lst: 193 if first: 194 first = False 195 else: 196 yield separator 197 for chunk in self._iterencode(value, markers): 198 yield chunk 199 if newline_indent is not None: 200 self.current_indent_level -= 1 201 yield self._newline_indent() 202 yield ']' 203 if markers is not None: 204 del markers[markerid]
205
206 - def _iterencode_dict(self, dct, markers=None):
207 if not dct: 208 yield '{}' 209 return 210 if markers is not None: 211 markerid = id(dct) 212 if markerid in markers: 213 raise ValueError("Circular reference detected") 214 markers[markerid] = dct 215 yield '{' 216 key_separator = self.key_separator 217 if self.indent is not None: 218 self.current_indent_level += 1 219 newline_indent = self._newline_indent() 220 item_separator = self.item_separator + newline_indent 221 yield newline_indent 222 else: 223 newline_indent = None 224 item_separator = self.item_separator 225 first = True 226 if self.ensure_ascii: 227 encoder = encode_basestring_ascii 228 else: 229 encoder = encode_basestring 230 allow_nan = self.allow_nan 231 if self.sort_keys: 232 keys = dct.keys() 233 keys.sort() 234 items = [(k, dct[k]) for k in keys] 235 else: 236 items = dct.iteritems() 237 _encoding = self.encoding 238 _do_decode = (_encoding is not None 239 and not (_need_utf8 and _encoding == 'utf-8')) 240 for key, value in items: 241 if isinstance(key, str): 242 if _do_decode: 243 key = key.decode(_encoding) 244 elif isinstance(key, basestring): 245 pass 246 # JavaScript is weakly typed for these, so it makes sense to 247 # also allow them. Many encoders seem to do something like this. 248 elif isinstance(key, float): 249 key = floatstr(key, allow_nan) 250 elif isinstance(key, (int, long)): 251 key = str(key) 252 elif key is True: 253 key = 'true' 254 elif key is False: 255 key = 'false' 256 elif key is None: 257 key = 'null' 258 elif self.skipkeys: 259 continue 260 else: 261 raise TypeError("key %r is not a string" % (key,)) 262 if first: 263 first = False 264 else: 265 yield item_separator 266 yield encoder(key) 267 yield key_separator 268 for chunk in self._iterencode(value, markers): 269 yield chunk 270 if newline_indent is not None: 271 self.current_indent_level -= 1 272 yield self._newline_indent() 273 yield '}' 274 if markers is not None: 275 del markers[markerid]
276
277 - def _iterencode(self, o, markers=None):
278 if isinstance(o, basestring): 279 if self.ensure_ascii: 280 encoder = encode_basestring_ascii 281 else: 282 encoder = encode_basestring 283 _encoding = self.encoding 284 if (_encoding is not None and isinstance(o, str) 285 and not (_need_utf8 and _encoding == 'utf-8')): 286 o = o.decode(_encoding) 287 yield encoder(o) 288 elif o is None: 289 yield 'null' 290 elif o is True: 291 yield 'true' 292 elif o is False: 293 yield 'false' 294 elif isinstance(o, (int, long)): 295 yield str(o) 296 elif isinstance(o, float): 297 yield floatstr(o, self.allow_nan) 298 elif isinstance(o, (list, tuple)): 299 for chunk in self._iterencode_list(o, markers): 300 yield chunk 301 elif isinstance(o, dict): 302 for chunk in self._iterencode_dict(o, markers): 303 yield chunk 304 else: 305 if markers is not None: 306 markerid = id(o) 307 if markerid in markers: 308 raise ValueError("Circular reference detected") 309 markers[markerid] = o 310 for chunk in self._iterencode_default(o, markers): 311 yield chunk 312 if markers is not None: 313 del markers[markerid]
314
315 - def _iterencode_default(self, o, markers=None):
316 newobj = self.default(o) 317 return self._iterencode(newobj, markers)
318
319 - def default(self, o):
320 """ 321 Implement this method in a subclass such that it returns 322 a serializable object for ``o``, or calls the base implementation 323 (to raise a ``TypeError``). 324 325 For example, to support arbitrary iterators, you could 326 implement default like this:: 327 328 def default(self, o): 329 try: 330 iterable = iter(o) 331 except TypeError: 332 pass 333 else: 334 return list(iterable) 335 return JSONEncoder.default(self, o) 336 """ 337 raise TypeError("%r is not JSON serializable" % (o,))
338
339 - def encode(self, o):
340 """ 341 Return a JSON string representation of a Python data structure. 342 343 >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) 344 '{"foo":["bar", "baz"]}' 345 """ 346 # This is for extremely simple cases and benchmarks... 347 if isinstance(o, basestring): 348 if isinstance(o, str): 349 _encoding = self.encoding 350 if (_encoding is not None 351 and not (_encoding == 'utf-8' and _need_utf8)): 352 o = o.decode(_encoding) 353 return encode_basestring_ascii(o) 354 # This doesn't pass the iterator directly to ''.join() because it 355 # sucks at reporting exceptions. It's going to do this internally 356 # anyway because it uses PySequence_Fast or similar. 357 chunks = list(self.iterencode(o)) 358 return ''.join(chunks)
359
360 - def iterencode(self, o):
361 """ 362 Encode the given object and yield each string 363 representation as available. 364 365 For example:: 366 367 for chunk in JSONEncoder().iterencode(bigobject): 368 mysocket.write(chunk) 369 """ 370 if self.check_circular: 371 markers = {} 372 else: 373 markers = None 374 return self._iterencode(o, markers)
375 376 __all__ = ['JSONEncoder'] 377