0001"""
0002Implementation of JSONEncoder
0003"""
0004import re
0005
0006ESCAPE = re.compile(r'[\x00-\x19\\"\b\f\n\r\t]')
0007ESCAPE_ASCII = re.compile(r'([\\"/]|[^\ -~])')
0008ESCAPE_DCT = {
0009
0010 '/': '\\/',
0011 '\\': '\\\\',
0012 '"': '\\"',
0013 '\b': '\\b',
0014 '\f': '\\f',
0015 '\n': '\\n',
0016 '\r': '\\r',
0017 '\t': '\\t',
0018}
0019for i in range(0x20):
0020 ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
0021
0022
0023INFINITY = float('1e66666')
0024
0025def floatstr(o, allow_nan=True):
0026
0027
0028
0029 if o != o:
0030 text = 'NaN'
0031 elif o == INFINITY:
0032 text = 'Infinity'
0033 elif o == -INFINITY:
0034 text = '-Infinity'
0035 else:
0036 return str(o)
0037
0038 if not allow_nan:
0039 raise ValueError("Out of range float values are not JSON compliant: %r"
0040 % (o,))
0041
0042 return text
0043
0044
0045def encode_basestring(s):
0046 """
0047 Return a JSON representation of a Python string
0048 """
0049 def replace(match):
0050 return ESCAPE_DCT[match.group(0)]
0051 return '"' + ESCAPE.sub(replace, s) + '"'
0052
0053def encode_basestring_ascii(s):
0054 def replace(match):
0055 s = match.group(0)
0056 try:
0057 return ESCAPE_DCT[s]
0058 except KeyError:
0059 return '\\u%04x' % (ord(s),)
0060 return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
0061
0062
0063class JSONEncoder(object):
0064 """
0065 Extensible JSON <http://json.org> encoder for Python data structures.
0066
0067 Supports the following objects and types by default:
0068
0069 +-------------------+---------------+
0070 | Python | JSON |
0071 +===================+===============+
0072 | dict | object |
0073 +-------------------+---------------+
0074 | list, tuple | array |
0075 +-------------------+---------------+
0076 | str, unicode | string |
0077 +-------------------+---------------+
0078 | int, long, float | number |
0079 +-------------------+---------------+
0080 | True | true |
0081 +-------------------+---------------+
0082 | False | false |
0083 +-------------------+---------------+
0084 | None | null |
0085 +-------------------+---------------+
0086
0087 To extend this to recognize other objects, subclass and implement a
0088 ``.default()`` method with another method that returns a serializable
0089 object for ``o`` if possible, otherwise it should call the superclass
0090 implementation (to raise ``TypeError``).
0091 """
0092 __all__ = ['__init__', 'default', 'encode', 'iterencode']
0093 item_separator = ', '
0094 key_separator = ': '
0095 def __init__(self, skipkeys=False, ensure_ascii=True,
0096 check_circular=True, allow_nan=True, sort_keys=False,
0097 indent=None, separators=None):
0098 """
0099 Constructor for JSONEncoder, with sensible defaults.
0100
0101 If skipkeys is False, then it is a TypeError to attempt
0102 encoding of keys that are not str, int, long, float or None. If
0103 skipkeys is True, such items are simply skipped.
0104
0105 If ensure_ascii is True, the output is guaranteed to be str
0106 objects with all incoming unicode characters escaped. If
0107 ensure_ascii is false, the output will be unicode object.
0108
0109 If check_circular is True, then lists, dicts, and custom encoded
0110 objects will be checked for circular references during encoding to
0111 prevent an infinite recursion (which would cause an OverflowError).
0112 Otherwise, no such check takes place.
0113
0114 If allow_nan is True, then NaN, Infinity, and -Infinity will be
0115 encoded as such. This behavior is not JSON specification compliant,
0116 but is consistent with most JavaScript based encoders and decoders.
0117 Otherwise, it will be a ValueError to encode such floats.
0118
0119 If sort_keys is True, then the output of dictionaries will be
0120 sorted by key; this is useful for regression tests to ensure
0121 that JSON serializations can be compared on a day-to-day basis.
0122
0123 If indent is a non-negative integer, then JSON array
0124 elements and object members will be pretty-printed with that
0125 indent level. An indent level of 0 will only insert newlines.
0126 None is the most compact representation.
0127
0128 If specified, separators should be a (item_separator, key_separator)
0129 tuple. The default is (', ', ': '). To get the most compact JSON
0130 representation you should specify (',', ':') to eliminate whitespace.
0131 """
0132
0133 self.skipkeys = skipkeys
0134 self.ensure_ascii = ensure_ascii
0135 self.check_circular = check_circular
0136 self.allow_nan = allow_nan
0137 self.sort_keys = sort_keys
0138 self.indent = indent
0139 self.current_indent_level = 0
0140 if separators is not None:
0141 self.item_separator, self.key_separator = separators
0142
0143 def _newline_indent(self):
0144 return '\n' + (' ' * (self.indent * self.current_indent_level))
0145
0146 def _iterencode_list(self, lst, markers=None):
0147 if not lst:
0148 yield '[]'
0149 return
0150 if markers is not None:
0151 markerid = id(lst)
0152 if markerid in markers:
0153 raise ValueError("Circular reference detected")
0154 markers[markerid] = lst
0155 yield '['
0156 if self.indent is not None:
0157 self.current_indent_level += 1
0158 newline_indent = self._newline_indent()
0159 separator = self.item_separator + newline_indent
0160 yield newline_indent
0161 else:
0162 newline_indent = None
0163 separator = self.item_separator
0164 first = True
0165 for value in lst:
0166 if first:
0167 first = False
0168 else:
0169 yield separator
0170 for chunk in self._iterencode(value, markers):
0171 yield chunk
0172 if newline_indent is not None:
0173 self.current_indent_level -= 1
0174 yield self._newline_indent()
0175 yield ']'
0176 if markers is not None:
0177 del markers[markerid]
0178
0179 def _iterencode_dict(self, dct, markers=None):
0180 if not dct:
0181 yield '{}'
0182 return
0183 if markers is not None:
0184 markerid = id(dct)
0185 if markerid in markers:
0186 raise ValueError("Circular reference detected")
0187 markers[markerid] = dct
0188 yield '{'
0189 key_separator = self.key_separator
0190 if self.indent is not None:
0191 self.current_indent_level += 1
0192 newline_indent = self._newline_indent()
0193 item_separator = self.item_separator + newline_indent
0194 yield newline_indent
0195 else:
0196 newline_indent = None
0197 item_separator = self.item_separator
0198 first = True
0199 if self.ensure_ascii:
0200 encoder = encode_basestring_ascii
0201 else:
0202 encoder = encode_basestring
0203 allow_nan = self.allow_nan
0204 if self.sort_keys:
0205 keys = dct.keys()
0206 keys.sort()
0207 items = [(k, dct[k]) for k in keys]
0208 else:
0209 items = dct.iteritems()
0210 for key, value in items:
0211 if isinstance(key, basestring):
0212 pass
0213
0214
0215 elif isinstance(key, float):
0216 key = floatstr(key, allow_nan)
0217 elif isinstance(key, (int, long)):
0218 key = str(key)
0219 elif key is True:
0220 key = 'true'
0221 elif key is False:
0222 key = 'false'
0223 elif key is None:
0224 key = 'null'
0225 elif self.skipkeys:
0226 continue
0227 else:
0228 raise TypeError("key %r is not a string" % (key,))
0229 if first:
0230 first = False
0231 else:
0232 yield item_separator
0233 yield encoder(key)
0234 yield key_separator
0235 for chunk in self._iterencode(value, markers):
0236 yield chunk
0237 if newline_indent is not None:
0238 self.current_indent_level -= 1
0239 yield self._newline_indent()
0240 yield '}'
0241 if markers is not None:
0242 del markers[markerid]
0243
0244 def _iterencode(self, o, markers=None):
0245 if isinstance(o, basestring):
0246 if self.ensure_ascii:
0247 encoder = encode_basestring_ascii
0248 else:
0249 encoder = encode_basestring
0250 yield encoder(o)
0251 elif o is None:
0252 yield 'null'
0253 elif o is True:
0254 yield 'true'
0255 elif o is False:
0256 yield 'false'
0257 elif isinstance(o, (int, long)):
0258 yield str(o)
0259 elif isinstance(o, float):
0260 yield floatstr(o, self.allow_nan)
0261 elif isinstance(o, (list, tuple)):
0262 for chunk in self._iterencode_list(o, markers):
0263 yield chunk
0264 elif isinstance(o, dict):
0265 for chunk in self._iterencode_dict(o, markers):
0266 yield chunk
0267 else:
0268 if markers is not None:
0269 markerid = id(o)
0270 if markerid in markers:
0271 raise ValueError("Circular reference detected")
0272 markers[markerid] = o
0273 for chunk in self._iterencode_default(o, markers):
0274 yield chunk
0275 if markers is not None:
0276 del markers[markerid]
0277
0278 def _iterencode_default(self, o, markers=None):
0279 newobj = self.default(o)
0280 return self._iterencode(newobj, markers)
0281
0282 def default(self, o):
0283 """
0284 Implement this method in a subclass such that it returns
0285 a serializable object for ``o``, or calls the base implementation
0286 (to raise a ``TypeError``).
0287
0288 For example, to support arbitrary iterators, you could
0289 implement default like this::
0290
0291 def default(self, o):
0292 try:
0293 iterable = iter(o)
0294 except TypeError:
0295 pass
0296 else:
0297 return list(iterable)
0298 return JSONEncoder.default(self, o)
0299 """
0300 raise TypeError("%r is not JSON serializable" % (o,))
0301
0302 def encode(self, o):
0303 """
0304 Return a JSON string representation of a Python data structure.
0305
0306 >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
0307 '{"foo":["bar", "baz"]}'
0308 """
0309
0310
0311
0312 chunks = list(self.iterencode(o))
0313 return ''.join(chunks)
0314
0315 def iterencode(self, o):
0316 """
0317 Encode the given object and yield each string
0318 representation as available.
0319
0320 For example::
0321
0322 for chunk in JSONEncoder().iterencode(bigobject):
0323 mysocket.write(chunk)
0324 """
0325 if self.check_circular:
0326 markers = {}
0327 else:
0328 markers = None
0329 return self._iterencode(o, markers)
0330
0331__all__ = ['JSONEncoder']