Ticket #3320: ticket-3320.diff
File ticket-3320.diff, 33.9 KB (added by , 18 years ago) |
---|
-
django/utils/simplejson/LICENSE.txt
a b 1 Copyright (c) 2006 Bob Ippolito 2 3 Permission is hereby granted, free of charge, to any person obtaining a copy of 4 this software and associated documentation files (the "Software"), to deal in 5 the Software without restriction, including without limitation the rights to 6 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 of the Software, and to permit persons to whom the Software is furnished to do 8 so, subject to the following conditions: 9 10 The above copyright notice and this permission notice shall be included in all 11 copies or substantial portions of the Software. 12 13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 SOFTWARE. -
django/utils/simplejson/__init__.py
diff --git a/django/utils/simplejson/__init__.py b/django/utils/simplejson/__init__.py index f88329b..5c79ccf 100644
a b 1 r""" 2 A simple, fast, extensible JSON encoder and decoder 3 4 JSON (JavaScript Object Notation) <http://json.org> is a subset of 5 JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data 6 interchange format. 7 8 simplejson exposes an API familiar to uses of the standard library 9 marshal and pickle modules. 10 11 Encoding basic Python object hierarchies:: 12 13 >>> import simplejson 14 >>> simplejson.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) 15 '["foo", {"bar": ["baz", null, 1.0, 2]}]' 16 >>> print simplejson.dumps("\"foo\bar") 17 "\"foo\bar" 18 >>> print simplejson.dumps(u'\u1234') 19 "\u1234" 20 >>> print simplejson.dumps('\\') 21 "\\" 22 >>> print simplejson.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) 23 {"a": 0, "b": 0, "c": 0} 24 >>> from StringIO import StringIO 25 >>> io = StringIO() 26 >>> simplejson.dump(['streaming API'], io) 27 >>> io.getvalue() 28 '["streaming API"]' 29 30 Compact encoding:: 31 32 >>> import simplejson 33 >>> simplejson.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) 34 '[1,2,3,{"4":5,"6":7}]' 35 36 Pretty printing:: 37 38 >>> import simplejson 39 >>> print simplejson.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4) 40 { 41 "4": 5, 42 "6": 7 43 } 44 45 Decoding JSON:: 46 47 >>> import simplejson 48 >>> simplejson.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') 49 [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] 50 >>> simplejson.loads('"\\"foo\\bar"') 51 u'"foo\x08ar' 52 >>> from StringIO import StringIO 53 >>> io = StringIO('["streaming API"]') 54 >>> simplejson.load(io) 55 [u'streaming API'] 56 57 Specializing JSON object decoding:: 58 59 >>> import simplejson 60 >>> def as_complex(dct): 61 ... if '__complex__' in dct: 62 ... return complex(dct['real'], dct['imag']) 63 ... return dct 64 ... 65 >>> simplejson.loads('{"__complex__": true, "real": 1, "imag": 2}', 66 ... object_hook=as_complex) 67 (1+2j) 68 69 Extending JSONEncoder:: 70 71 >>> import simplejson 72 >>> class ComplexEncoder(simplejson.JSONEncoder): 73 ... def default(self, obj): 74 ... if isinstance(obj, complex): 75 ... return [obj.real, obj.imag] 76 ... return simplejson.JSONEncoder.default(self, obj) 77 ... 78 >>> dumps(2 + 1j, cls=ComplexEncoder) 79 '[2.0, 1.0]' 80 >>> ComplexEncoder().encode(2 + 1j) 81 '[2.0, 1.0]' 82 >>> list(ComplexEncoder().iterencode(2 + 1j)) 83 ['[', '2.0', ', ', '1.0', ']'] 84 85 86 Note that the JSON produced by this module's default settings 87 is a subset of YAML, so it may be used as a serializer for that as well. 88 """ 89 __version__ = '1.5' 90 __all__ = [ 91 'dump', 'dumps', 'load', 'loads', 92 'JSONDecoder', 'JSONEncoder', 93 ] 94 95 from decoder import JSONDecoder 96 from encoder import JSONEncoder 97 98 def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, 99 allow_nan=True, cls=None, indent=None, **kw): 100 """ 101 Serialize ``obj`` as a JSON formatted stream to ``fp`` (a 102 ``.write()``-supporting file-like object). 103 104 If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types 105 (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) 106 will be skipped instead of raising a ``TypeError``. 107 108 If ``ensure_ascii`` is ``False``, then the some chunks written to ``fp`` 109 may be ``unicode`` instances, subject to normal Python ``str`` to 110 ``unicode`` coercion rules. Unless ``fp.write()`` explicitly 111 understands ``unicode`` (as in ``codecs.getwriter()``) this is likely 112 to cause an error. 113 114 If ``check_circular`` is ``False``, then the circular reference check 115 for container types will be skipped and a circular reference will 116 result in an ``OverflowError`` (or worse). 117 118 If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to 119 serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) 120 in strict compliance of the JSON specification, instead of using the 121 JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). 122 123 If ``indent`` is a non-negative integer, then JSON array elements and object 124 members will be pretty-printed with that indent level. An indent level 125 of 0 will only insert newlines. ``None`` is the most compact representation. 126 127 To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the 128 ``.default()`` method to serialize additional types), specify it with 129 the ``cls`` kwarg. 130 """ 131 if cls is None: 132 cls = JSONEncoder 133 iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, 134 check_circular=check_circular, allow_nan=allow_nan, indent=indent, 135 **kw).iterencode(obj) 136 # could accelerate with writelines in some versions of Python, at 137 # a debuggability cost 138 for chunk in iterable: 139 fp.write(chunk) 140 141 def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, 142 allow_nan=True, cls=None, indent=None, separators=None, **kw): 143 """ 144 Serialize ``obj`` to a JSON formatted ``str``. 145 146 If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types 147 (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) 148 will be skipped instead of raising a ``TypeError``. 149 150 If ``ensure_ascii`` is ``False``, then the return value will be a 151 ``unicode`` instance subject to normal Python ``str`` to ``unicode`` 152 coercion rules instead of being escaped to an ASCII ``str``. 153 154 If ``check_circular`` is ``False``, then the circular reference check 155 for container types will be skipped and a circular reference will 156 result in an ``OverflowError`` (or worse). 157 158 If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to 159 serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in 160 strict compliance of the JSON specification, instead of using the 161 JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). 162 163 If ``indent`` is a non-negative integer, then JSON array elements and 164 object members will be pretty-printed with that indent level. An indent 165 level of 0 will only insert newlines. ``None`` is the most compact 166 representation. 167 168 If ``separators`` is an ``(item_separator, dict_separator)`` tuple 169 then it will be used instead of the default ``(', ', ': ')`` separators. 170 ``(',', ':')`` is the most compact JSON representation. 171 172 To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the 173 ``.default()`` method to serialize additional types), specify it with 174 the ``cls`` kwarg. 175 """ 176 if cls is None: 177 cls = JSONEncoder 178 return cls( 179 skipkeys=skipkeys, ensure_ascii=ensure_ascii, 180 check_circular=check_circular, allow_nan=allow_nan, indent=indent, 181 separators=separators, 182 **kw).encode(obj) 183 184 def load(fp, encoding=None, cls=None, object_hook=None, **kw): 185 """ 186 Deserialize ``fp`` (a ``.read()``-supporting file-like object containing 187 a JSON document) to a Python object. 188 189 If the contents of ``fp`` is encoded with an ASCII based encoding other 190 than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must 191 be specified. Encodings that are not ASCII based (such as UCS-2) are 192 not allowed, and should be wrapped with 193 ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode`` 194 object and passed to ``loads()`` 195 196 ``object_hook`` is an optional function that will be called with the 197 result of any object literal decode (a ``dict``). The return value of 198 ``object_hook`` will be used instead of the ``dict``. This feature 199 can be used to implement custom decoders (e.g. JSON-RPC class hinting). 200 201 To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` 202 kwarg. 203 """ 204 if cls is None: 205 cls = JSONDecoder 206 if object_hook is not None: 207 kw['object_hook'] = object_hook 208 return cls(encoding=encoding, **kw).decode(fp.read()) 209 210 def loads(s, encoding=None, cls=None, object_hook=None, **kw): 211 """ 212 Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON 213 document) to a Python object. 214 215 If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding 216 other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name 217 must be specified. Encodings that are not ASCII based (such as UCS-2) 218 are not allowed and should be decoded to ``unicode`` first. 219 220 ``object_hook`` is an optional function that will be called with the 221 result of any object literal decode (a ``dict``). The return value of 222 ``object_hook`` will be used instead of the ``dict``. This feature 223 can be used to implement custom decoders (e.g. JSON-RPC class hinting). 224 225 To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` 226 kwarg. 227 """ 228 if cls is None: 229 cls = JSONDecoder 230 if object_hook is not None: 231 kw['object_hook'] = object_hook 232 return cls(encoding=encoding, **kw).decode(s) 233 234 def read(s): 235 """ 236 json-py API compatibility hook. Use loads(s) instead. 237 """ 238 import warnings 239 warnings.warn("simplejson.loads(s) should be used instead of read(s)", 240 DeprecationWarning) 241 return loads(s) 242 243 def write(obj): 244 """ 245 json-py API compatibility hook. Use dumps(s) instead. 246 """ 247 import warnings 248 warnings.warn("simplejson.dumps(s) should be used instead of write(s)", 249 DeprecationWarning) 250 return dumps(obj) 251 252 -
django/utils/simplejson/decoder.py
diff --git a/django/utils/simplejson/decoder.py b/django/utils/simplejson/decoder.py index 684af8c..a1b53b2 100644
a b 1 """ 2 Implementation of JSONDecoder 3 """ 4 import re 5 6 from simplejson.scanner import Scanner, pattern 7 8 FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL 9 10 def _floatconstants(): 11 import struct 12 import sys 13 _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') 14 if sys.byteorder != 'big': 15 _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1] 16 nan, inf = struct.unpack('dd', _BYTES) 17 return nan, inf, -inf 18 19 NaN, PosInf, NegInf = _floatconstants() 20 21 def linecol(doc, pos): 22 lineno = doc.count('\n', 0, pos) + 1 23 if lineno == 1: 24 colno = pos 25 else: 26 colno = pos - doc.rindex('\n', 0, pos) 27 return lineno, colno 28 29 def errmsg(msg, doc, pos, end=None): 30 lineno, colno = linecol(doc, pos) 31 if end is None: 32 return '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos) 33 endlineno, endcolno = linecol(doc, end) 34 return '%s: line %d column %d - line %d column %d (char %d - %d)' % ( 35 msg, lineno, colno, endlineno, endcolno, pos, end) 36 37 _CONSTANTS = { 38 '-Infinity': NegInf, 39 'Infinity': PosInf, 40 'NaN': NaN, 41 'true': True, 42 'false': False, 43 'null': None, 44 } 45 46 def JSONConstant(match, context, c=_CONSTANTS): 47 return c[match.group(0)], None 48 pattern('(-?Infinity|NaN|true|false|null)')(JSONConstant) 49 50 def JSONNumber(match, context): 51 match = JSONNumber.regex.match(match.string, *match.span()) 52 integer, frac, exp = match.groups() 53 if frac or exp: 54 res = float(integer + (frac or '') + (exp or '')) 55 else: 56 res = int(integer) 57 return res, None 58 pattern(r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?')(JSONNumber) 59 60 STRINGCHUNK = re.compile(r'(.*?)(["\\])', FLAGS) 61 BACKSLASH = { 62 '"': u'"', '\\': u'\\', '/': u'/', 63 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', 64 } 65 66 DEFAULT_ENCODING = "utf-8" 67 68 def scanstring(s, end, encoding=None, _b=BACKSLASH, _m=STRINGCHUNK.match): 69 if encoding is None: 70 encoding = DEFAULT_ENCODING 71 chunks = [] 72 _append = chunks.append 73 begin = end - 1 74 while 1: 75 chunk = _m(s, end) 76 if chunk is None: 77 raise ValueError( 78 errmsg("Unterminated string starting at", s, begin)) 79 end = chunk.end() 80 content, terminator = chunk.groups() 81 if content: 82 if not isinstance(content, unicode): 83 content = unicode(content, encoding) 84 _append(content) 85 if terminator == '"': 86 break 87 try: 88 esc = s[end] 89 except IndexError: 90 raise ValueError( 91 errmsg("Unterminated string starting at", s, begin)) 92 if esc != 'u': 93 try: 94 m = _b[esc] 95 except KeyError: 96 raise ValueError( 97 errmsg("Invalid \\escape: %r" % (esc,), s, end)) 98 end += 1 99 else: 100 esc = s[end + 1:end + 5] 101 try: 102 m = unichr(int(esc, 16)) 103 if len(esc) != 4 or not esc.isalnum(): 104 raise ValueError 105 except ValueError: 106 raise ValueError(errmsg("Invalid \\uXXXX escape", s, end)) 107 end += 5 108 _append(m) 109 return u''.join(chunks), end 110 111 def JSONString(match, context): 112 encoding = getattr(context, 'encoding', None) 113 return scanstring(match.string, match.end(), encoding) 114 pattern(r'"')(JSONString) 115 116 WHITESPACE = re.compile(r'\s*', FLAGS) 117 118 def JSONObject(match, context, _w=WHITESPACE.match): 119 pairs = {} 120 s = match.string 121 end = _w(s, match.end()).end() 122 nextchar = s[end:end + 1] 123 # trivial empty object 124 if nextchar == '}': 125 return pairs, end + 1 126 if nextchar != '"': 127 raise ValueError(errmsg("Expecting property name", s, end)) 128 end += 1 129 encoding = getattr(context, 'encoding', None) 130 iterscan = JSONScanner.iterscan 131 while True: 132 key, end = scanstring(s, end, encoding) 133 end = _w(s, end).end() 134 if s[end:end + 1] != ':': 135 raise ValueError(errmsg("Expecting : delimiter", s, end)) 136 end = _w(s, end + 1).end() 137 try: 138 value, end = iterscan(s, idx=end, context=context).next() 139 except StopIteration: 140 raise ValueError(errmsg("Expecting object", s, end)) 141 pairs[key] = value 142 end = _w(s, end).end() 143 nextchar = s[end:end + 1] 144 end += 1 145 if nextchar == '}': 146 break 147 if nextchar != ',': 148 raise ValueError(errmsg("Expecting , delimiter", s, end - 1)) 149 end = _w(s, end).end() 150 nextchar = s[end:end + 1] 151 end += 1 152 if nextchar != '"': 153 raise ValueError(errmsg("Expecting property name", s, end - 1)) 154 object_hook = getattr(context, 'object_hook', None) 155 if object_hook is not None: 156 pairs = object_hook(pairs) 157 return pairs, end 158 pattern(r'{')(JSONObject) 159 160 def JSONArray(match, context, _w=WHITESPACE.match): 161 values = [] 162 s = match.string 163 end = _w(s, match.end()).end() 164 # look-ahead for trivial empty array 165 nextchar = s[end:end + 1] 166 if nextchar == ']': 167 return values, end + 1 168 iterscan = JSONScanner.iterscan 169 while True: 170 try: 171 value, end = iterscan(s, idx=end, context=context).next() 172 except StopIteration: 173 raise ValueError(errmsg("Expecting object", s, end)) 174 values.append(value) 175 end = _w(s, end).end() 176 nextchar = s[end:end + 1] 177 end += 1 178 if nextchar == ']': 179 break 180 if nextchar != ',': 181 raise ValueError(errmsg("Expecting , delimiter", s, end)) 182 end = _w(s, end).end() 183 return values, end 184 pattern(r'\[')(JSONArray) 185 186 ANYTHING = [ 187 JSONObject, 188 JSONArray, 189 JSONString, 190 JSONConstant, 191 JSONNumber, 192 ] 193 194 JSONScanner = Scanner(ANYTHING) 195 196 class JSONDecoder(object): 197 """ 198 Simple JSON <http://json.org> decoder 199 200 Performs the following translations in decoding: 201 202 +---------------+-------------------+ 203 | JSON | Python | 204 +===============+===================+ 205 | object | dict | 206 +---------------+-------------------+ 207 | array | list | 208 +---------------+-------------------+ 209 | string | unicode | 210 +---------------+-------------------+ 211 | number (int) | int, long | 212 +---------------+-------------------+ 213 | number (real) | float | 214 +---------------+-------------------+ 215 | true | True | 216 +---------------+-------------------+ 217 | false | False | 218 +---------------+-------------------+ 219 | null | None | 220 +---------------+-------------------+ 221 222 It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as 223 their corresponding ``float`` values, which is outside the JSON spec. 224 """ 225 226 _scanner = Scanner(ANYTHING) 227 __all__ = ['__init__', 'decode', 'raw_decode'] 228 229 def __init__(self, encoding=None, object_hook=None): 230 """ 231 ``encoding`` determines the encoding used to interpret any ``str`` 232 objects decoded by this instance (utf-8 by default). It has no 233 effect when decoding ``unicode`` objects. 234 235 Note that currently only encodings that are a superset of ASCII work, 236 strings of other encodings should be passed in as ``unicode``. 237 238 ``object_hook``, if specified, will be called with the result 239 of every JSON object decoded and its return value will be used in 240 place of the given ``dict``. This can be used to provide custom 241 deserializations (e.g. to support JSON-RPC class hinting). 242 """ 243 self.encoding = encoding 244 self.object_hook = object_hook 245 246 def decode(self, s, _w=WHITESPACE.match): 247 """ 248 Return the Python representation of ``s`` (a ``str`` or ``unicode`` 249 instance containing a JSON document) 250 """ 251 obj, end = self.raw_decode(s, idx=_w(s, 0).end()) 252 end = _w(s, end).end() 253 if end != len(s): 254 raise ValueError(errmsg("Extra data", s, end, len(s))) 255 return obj 256 257 def raw_decode(self, s, **kw): 258 """ 259 Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning 260 with a JSON document) and return a 2-tuple of the Python 261 representation and the index in ``s`` where the document ended. 262 263 This can be used to decode a JSON document from a string that may 264 have extraneous data at the end. 265 """ 266 kw.setdefault('context', self) 267 try: 268 obj, end = self._scanner.iterscan(s, **kw).next() 269 except StopIteration: 270 raise ValueError("No JSON object could be decoded") 271 return obj, end 272 273 __all__ = ['JSONDecoder'] -
django/utils/simplejson/encoder.py
diff --git a/django/utils/simplejson/encoder.py b/django/utils/simplejson/encoder.py index bb1aba0..c83c687 100644
a b 1 """ 2 Implementation of JSONEncoder 3 """ 4 import re 5 6 ESCAPE = re.compile(r'[\x00-\x19\\"\b\f\n\r\t]') 7 ESCAPE_ASCII = re.compile(r'([\\"/]|[^\ -~])') 8 ESCAPE_DCT = { 9 # escape all forward slashes to prevent </script> attack 10 '/': '\\/', 11 '\\': '\\\\', 12 '"': '\\"', 13 '\b': '\\b', 14 '\f': '\\f', 15 '\n': '\\n', 16 '\r': '\\r', 17 '\t': '\\t', 18 } 19 for i in range(0x20): 20 ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) 21 22 # assume this produces an infinity on all machines (probably not guaranteed) 23 INFINITY = float('1e66666') 24 25 def floatstr(o, allow_nan=True): 26 # Check for specials. Note that this type of test is processor- and/or 27 # platform-specific, so do tests which don't depend on the internals. 28 29 if o != o: 30 text = 'NaN' 31 elif o == INFINITY: 32 text = 'Infinity' 33 elif o == -INFINITY: 34 text = '-Infinity' 35 else: 36 return str(o) 37 38 if not allow_nan: 39 raise ValueError("Out of range float values are not JSON compliant: %r" 40 % (o,)) 41 42 return text 43 44 45 def encode_basestring(s): 46 """ 47 Return a JSON representation of a Python string 48 """ 49 def replace(match): 50 return ESCAPE_DCT[match.group(0)] 51 return '"' + ESCAPE.sub(replace, s) + '"' 52 53 def encode_basestring_ascii(s): 54 def replace(match): 55 s = match.group(0) 56 try: 57 return ESCAPE_DCT[s] 58 except KeyError: 59 return '\\u%04x' % (ord(s),) 60 return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' 61 62 63 class JSONEncoder(object): 64 """ 65 Extensible JSON <http://json.org> encoder for Python data structures. 66 67 Supports the following objects and types by default: 68 69 +-------------------+---------------+ 70 | Python | JSON | 71 +===================+===============+ 72 | dict | object | 73 +-------------------+---------------+ 74 | list, tuple | array | 75 +-------------------+---------------+ 76 | str, unicode | string | 77 +-------------------+---------------+ 78 | int, long, float | number | 79 +-------------------+---------------+ 80 | True | true | 81 +-------------------+---------------+ 82 | False | false | 83 +-------------------+---------------+ 84 | None | null | 85 +-------------------+---------------+ 86 87 To extend this to recognize other objects, subclass and implement a 88 ``.default()`` method with another method that returns a serializable 89 object for ``o`` if possible, otherwise it should call the superclass 90 implementation (to raise ``TypeError``). 91 """ 92 __all__ = ['__init__', 'default', 'encode', 'iterencode'] 93 item_separator = ', ' 94 key_separator = ': ' 95 def __init__(self, skipkeys=False, ensure_ascii=True, 96 check_circular=True, allow_nan=True, sort_keys=False, 97 indent=None, separators=None): 98 """ 99 Constructor for JSONEncoder, with sensible defaults. 100 101 If skipkeys is False, then it is a TypeError to attempt 102 encoding of keys that are not str, int, long, float or None. If 103 skipkeys is True, such items are simply skipped. 104 105 If ensure_ascii is True, the output is guaranteed to be str 106 objects with all incoming unicode characters escaped. If 107 ensure_ascii is false, the output will be unicode object. 108 109 If check_circular is True, then lists, dicts, and custom encoded 110 objects will be checked for circular references during encoding to 111 prevent an infinite recursion (which would cause an OverflowError). 112 Otherwise, no such check takes place. 113 114 If allow_nan is True, then NaN, Infinity, and -Infinity will be 115 encoded as such. This behavior is not JSON specification compliant, 116 but is consistent with most JavaScript based encoders and decoders. 117 Otherwise, it will be a ValueError to encode such floats. 118 119 If sort_keys is True, then the output of dictionaries will be 120 sorted by key; this is useful for regression tests to ensure 121 that JSON serializations can be compared on a day-to-day basis. 122 123 If indent is a non-negative integer, then JSON array 124 elements and object members will be pretty-printed with that 125 indent level. An indent level of 0 will only insert newlines. 126 None is the most compact representation. 127 128 If specified, separators should be a (item_separator, key_separator) 129 tuple. The default is (', ', ': '). To get the most compact JSON 130 representation you should specify (',', ':') to eliminate whitespace. 131 """ 132 133 self.skipkeys = skipkeys 134 self.ensure_ascii = ensure_ascii 135 self.check_circular = check_circular 136 self.allow_nan = allow_nan 137 self.sort_keys = sort_keys 138 self.indent = indent 139 self.current_indent_level = 0 140 if separators is not None: 141 self.item_separator, self.key_separator = separators 142 143 def _newline_indent(self): 144 return '\n' + (' ' * (self.indent * self.current_indent_level)) 145 146 def _iterencode_list(self, lst, markers=None): 147 if not lst: 148 yield '[]' 149 return 150 if markers is not None: 151 markerid = id(lst) 152 if markerid in markers: 153 raise ValueError("Circular reference detected") 154 markers[markerid] = lst 155 yield '[' 156 if self.indent is not None: 157 self.current_indent_level += 1 158 newline_indent = self._newline_indent() 159 separator = self.item_separator + newline_indent 160 yield newline_indent 161 else: 162 newline_indent = None 163 separator = self.item_separator 164 first = True 165 for value in lst: 166 if first: 167 first = False 168 else: 169 yield separator 170 for chunk in self._iterencode(value, markers): 171 yield chunk 172 if newline_indent is not None: 173 self.current_indent_level -= 1 174 yield self._newline_indent() 175 yield ']' 176 if markers is not None: 177 del markers[markerid] 178 179 def _iterencode_dict(self, dct, markers=None): 180 if not dct: 181 yield '{}' 182 return 183 if markers is not None: 184 markerid = id(dct) 185 if markerid in markers: 186 raise ValueError("Circular reference detected") 187 markers[markerid] = dct 188 yield '{' 189 key_separator = self.key_separator 190 if self.indent is not None: 191 self.current_indent_level += 1 192 newline_indent = self._newline_indent() 193 item_separator = self.item_separator + newline_indent 194 yield newline_indent 195 else: 196 newline_indent = None 197 item_separator = self.item_separator 198 first = True 199 if self.ensure_ascii: 200 encoder = encode_basestring_ascii 201 else: 202 encoder = encode_basestring 203 allow_nan = self.allow_nan 204 if self.sort_keys: 205 keys = dct.keys() 206 keys.sort() 207 items = [(k, dct[k]) for k in keys] 208 else: 209 items = dct.iteritems() 210 for key, value in items: 211 if isinstance(key, basestring): 212 pass 213 # JavaScript is weakly typed for these, so it makes sense to 214 # also allow them. Many encoders seem to do something like this. 215 elif isinstance(key, float): 216 key = floatstr(key, allow_nan) 217 elif isinstance(key, (int, long)): 218 key = str(key) 219 elif key is True: 220 key = 'true' 221 elif key is False: 222 key = 'false' 223 elif key is None: 224 key = 'null' 225 elif self.skipkeys: 226 continue 227 else: 228 raise TypeError("key %r is not a string" % (key,)) 229 if first: 230 first = False 231 else: 232 yield item_separator 233 yield encoder(key) 234 yield key_separator 235 for chunk in self._iterencode(value, markers): 236 yield chunk 237 if newline_indent is not None: 238 self.current_indent_level -= 1 239 yield self._newline_indent() 240 yield '}' 241 if markers is not None: 242 del markers[markerid] 243 244 def _iterencode(self, o, markers=None): 245 if isinstance(o, basestring): 246 if self.ensure_ascii: 247 encoder = encode_basestring_ascii 248 else: 249 encoder = encode_basestring 250 yield encoder(o) 251 elif o is None: 252 yield 'null' 253 elif o is True: 254 yield 'true' 255 elif o is False: 256 yield 'false' 257 elif isinstance(o, (int, long)): 258 yield str(o) 259 elif isinstance(o, float): 260 yield floatstr(o, self.allow_nan) 261 elif isinstance(o, (list, tuple)): 262 for chunk in self._iterencode_list(o, markers): 263 yield chunk 264 elif isinstance(o, dict): 265 for chunk in self._iterencode_dict(o, markers): 266 yield chunk 267 else: 268 if markers is not None: 269 markerid = id(o) 270 if markerid in markers: 271 raise ValueError("Circular reference detected") 272 markers[markerid] = o 273 for chunk in self._iterencode_default(o, markers): 274 yield chunk 275 if markers is not None: 276 del markers[markerid] 277 278 def _iterencode_default(self, o, markers=None): 279 newobj = self.default(o) 280 return self._iterencode(newobj, markers) 281 282 def default(self, o): 283 """ 284 Implement this method in a subclass such that it returns 285 a serializable object for ``o``, or calls the base implementation 286 (to raise a ``TypeError``). 287 288 For example, to support arbitrary iterators, you could 289 implement default like this:: 290 291 def default(self, o): 292 try: 293 iterable = iter(o) 294 except TypeError: 295 pass 296 else: 297 return list(iterable) 298 return JSONEncoder.default(self, o) 299 """ 300 raise TypeError("%r is not JSON serializable" % (o,)) 301 302 def encode(self, o): 303 """ 304 Return a JSON string representation of a Python data structure. 305 306 >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) 307 '{"foo":["bar", "baz"]}' 308 """ 309 # This doesn't pass the iterator directly to ''.join() because it 310 # sucks at reporting exceptions. It's going to do this internally 311 # anyway because it uses PySequence_Fast or similar. 312 chunks = list(self.iterencode(o)) 313 return ''.join(chunks) 314 315 def iterencode(self, o): 316 """ 317 Encode the given object and yield each string 318 representation as available. 319 320 For example:: 321 322 for chunk in JSONEncoder().iterencode(bigobject): 323 mysocket.write(chunk) 324 """ 325 if self.check_circular: 326 markers = {} 327 else: 328 markers = None 329 return self._iterencode(o, markers) 330 331 __all__ = ['JSONEncoder'] -
django/utils/simplejson/scanner.py
diff --git a/django/utils/simplejson/scanner.py b/django/utils/simplejson/scanner.py index b9244cf..64f4999 100644
a b 1 """ 2 Iterator based sre token scanner 3 """ 4 import sre_parse, sre_compile, sre_constants 5 from sre_constants import BRANCH, SUBPATTERN 6 from re import VERBOSE, MULTILINE, DOTALL 7 import re 8 9 __all__ = ['Scanner', 'pattern'] 10 11 FLAGS = (VERBOSE | MULTILINE | DOTALL) 12 class Scanner(object): 13 def __init__(self, lexicon, flags=FLAGS): 14 self.actions = [None] 15 # combine phrases into a compound pattern 16 s = sre_parse.Pattern() 17 s.flags = flags 18 p = [] 19 for idx, token in enumerate(lexicon): 20 phrase = token.pattern 21 try: 22 subpattern = sre_parse.SubPattern(s, 23 [(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))]) 24 except sre_constants.error: 25 raise 26 p.append(subpattern) 27 self.actions.append(token) 28 29 p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) 30 self.scanner = sre_compile.compile(p) 31 32 33 def iterscan(self, string, idx=0, context=None): 34 """ 35 Yield match, end_idx for each match 36 """ 37 match = self.scanner.scanner(string, idx).match 38 actions = self.actions 39 lastend = idx 40 end = len(string) 41 while True: 42 m = match() 43 if m is None: 44 break 45 matchbegin, matchend = m.span() 46 if lastend == matchend: 47 break 48 action = actions[m.lastindex] 49 if action is not None: 50 rval, next_pos = action(m, context) 51 if next_pos is not None and next_pos != matchend: 52 # "fast forward" the scanner 53 matchend = next_pos 54 match = self.scanner.scanner(string, matchend).match 55 yield rval, matchend 56 lastend = matchend 57 58 def pattern(pattern, flags=FLAGS): 59 def decorator(fn): 60 fn.pattern = pattern 61 fn.regex = re.compile(pattern, flags) 62 return fn 63 return decorator