Index: src/third_party/pylib/simplejson/encoder.py |
=================================================================== |
--- src/third_party/pylib/simplejson/encoder.py (revision 9275) |
+++ src/third_party/pylib/simplejson/encoder.py (working copy) |
@@ -1,501 +0,0 @@ |
-"""Implementation of JSONEncoder |
-""" |
-import re |
-from decimal import Decimal |
- |
-def _import_speedups(): |
- try: |
- from simplejson import _speedups |
- return _speedups.encode_basestring_ascii, _speedups.make_encoder |
- except ImportError: |
- return None, None |
-c_encode_basestring_ascii, c_make_encoder = _import_speedups() |
- |
-from simplejson.decoder import PosInf |
- |
-ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') |
-ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') |
-HAS_UTF8 = re.compile(r'[\x80-\xff]') |
-ESCAPE_DCT = { |
- '\\': '\\\\', |
- '"': '\\"', |
- '\b': '\\b', |
- '\f': '\\f', |
- '\n': '\\n', |
- '\r': '\\r', |
- '\t': '\\t', |
-} |
-for i in range(0x20): |
- #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) |
- ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) |
- |
-FLOAT_REPR = repr |
- |
-def encode_basestring(s): |
- """Return a JSON representation of a Python string |
- |
- """ |
- if isinstance(s, str) and HAS_UTF8.search(s) is not None: |
- s = s.decode('utf-8') |
- def replace(match): |
- return ESCAPE_DCT[match.group(0)] |
- return u'"' + ESCAPE.sub(replace, s) + u'"' |
- |
- |
-def py_encode_basestring_ascii(s): |
- """Return an ASCII-only JSON representation of a Python string |
- |
- """ |
- if isinstance(s, str) and HAS_UTF8.search(s) is not None: |
- s = s.decode('utf-8') |
- def replace(match): |
- s = match.group(0) |
- try: |
- return ESCAPE_DCT[s] |
- except KeyError: |
- n = ord(s) |
- if n < 0x10000: |
- #return '\\u{0:04x}'.format(n) |
- return '\\u%04x' % (n,) |
- else: |
- # surrogate pair |
- n -= 0x10000 |
- s1 = 0xd800 | ((n >> 10) & 0x3ff) |
- s2 = 0xdc00 | (n & 0x3ff) |
- #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) |
- return '\\u%04x\\u%04x' % (s1, s2) |
- return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' |
- |
- |
-encode_basestring_ascii = ( |
- c_encode_basestring_ascii or py_encode_basestring_ascii) |
- |
-class JSONEncoder(object): |
- """Extensible JSON <http://json.org> encoder for Python data structures. |
- |
- Supports the following objects and types by default: |
- |
- +-------------------+---------------+ |
- | Python | JSON | |
- +===================+===============+ |
- | dict | object | |
- +-------------------+---------------+ |
- | list, tuple | array | |
- +-------------------+---------------+ |
- | str, unicode | string | |
- +-------------------+---------------+ |
- | int, long, float | number | |
- +-------------------+---------------+ |
- | True | true | |
- +-------------------+---------------+ |
- | False | false | |
- +-------------------+---------------+ |
- | None | null | |
- +-------------------+---------------+ |
- |
- To extend this to recognize other objects, subclass and implement a |
- ``.default()`` method with another method that returns a serializable |
- object for ``o`` if possible, otherwise it should call the superclass |
- implementation (to raise ``TypeError``). |
- |
- """ |
- item_separator = ', ' |
- key_separator = ': ' |
- def __init__(self, skipkeys=False, ensure_ascii=True, |
- check_circular=True, allow_nan=True, sort_keys=False, |
- indent=None, separators=None, encoding='utf-8', default=None, |
- use_decimal=False): |
- """Constructor for JSONEncoder, with sensible defaults. |
- |
- If skipkeys is false, then it is a TypeError to attempt |
- encoding of keys that are not str, int, long, float or None. If |
- skipkeys is True, such items are simply skipped. |
- |
- If ensure_ascii is true, the output is guaranteed to be str |
- objects with all incoming unicode characters escaped. If |
- ensure_ascii is false, the output will be unicode object. |
- |
- If check_circular is true, then lists, dicts, and custom encoded |
- objects will be checked for circular references during encoding to |
- prevent an infinite recursion (which would cause an OverflowError). |
- Otherwise, no such check takes place. |
- |
- If allow_nan is true, then NaN, Infinity, and -Infinity will be |
- encoded as such. This behavior is not JSON specification compliant, |
- but is consistent with most JavaScript based encoders and decoders. |
- Otherwise, it will be a ValueError to encode such floats. |
- |
- If sort_keys is true, then the output of dictionaries will be |
- sorted by key; this is useful for regression tests to ensure |
- that JSON serializations can be compared on a day-to-day basis. |
- |
- If indent is a string, then JSON array elements and object members |
- will be pretty-printed with a newline followed by that string repeated |
- for each level of nesting. ``None`` (the default) selects the most compact |
- representation without any newlines. For backwards compatibility with |
- versions of simplejson earlier than 2.1.0, an integer is also accepted |
- and is converted to a string with that many spaces. |
- |
- If specified, separators should be a (item_separator, key_separator) |
- tuple. The default is (', ', ': '). To get the most compact JSON |
- representation you should specify (',', ':') to eliminate whitespace. |
- |
- If specified, default is a function that gets called for objects |
- that can't otherwise be serialized. It should return a JSON encodable |
- version of the object or raise a ``TypeError``. |
- |
- If encoding is not None, then all input strings will be |
- transformed into unicode using that encoding prior to JSON-encoding. |
- The default is UTF-8. |
- |
- If use_decimal is true (not the default), ``decimal.Decimal`` will |
- be supported directly by the encoder. For the inverse, decode JSON |
- with ``parse_float=decimal.Decimal``. |
- |
- """ |
- |
- self.skipkeys = skipkeys |
- self.ensure_ascii = ensure_ascii |
- self.check_circular = check_circular |
- self.allow_nan = allow_nan |
- self.sort_keys = sort_keys |
- self.use_decimal = use_decimal |
- if isinstance(indent, (int, long)): |
- indent = ' ' * indent |
- self.indent = indent |
- if separators is not None: |
- self.item_separator, self.key_separator = separators |
- if default is not None: |
- self.default = default |
- self.encoding = encoding |
- |
- def default(self, o): |
- """Implement this method in a subclass such that it returns |
- a serializable object for ``o``, or calls the base implementation |
- (to raise a ``TypeError``). |
- |
- For example, to support arbitrary iterators, you could |
- implement default like this:: |
- |
- def default(self, o): |
- try: |
- iterable = iter(o) |
- except TypeError: |
- pass |
- else: |
- return list(iterable) |
- return JSONEncoder.default(self, o) |
- |
- """ |
- raise TypeError(repr(o) + " is not JSON serializable") |
- |
- def encode(self, o): |
- """Return a JSON string representation of a Python data structure. |
- |
- >>> from simplejson import JSONEncoder |
- >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) |
- '{"foo": ["bar", "baz"]}' |
- |
- """ |
- # This is for extremely simple cases and benchmarks. |
- if isinstance(o, basestring): |
- if isinstance(o, str): |
- _encoding = self.encoding |
- if (_encoding is not None |
- and not (_encoding == 'utf-8')): |
- o = o.decode(_encoding) |
- if self.ensure_ascii: |
- return encode_basestring_ascii(o) |
- else: |
- return encode_basestring(o) |
- # This doesn't pass the iterator directly to ''.join() because the |
- # exceptions aren't as detailed. The list call should be roughly |
- # equivalent to the PySequence_Fast that ''.join() would do. |
- chunks = self.iterencode(o, _one_shot=True) |
- if not isinstance(chunks, (list, tuple)): |
- chunks = list(chunks) |
- if self.ensure_ascii: |
- return ''.join(chunks) |
- else: |
- return u''.join(chunks) |
- |
- def iterencode(self, o, _one_shot=False): |
- """Encode the given object and yield each string |
- representation as available. |
- |
- For example:: |
- |
- for chunk in JSONEncoder().iterencode(bigobject): |
- mysocket.write(chunk) |
- |
- """ |
- if self.check_circular: |
- markers = {} |
- else: |
- markers = None |
- if self.ensure_ascii: |
- _encoder = encode_basestring_ascii |
- else: |
- _encoder = encode_basestring |
- if self.encoding != 'utf-8': |
- def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): |
- if isinstance(o, str): |
- o = o.decode(_encoding) |
- return _orig_encoder(o) |
- |
- def floatstr(o, allow_nan=self.allow_nan, |
- _repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf): |
- # Check for specials. Note that this type of test is processor |
- # and/or platform-specific, so do tests which don't depend on |
- # the internals. |
- |
- if o != o: |
- text = 'NaN' |
- elif o == _inf: |
- text = 'Infinity' |
- elif o == _neginf: |
- text = '-Infinity' |
- else: |
- return _repr(o) |
- |
- if not allow_nan: |
- raise ValueError( |
- "Out of range float values are not JSON compliant: " + |
- repr(o)) |
- |
- return text |
- |
- |
- key_memo = {} |
- if (_one_shot and c_make_encoder is not None |
- and self.indent is None and not self.sort_keys): |
- _iterencode = c_make_encoder( |
- markers, self.default, _encoder, self.indent, |
- self.key_separator, self.item_separator, self.sort_keys, |
- self.skipkeys, self.allow_nan, key_memo, self.use_decimal) |
- else: |
- _iterencode = _make_iterencode( |
- markers, self.default, _encoder, self.indent, floatstr, |
- self.key_separator, self.item_separator, self.sort_keys, |
- self.skipkeys, _one_shot, self.use_decimal) |
- try: |
- return _iterencode(o, 0) |
- finally: |
- key_memo.clear() |
- |
- |
-class JSONEncoderForHTML(JSONEncoder): |
- """An encoder that produces JSON safe to embed in HTML. |
- |
- To embed JSON content in, say, a script tag on a web page, the |
- characters &, < and > should be escaped. They cannot be escaped |
- with the usual entities (e.g. &) because they are not expanded |
- within <script> tags. |
- """ |
- |
- def encode(self, o): |
- # Override JSONEncoder.encode because it has hacks for |
- # performance that make things more complicated. |
- chunks = self.iterencode(o, True) |
- if self.ensure_ascii: |
- return ''.join(chunks) |
- else: |
- return u''.join(chunks) |
- |
- def iterencode(self, o, _one_shot=False): |
- chunks = super(JSONEncoderForHTML, self).iterencode(o, _one_shot) |
- for chunk in chunks: |
- chunk = chunk.replace('&', '\\u0026') |
- chunk = chunk.replace('<', '\\u003c') |
- chunk = chunk.replace('>', '\\u003e') |
- yield chunk |
- |
- |
-def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, |
- _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, |
- _use_decimal, |
- ## HACK: hand-optimized bytecode; turn globals into locals |
- False=False, |
- True=True, |
- ValueError=ValueError, |
- basestring=basestring, |
- Decimal=Decimal, |
- dict=dict, |
- float=float, |
- id=id, |
- int=int, |
- isinstance=isinstance, |
- list=list, |
- long=long, |
- str=str, |
- tuple=tuple, |
- ): |
- |
- def _iterencode_list(lst, _current_indent_level): |
- if not lst: |
- yield '[]' |
- return |
- if markers is not None: |
- markerid = id(lst) |
- if markerid in markers: |
- raise ValueError("Circular reference detected") |
- markers[markerid] = lst |
- buf = '[' |
- if _indent is not None: |
- _current_indent_level += 1 |
- newline_indent = '\n' + (_indent * _current_indent_level) |
- separator = _item_separator + newline_indent |
- buf += newline_indent |
- else: |
- newline_indent = None |
- separator = _item_separator |
- first = True |
- for value in lst: |
- if first: |
- first = False |
- else: |
- buf = separator |
- if isinstance(value, basestring): |
- yield buf + _encoder(value) |
- elif value is None: |
- yield buf + 'null' |
- elif value is True: |
- yield buf + 'true' |
- elif value is False: |
- yield buf + 'false' |
- elif isinstance(value, (int, long)): |
- yield buf + str(value) |
- elif isinstance(value, float): |
- yield buf + _floatstr(value) |
- elif _use_decimal and isinstance(value, Decimal): |
- yield buf + str(value) |
- else: |
- yield buf |
- if isinstance(value, (list, tuple)): |
- chunks = _iterencode_list(value, _current_indent_level) |
- elif isinstance(value, dict): |
- chunks = _iterencode_dict(value, _current_indent_level) |
- else: |
- chunks = _iterencode(value, _current_indent_level) |
- for chunk in chunks: |
- yield chunk |
- if newline_indent is not None: |
- _current_indent_level -= 1 |
- yield '\n' + (_indent * _current_indent_level) |
- yield ']' |
- if markers is not None: |
- del markers[markerid] |
- |
- def _iterencode_dict(dct, _current_indent_level): |
- if not dct: |
- yield '{}' |
- return |
- if markers is not None: |
- markerid = id(dct) |
- if markerid in markers: |
- raise ValueError("Circular reference detected") |
- markers[markerid] = dct |
- yield '{' |
- if _indent is not None: |
- _current_indent_level += 1 |
- newline_indent = '\n' + (_indent * _current_indent_level) |
- item_separator = _item_separator + newline_indent |
- yield newline_indent |
- else: |
- newline_indent = None |
- item_separator = _item_separator |
- first = True |
- if _sort_keys: |
- items = dct.items() |
- items.sort(key=lambda kv: kv[0]) |
- else: |
- items = dct.iteritems() |
- for key, value in items: |
- if isinstance(key, basestring): |
- pass |
- # JavaScript is weakly typed for these, so it makes sense to |
- # also allow them. Many encoders seem to do something like this. |
- elif isinstance(key, float): |
- key = _floatstr(key) |
- elif key is True: |
- key = 'true' |
- elif key is False: |
- key = 'false' |
- elif key is None: |
- key = 'null' |
- elif isinstance(key, (int, long)): |
- key = str(key) |
- elif _skipkeys: |
- continue |
- else: |
- raise TypeError("key " + repr(key) + " is not a string") |
- if first: |
- first = False |
- else: |
- yield item_separator |
- yield _encoder(key) |
- yield _key_separator |
- if isinstance(value, basestring): |
- yield _encoder(value) |
- elif value is None: |
- yield 'null' |
- elif value is True: |
- yield 'true' |
- elif value is False: |
- yield 'false' |
- elif isinstance(value, (int, long)): |
- yield str(value) |
- elif isinstance(value, float): |
- yield _floatstr(value) |
- elif _use_decimal and isinstance(value, Decimal): |
- yield str(value) |
- else: |
- if isinstance(value, (list, tuple)): |
- chunks = _iterencode_list(value, _current_indent_level) |
- elif isinstance(value, dict): |
- chunks = _iterencode_dict(value, _current_indent_level) |
- else: |
- chunks = _iterencode(value, _current_indent_level) |
- for chunk in chunks: |
- yield chunk |
- if newline_indent is not None: |
- _current_indent_level -= 1 |
- yield '\n' + (_indent * _current_indent_level) |
- yield '}' |
- if markers is not None: |
- del markers[markerid] |
- |
- def _iterencode(o, _current_indent_level): |
- if isinstance(o, basestring): |
- yield _encoder(o) |
- elif o is None: |
- yield 'null' |
- elif o is True: |
- yield 'true' |
- elif o is False: |
- yield 'false' |
- elif isinstance(o, (int, long)): |
- yield str(o) |
- elif isinstance(o, float): |
- yield _floatstr(o) |
- elif isinstance(o, (list, tuple)): |
- for chunk in _iterencode_list(o, _current_indent_level): |
- yield chunk |
- elif isinstance(o, dict): |
- for chunk in _iterencode_dict(o, _current_indent_level): |
- yield chunk |
- elif _use_decimal and isinstance(o, Decimal): |
- yield str(o) |
- else: |
- if markers is not None: |
- markerid = id(o) |
- if markerid in markers: |
- raise ValueError("Circular reference detected") |
- markers[markerid] = o |
- o = _default(o) |
- for chunk in _iterencode(o, _current_indent_level): |
- yield chunk |
- if markers is not None: |
- del markers[markerid] |
- |
- return _iterencode |