0001"""
0002Implementation of JSONEncoder
0003"""
0004import re
0005
0006# this should match any kind of infinity
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    # If the first non-sign is a digit then it's not a special value
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    # These are the string representations on the platforms I've tried
0031    if s == 'nan':
0032        return 'NaN'
0033    if s == 'inf':
0034        return 'Infinity'
0035    if s == '-inf':
0036        return '-Infinity'
0037    # NaN should either be inequal to itself, or equal to everything
0038    if o != o or o == 0.0:
0039        return 'NaN'
0040    # Last ditch effort, assume inf
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            # JavaScript is weakly typed for these, so it makes sense to
0175            # also allow them.  Many encoders seem to do something like this.
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        # This doesn't pass the iterator directly to ''.join() because it
0268        # sucks at reporting exceptions.  It's going to do this internally
0269        # anyway because it uses PySequence_Fast or similar.
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']