0001"""
0002Implementation of JSONEncoder
0003"""
0004import re
0005
0006
0007INFCHARS = re.compile(r'[infINF]')
0008ESCAPE = re.compile(r'[\x00-\x19\\"\b\f\n\r\t]')
0009ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
0010ESCAPE_DCT = {
0011 '\\': '\\\\',
0012 '"': '\\"',
0013 '\b': '\\b',
0014 '\f': '\\f',
0015 '\n': '\\n',
0016 '\r': '\\r',
0017 '\t': '\\t',
0018}
0019for i in range(20):
0020 ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
0021
0022def floatstr(o, allow_nan=True):
0023 s = str(o)
0024
0025 if (o < 0.0 and s[1].isdigit()) or s[0].isdigit():
0026 return s
0027 elif not allow_nan:
0028 raise ValueError("Out of range float values are not JSON compliant: %r"
0029 % (o,))
0030
0031 if s == 'nan':
0032 return 'NaN'
0033 if s == 'inf':
0034 return 'Infinity'
0035 if s == '-inf':
0036 return '-Infinity'
0037
0038 if o != o or o == 0.0:
0039 return 'NaN'
0040
0041 if o < 0:
0042 return '-Infinity'
0043 return 'Infinity'
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 def __init__(self, skipkeys=False, ensure_ascii=True,
0094 check_circular=True, allow_nan=True, sort_keys=False):
0095 """
0096 Constructor for JSONEncoder, with sensible defaults.
0097
0098 If skipkeys is False, then it is a TypeError to attempt
0099 encoding of keys that are not str, int, long, float or None. If
0100 skipkeys is True, such items are simply skipped.
0101
0102 If ensure_ascii is True, the output is guaranteed to be str
0103 objects with all incoming unicode characters escaped. If
0104 ensure_ascii is false, the output will be unicode object.
0105
0106 If check_circular is True, then lists, dicts, and custom encoded
0107 objects will be checked for circular references during encoding to
0108 prevent an infinite recursion (which would cause an OverflowError).
0109 Otherwise, no such check takes place.
0110
0111 If allow_nan is True, then NaN, Infinity, and -Infinity will be
0112 encoded as such. This behavior is not JSON specification compliant,
0113 but is consistent with most JavaScript based encoders and decoders.
0114 Otherwise, it will be a ValueError to encode such floats.
0115
0116 If sort_keys is True, then the output of dictionaries will be
0117 sorted by key; this is useful for regression tests to ensure
0118 that JSON serializations can be compared on a day-to-day basis.
0119 """
0120
0121 self.skipkeys = skipkeys
0122 self.ensure_ascii = ensure_ascii
0123 self.check_circular = check_circular
0124 self.allow_nan = allow_nan
0125 self.sort_keys = sort_keys
0126
0127 def _iterencode_list(self, lst, markers=None):
0128 if not lst:
0129 yield '[]'
0130 return
0131 if markers is not None:
0132 markerid = id(lst)
0133 if markerid in markers:
0134 raise ValueError("Circular reference detected")
0135 markers[markerid] = lst
0136 yield '['
0137 first = True
0138 for value in lst:
0139 if first:
0140 first = False
0141 else:
0142 yield ', '
0143 for chunk in self._iterencode(value, markers):
0144 yield chunk
0145 yield ']'
0146 if markers is not None:
0147 del markers[markerid]
0148
0149 def _iterencode_dict(self, dct, markers=None):
0150 if not dct:
0151 yield '{}'
0152 return
0153 if markers is not None:
0154 markerid = id(dct)
0155 if markerid in markers:
0156 raise ValueError("Circular reference detected")
0157 markers[markerid] = dct
0158 yield '{'
0159 first = True
0160 if self.ensure_ascii:
0161 encoder = encode_basestring_ascii
0162 else:
0163 encoder = encode_basestring
0164 allow_nan = self.allow_nan
0165 if self.sort_keys:
0166 keys = dct.keys()
0167 keys.sort()
0168 items = [(k,dct[k]) for k in keys]
0169 else:
0170 items = dct.iteritems()
0171 for key, value in items:
0172 if isinstance(key, basestring):
0173 pass
0174
0175
0176 elif isinstance(key, float):
0177 key = floatstr(key, allow_nan)
0178 elif isinstance(key, (int, long)):
0179 key = str(key)
0180 elif key is True:
0181 key = 'true'
0182 elif key is False:
0183 key = 'false'
0184 elif key is None:
0185 key = 'null'
0186 elif self.skipkeys:
0187 continue
0188 else:
0189 raise TypeError("key %r is not a string" % (key,))
0190 if first:
0191 first = False
0192 else:
0193 yield ', '
0194 yield encoder(key)
0195 yield ': '
0196 for chunk in self._iterencode(value, markers):
0197 yield chunk
0198 yield '}'
0199 if markers is not None:
0200 del markers[markerid]
0201
0202 def _iterencode(self, o, markers=None):
0203 if isinstance(o, basestring):
0204 if self.ensure_ascii:
0205 encoder = encode_basestring_ascii
0206 else:
0207 encoder = encode_basestring
0208 yield encoder(o)
0209 elif o is None:
0210 yield 'null'
0211 elif o is True:
0212 yield 'true'
0213 elif o is False:
0214 yield 'false'
0215 elif isinstance(o, (int, long)):
0216 yield str(o)
0217 elif isinstance(o, float):
0218 yield floatstr(o, self.allow_nan)
0219 elif isinstance(o, (list, tuple)):
0220 for chunk in self._iterencode_list(o, markers):
0221 yield chunk
0222 elif isinstance(o, dict):
0223 for chunk in self._iterencode_dict(o, markers):
0224 yield chunk
0225 else:
0226 if markers is not None:
0227 markerid = id(o)
0228 if markerid in markers:
0229 raise ValueError("Circular reference detected")
0230 markers[markerid] = o
0231 for chunk in self._iterencode_default(o, markers):
0232 yield chunk
0233 if markers is not None:
0234 del markers[markerid]
0235
0236 def _iterencode_default(self, o, markers=None):
0237 newobj = self.default(o)
0238 return self._iterencode(newobj, markers)
0239
0240 def default(self, o):
0241 """
0242 Implement this method in a subclass such that it returns
0243 a serializable object for ``o``, or calls the base implementation
0244 (to raise a ``TypeError``).
0245
0246 For example, to support arbitrary iterators, you could
0247 implement default like this::
0248
0249 def default(self, o):
0250 try:
0251 iterable = iter(o)
0252 except TypeError:
0253 pass
0254 else:
0255 return list(iterable)
0256 return JSONEncoder.default(self, o)
0257 """
0258 raise TypeError("%r is not JSON serializable" % (o,))
0259
0260 def encode(self, o):
0261 """
0262 Return a JSON string representation of a Python data structure.
0263
0264 >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
0265 '{"foo":["bar", "baz"]}'
0266 """
0267
0268
0269
0270 chunks = list(self.iterencode(o))
0271 return ''.join(chunks)
0272
0273 def iterencode(self, o):
0274 """
0275 Encode the given object and yield each string
0276 representation as available.
0277
0278 For example::
0279
0280 for chunk in JSONEncoder().iterencode(bigobject):
0281 mysocket.write(chunk)
0282 """
0283 if self.check_circular:
0284 markers = {}
0285 else:
0286 markers = None
0287 return self._iterencode(o, markers)
0288
0289__all__ = ['JSONEncoder']