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
25 INFINITY = float('1e66666')
26 FLOAT_REPR = repr
27
29
30
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
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
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
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
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
171 return '\n' + (' ' * (self.indent * self.current_indent_level))
172
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
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
247
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
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
318
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
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
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
355
356
357 chunks = list(self.iterencode(o))
358 return ''.join(chunks)
359
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