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, check_circular=True,
0094 allow_nan=True):
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 ensure_ascii
0104 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
0117 self.skipkeys = skipkeys
0118 self.ensure_ascii = ensure_ascii
0119 self.check_circular = check_circular
0120 self.allow_nan = allow_nan
0121
0122 def _iterencode_list(self, lst, markers=None):
0123 if not lst:
0124 yield '[]'
0125 return
0126 if markers is not None:
0127 markerid = id(lst)
0128 if markerid in markers:
0129 raise ValueError("Circular reference detected")
0130 markers[markerid] = lst
0131 yield '['
0132 first = True
0133 for value in lst:
0134 if first:
0135 first = False
0136 else:
0137 yield ', '
0138 for chunk in self._iterencode(value, markers):
0139 yield chunk
0140 yield ']'
0141 if markers is not None:
0142 del markers[markerid]
0143
0144 def _iterencode_dict(self, dct, markers=None):
0145 if not dct:
0146 yield '{}'
0147 return
0148 if markers is not None:
0149 markerid = id(dct)
0150 if markerid in markers:
0151 raise ValueError("Circular reference detected")
0152 markers[markerid] = dct
0153 yield '{'
0154 first = True
0155 if self.ensure_ascii:
0156 encoder = encode_basestring_ascii
0157 else:
0158 encoder = encode_basestring
0159 allow_nan = self.allow_nan
0160 for key, value in dct.iteritems():
0161 if isinstance(key, basestring):
0162 pass
0163
0164
0165 elif isinstance(key, float):
0166 key = floatstr(key, allow_nan)
0167 elif isinstance(key, (int, long)):
0168 key = str(key)
0169 elif key is True:
0170 key = 'true'
0171 elif key is False:
0172 key = 'false'
0173 elif key is None:
0174 key = 'null'
0175 elif self.skipkeys:
0176 continue
0177 else:
0178 raise TypeError("key %r is not a string" % (key,))
0179 if first:
0180 first = False
0181 else:
0182 yield ', '
0183 yield encoder(key)
0184 yield ':'
0185 for chunk in self._iterencode(value, markers):
0186 yield chunk
0187 yield '}'
0188 if markers is not None:
0189 del markers[markerid]
0190
0191 def _iterencode(self, o, markers=None):
0192 if isinstance(o, basestring):
0193 if self.ensure_ascii:
0194 encoder = encode_basestring_ascii
0195 else:
0196 encoder = encode_basestring
0197 yield encoder(o)
0198 elif o is None:
0199 yield 'null'
0200 elif o is True:
0201 yield 'true'
0202 elif o is False:
0203 yield 'false'
0204 elif isinstance(o, (int, long)):
0205 yield str(o)
0206 elif isinstance(o, float):
0207 yield floatstr(o, self.allow_nan)
0208 elif isinstance(o, (list, tuple)):
0209 for chunk in self._iterencode_list(o, markers):
0210 yield chunk
0211 elif isinstance(o, dict):
0212 for chunk in self._iterencode_dict(o, markers):
0213 yield chunk
0214 else:
0215 if markers is not None:
0216 markerid = id(o)
0217 if markerid in markers:
0218 raise ValueError("Circular reference detected")
0219 markers[markerid] = o
0220 for chunk in self._iterencode_default(o, markers):
0221 yield chunk
0222 if markers is not None:
0223 del markers[markerid]
0224
0225 def _iterencode_default(self, o, markers=None):
0226 newobj = self.default(o)
0227 return self._iterencode(newobj, markers)
0228
0229 def default(self, o):
0230 """
0231 Implement this method in a subclass such that it returns
0232 a serializable object for ``o``, or calls the base implementation
0233 (to raise a ``TypeError``).
0234
0235 For example, to support arbitrary iterators, you could
0236 implement default like this::
0237
0238 def default(self, o):
0239 try:
0240 iterable = iter(o)
0241 except TypeError:
0242 pass
0243 else:
0244 return list(iterable)
0245 return JSONEncoder.default(self, o)
0246 """
0247 raise TypeError("%r is not JSON serializable" % (o,))
0248
0249 def encode(self, o):
0250 """
0251 Return a JSON string representation of a Python data structure.
0252
0253 >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
0254 '{"foo":["bar", "baz"]}'
0255 """
0256
0257
0258
0259 chunks = list(self.iterencode(o))
0260 return ''.join(chunks)
0261
0262 def iterencode(self, o):
0263 """
0264 Encode the given object and yield each string
0265 representation as available.
0266
0267 For example::
0268
0269 for chunk in JSONEncoder().iterencode(bigobject):
0270 mysocket.write(chunk)
0271 """
0272 if self.check_circular:
0273 markers = {}
0274 else:
0275 markers = None
0276 return self._iterencode(o, markers)
0277
0278__all__ = ['JSONEncoder']