Commit a9c2f033 authored by Malcolm Tredinnick's avatar Malcolm Tredinnick
Browse files

Upgraded included simplejson to 2.0.7.

Also changed importing logic to prefer a system-installed version of
simplejson (unless it's an earlier version that does not contian the C
speedups), then the json module from Python 2.6, then the version
shipped with Django.

Fixed #9266.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9707 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 3b489b77
Loading
Loading
Loading
Loading
+290 −323
Original line number Diff line number Diff line
r"""
A simple, fast, extensible JSON encoder and decoder

JSON (JavaScript Object Notation) <http://json.org> is a subset of
r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of
JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
interchange format.

simplejson exposes an API familiar to uses of the standard library
marshal and pickle modules.
:mod:`simplejson` exposes an API familiar to users of the standard library
:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
version of the :mod:`json` library contained in Python 2.6, but maintains
compatibility with Python 2.4 and Python 2.5 and (currently) has
significant performance advantages, even without using the optional C
extension for speedups.

Encoding basic Python object hierarchies::

    >>> import simplejson
    >>> simplejson.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
    >>> import simplejson as json
    >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
    '["foo", {"bar": ["baz", null, 1.0, 2]}]'
    >>> print simplejson.dumps("\"foo\bar")
    >>> print json.dumps("\"foo\bar")
    "\"foo\bar"
    >>> print simplejson.dumps(u'\u1234')
    >>> print json.dumps(u'\u1234')
    "\u1234"
    >>> print simplejson.dumps('\\')
    >>> print json.dumps('\\')
    "\\"
    >>> print simplejson.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
    >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
    {"a": 0, "b": 0, "c": 0}
    >>> from StringIO import StringIO
    >>> io = StringIO()
    >>> simplejson.dump(['streaming API'], io)
    >>> json.dump(['streaming API'], io)
    >>> io.getvalue()
    '["streaming API"]'

Compact encoding::

    >>> import simplejson
    >>> simplejson.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
    >>> import simplejson as json
    >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
    '[1,2,3,{"4":5,"6":7}]'

Pretty printing::

    >>> import simplejson
    >>> print simplejson.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
    >>> import simplejson as json
    >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
    >>> print '\n'.join([l.rstrip() for l in  s.splitlines()])
    {
        "4": 5,
        "6": 7
@@ -44,50 +46,49 @@ Pretty printing::

Decoding JSON::

    >>> import simplejson
    >>> simplejson.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
    [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
    >>> simplejson.loads('"\\"foo\\bar"')
    u'"foo\x08ar'
    >>> import simplejson as json
    >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
    >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
    True
    >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
    True
    >>> from StringIO import StringIO
    >>> io = StringIO('["streaming API"]')
    >>> simplejson.load(io)
    [u'streaming API']
    >>> json.load(io)[0] == 'streaming API'
    True

Specializing JSON object decoding::

    >>> import simplejson
    >>> import simplejson as json
    >>> def as_complex(dct):
    ...     if '__complex__' in dct:
    ...         return complex(dct['real'], dct['imag'])
    ...     return dct
    ...
    >>> simplejson.loads('{"__complex__": true, "real": 1, "imag": 2}',
    >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
    ...     object_hook=as_complex)
    (1+2j)
    >>> import decimal
    >>> simplejson.loads('1.1', parse_float=decimal.Decimal)
    Decimal("1.1")
    >>> json.loads('1.1', parse_float=decimal.Decimal) == decimal.Decimal('1.1')
    True

Extending JSONEncoder::
Specializing JSON object encoding::

    >>> import simplejson
    >>> class ComplexEncoder(simplejson.JSONEncoder):
    ...     def default(self, obj):
    >>> import simplejson as json
    >>> def encode_complex(obj):
    ...     if isinstance(obj, complex):
    ...         return [obj.real, obj.imag]
    ...         return simplejson.JSONEncoder.default(self, obj)
    ...     raise TypeError("%r is not JSON serializable" % (o,))
    ...
    >>> dumps(2 + 1j, cls=ComplexEncoder)
    >>> json.dumps(2 + 1j, default=encode_complex)
    '[2.0, 1.0]'
    >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
    '[2.0, 1.0]'
    >>> ComplexEncoder().encode(2 + 1j)
    >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
    '[2.0, 1.0]'
    >>> list(ComplexEncoder().iterencode(2 + 1j))
    ['[', '2.0', ', ', '1.0', ']']


Using simplejson from the shell to validate and
pretty-print::
Using simplejson.tool from the shell to validate and pretty-print::

    $ echo '{"json":"obj"}' | python -msimplejson.tool
    {
@@ -95,24 +96,42 @@ pretty-print::
    }
    $ echo '{ 1.2:3.4}' | python -msimplejson.tool
    Expecting property name: line 1 column 2 (char 2)

Note that the JSON produced by this module's default settings
is a subset of YAML, so it may be used as a serializer for that as well.
"""
__version__ = '1.9.2'

# Django modification: try to use the system version first, providing it's
# either of a later version of has the C speedups in place. Otherwise, fall
# back to our local copy.

__version__ = '2.0.7'

use_system_version = False
try:
    # The system-installed version has priority providing it is either not an
    # earlier version or it contains the C speedups.
    import simplejson
    if (simplejson.__version__.split('.') >= __version__.split('.') or
            hasattr(simplejson, '_speedups')):
        from simplejson import *
        use_system_version = True
except ImportError:
    pass

if not use_system_version:
    try:
        from json import *      # Python 2.6 preferred over local copy.
        use_system_version = True
    except ImportError:
        pass

# If all else fails, we have a bundled version that can be used.
if not use_system_version:
    __all__ = [
        'dump', 'dumps', 'load', 'loads',
        'JSONDecoder', 'JSONEncoder',
    ]

if __name__ == '__main__':
    import warnings
    warnings.warn('python -msimplejson is deprecated, use python -msiplejson.tool', DeprecationWarning)
    from django.utils.simplejson.decoder import JSONDecoder
    from django.utils.simplejson.encoder import JSONEncoder
else:
    from decoder import JSONDecoder
    from encoder import JSONEncoder

    _default_encoder = JSONEncoder(
        skipkeys=False,
@@ -128,8 +147,7 @@ _default_encoder = JSONEncoder(
    def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
            allow_nan=True, cls=None, indent=None, separators=None,
            encoding='utf-8', default=None, **kw):
    """
    Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
        """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
        ``.write()``-supporting file-like object).

        If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
@@ -167,6 +185,7 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
        To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
        ``.default()`` method to serialize additional types), specify it with
        the ``cls`` kwarg.

        """
        # cached encoder
        if (skipkeys is False and ensure_ascii is True and
@@ -190,8 +209,7 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
    def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
            allow_nan=True, cls=None, indent=None, separators=None,
            encoding='utf-8', default=None, **kw):
    """
    Serialize ``obj`` to a JSON formatted ``str``.
        """Serialize ``obj`` to a JSON formatted ``str``.

        If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
        (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
@@ -227,6 +245,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
        To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
        ``.default()`` method to serialize additional types), specify it with
        the ``cls`` kwarg.

        """
        # cached encoder
        if (skipkeys is False and ensure_ascii is True and
@@ -248,8 +267,7 @@ _default_decoder = JSONDecoder(encoding=None, object_hook=None)

    def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
            parse_int=None, parse_constant=None, **kw):
    """
    Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
        """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
        a JSON document) to a Python object.

        If the contents of ``fp`` is encoded with an ASCII based encoding other
@@ -266,6 +284,7 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,

        To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
        kwarg.

        """
        return loads(fp.read(),
            encoding=encoding, cls=cls, object_hook=object_hook,
@@ -275,8 +294,7 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,

    def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
            parse_int=None, parse_constant=None, **kw):
    """
    Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
        """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
        document) to a Python object.

        If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding
@@ -306,6 +324,7 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,

        To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
        kwarg.

        """
        if (cls is None and encoding is None and object_hook is None and
                parse_int is None and parse_float is None and
@@ -322,55 +341,3 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
        if parse_constant is not None:
            kw['parse_constant'] = parse_constant
        return cls(encoding=encoding, **kw).decode(s)


#
# Compatibility cruft from other libraries
#


def decode(s):
    """
    demjson, python-cjson API compatibility hook. Use loads(s) instead.
    """
    import warnings
    warnings.warn("simplejson.loads(s) should be used instead of decode(s)",
        DeprecationWarning)
    return loads(s)


def encode(obj):
    """
    demjson, python-cjson compatibility hook. Use dumps(s) instead.
    """
    import warnings
    warnings.warn("simplejson.dumps(s) should be used instead of encode(s)",
        DeprecationWarning)
    return dumps(obj)


def read(s):
    """
    jsonlib, JsonUtils, python-json, json-py API compatibility hook.
    Use loads(s) instead.
    """
    import warnings
    warnings.warn("simplejson.loads(s) should be used instead of read(s)",
        DeprecationWarning)
    return loads(s)


def write(obj):
    """
    jsonlib, JsonUtils, python-json, json-py API compatibility hook.
    Use dumps(s) instead.
    """
    import warnings
    warnings.warn("simplejson.dumps(s) should be used instead of write(s)",
        DeprecationWarning)
    return dumps(obj)


if __name__ == '__main__':
    import simplejson.tool
    simplejson.tool.main()
+137 −135
Original line number Diff line number Diff line
"""
Implementation of JSONDecoder
"""Implementation of JSONDecoder
"""
import re
import sys
import struct

from django.utils.simplejson.scanner import Scanner, pattern
try:
    from django.utils.simplejson._speedups import scanstring as c_scanstring
except ImportError:
    pass
from django.utils.simplejson.scanner import make_scanner
c_scanstring = None

__all__ = ['JSONDecoder']

FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL

def _floatconstants():
    import struct
    import sys
    _BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
    if sys.byteorder != 'big':
        _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
@@ -34,6 +31,7 @@ def linecol(doc, pos):


def errmsg(msg, doc, pos, end=None):
    # Note that this function is called from _speedups
    lineno, colno = linecol(doc, pos)
    if end is None:
        return '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos)
@@ -46,35 +44,8 @@ _CONSTANTS = {
    '-Infinity': NegInf,
    'Infinity': PosInf,
    'NaN': NaN,
    'true': True,
    'false': False,
    'null': None,
}

def JSONConstant(match, context, c=_CONSTANTS):
    s = match.group(0)
    fn = getattr(context, 'parse_constant', None)
    if fn is None:
        rval = c[s]
    else:
        rval = fn(s)
    return rval, None
pattern('(-?Infinity|NaN|true|false|null)')(JSONConstant)


def JSONNumber(match, context):
    match = JSONNumber.regex.match(match.string, *match.span())
    integer, frac, exp = match.groups()
    if frac or exp:
        fn = getattr(context, 'parse_float', None) or float
        res = fn(integer + (frac or '') + (exp or ''))
    else:
        fn = getattr(context, 'parse_int', None) or int
        res = fn(integer)
    return res, None
pattern(r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?')(JSONNumber)


STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
BACKSLASH = {
    '"': u'"', '\\': u'\\', '/': u'/',
@@ -84,6 +55,14 @@ BACKSLASH = {
DEFAULT_ENCODING = "utf-8"

def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match):
    """Scan the string s for a JSON string. End is the index of the
    character in s after the quote that started the JSON string.
    Unescapes all valid JSON string escape sequences and raises ValueError
    on attempt to decode an invalid string. If strict is False then literal
    control characters are allowed in the string.
    
    Returns a tuple of the decoded string and the index of the character in s
    after the end quote."""
    if encoding is None:
        encoding = DEFAULT_ENCODING
    chunks = []
@@ -96,15 +75,19 @@ def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHU
                errmsg("Unterminated string starting at", s, begin))
        end = chunk.end()
        content, terminator = chunk.groups()
        # Content is contains zero or more unescaped string characters
        if content:
            if not isinstance(content, unicode):
                content = unicode(content, encoding)
            _append(content)
        # Terminator is the end of string, a literal control character,
        # or a backslash denoting that an escape sequence follows
        if terminator == '"':
            break
        elif terminator != '\\':
            if strict:
                raise ValueError(errmsg("Invalid control character %r at", s, end))
                msg = "Invalid control character %r at" % (terminator,)
                raise ValueError(msg, s, end)
            else:
                _append(terminator)
                continue
@@ -113,139 +96,159 @@ def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHU
        except IndexError:
            raise ValueError(
                errmsg("Unterminated string starting at", s, begin))
        # If not a unicode escape sequence, must be in the lookup table
        if esc != 'u':
            try:
                m = _b[esc]
                char = _b[esc]
            except KeyError:
                raise ValueError(
                    errmsg("Invalid \\escape: %r" % (esc,), s, end))
            end += 1
        else:
            # Unicode escape sequence
            esc = s[end + 1:end + 5]
            next_end = end + 5
            msg = "Invalid \\uXXXX escape"
            try:
            if len(esc) != 4:
                    raise ValueError
                msg = "Invalid \\uXXXX escape"
                raise ValueError(errmsg(msg, s, end))
            uni = int(esc, 16)
            # Check for surrogate pair on UCS-4 systems
            if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
                msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
                if not s[end + 5:end + 7] == '\\u':
                        raise ValueError
                    raise ValueError(errmsg(msg, s, end))
                esc2 = s[end + 7:end + 11]
                if len(esc2) != 4:
                        raise ValueError
                    raise ValueError(errmsg(msg, s, end))
                uni2 = int(esc2, 16)
                uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
                next_end += 6
                m = unichr(uni)
            except ValueError:
                raise ValueError(errmsg(msg, s, end))
            char = unichr(uni)
            end = next_end
        _append(m)
        # Append the unescaped character
        _append(char)
    return u''.join(chunks), end


# Use speedup
try:
    scanstring = c_scanstring
except NameError:
    scanstring = py_scanstring

def JSONString(match, context):
    encoding = getattr(context, 'encoding', None)
    strict = getattr(context, 'strict', True)
    return scanstring(match.string, match.end(), encoding, strict)
pattern(r'"')(JSONString)

# Use speedup if available
scanstring = c_scanstring or py_scanstring

WHITESPACE = re.compile(r'\s*', FLAGS)
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
WHITESPACE_STR = ' \t\n\r'

def JSONObject(match, context, _w=WHITESPACE.match):
def JSONObject((s, end), encoding, strict, scan_once, object_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
    pairs = {}
    s = match.string
    end = _w(s, match.end()).end()
    # Use a slice to prevent IndexError from being raised, the following
    # check will raise a more specific ValueError if the string is empty
    nextchar = s[end:end + 1]
    # Normally we expect nextchar == '"'
    if nextchar != '"':
        if nextchar in _ws:
            end = _w(s, end).end()
            nextchar = s[end:end + 1]
        # Trivial empty object
        if nextchar == '}':
            return pairs, end + 1
    if nextchar != '"':
        elif nextchar != '"':
            raise ValueError(errmsg("Expecting property name", s, end))
    end += 1
    encoding = getattr(context, 'encoding', None)
    strict = getattr(context, 'strict', True)
    iterscan = JSONScanner.iterscan
    while True:
        key, end = scanstring(s, end, encoding, strict)

        # To skip some function call overhead we optimize the fast paths where
        # the JSON key separator is ": " or just ":".
        if s[end:end + 1] != ':':
            end = _w(s, end).end()
            if s[end:end + 1] != ':':
                raise ValueError(errmsg("Expecting : delimiter", s, end))

        end += 1

        try:
            if s[end] in _ws:
                end += 1
                if s[end] in _ws:
                    end = _w(s, end + 1).end()
        except IndexError:
            pass

        try:
            value, end = iterscan(s, idx=end, context=context).next()
            value, end = scan_once(s, end)
        except StopIteration:
            raise ValueError(errmsg("Expecting object", s, end))
        pairs[key] = value
        end = _w(s, end).end()
        nextchar = s[end:end + 1]

        try:
            nextchar = s[end]
            if nextchar in _ws:
                end = _w(s, end + 1).end()
                nextchar = s[end]
        except IndexError:
            nextchar = ''
        end += 1

        if nextchar == '}':
            break
        if nextchar != ',':
        elif nextchar != ',':
            raise ValueError(errmsg("Expecting , delimiter", s, end - 1))
        end = _w(s, end).end()
        nextchar = s[end:end + 1]

        try:
            nextchar = s[end]
            if nextchar in _ws:
                end += 1
                nextchar = s[end]
                if nextchar in _ws:
                    end = _w(s, end + 1).end()
                    nextchar = s[end]
        except IndexError:
            nextchar = ''

        end += 1
        if nextchar != '"':
            raise ValueError(errmsg("Expecting property name", s, end - 1))
    object_hook = getattr(context, 'object_hook', None)

    if object_hook is not None:
        pairs = object_hook(pairs)
    return pairs, end
pattern(r'{')(JSONObject)


def JSONArray(match, context, _w=WHITESPACE.match):
def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
    values = []
    s = match.string
    end = _w(s, match.end()).end()
    # Look-ahead for trivial empty array
    nextchar = s[end:end + 1]
    if nextchar in _ws:
        end = _w(s, end + 1).end()
        nextchar = s[end:end + 1]
    # Look-ahead for trivial empty array
    if nextchar == ']':
        return values, end + 1
    iterscan = JSONScanner.iterscan
    _append = values.append
    while True:
        try:
            value, end = iterscan(s, idx=end, context=context).next()
            value, end = scan_once(s, end)
        except StopIteration:
            raise ValueError(errmsg("Expecting object", s, end))
        values.append(value)
        end = _w(s, end).end()
        _append(value)
        nextchar = s[end:end + 1]
        if nextchar in _ws:
            end = _w(s, end + 1).end()
            nextchar = s[end:end + 1]
        end += 1
        if nextchar == ']':
            break
        if nextchar != ',':
        elif nextchar != ',':
            raise ValueError(errmsg("Expecting , delimiter", s, end))
        end = _w(s, end).end()
    return values, end
pattern(r'\[')(JSONArray)


ANYTHING = [
    JSONObject,
    JSONArray,
    JSONString,
    JSONConstant,
    JSONNumber,
]

JSONScanner = Scanner(ANYTHING)
        try:
            if s[end] in _ws:
                end += 1
                if s[end] in _ws:
                    end = _w(s, end + 1).end()
        except IndexError:
            pass

    return values, end

class JSONDecoder(object):
    """
    Simple JSON <http://json.org> decoder
    """Simple JSON <http://json.org> decoder

    Performs the following translations in decoding by default:

@@ -271,15 +274,12 @@ class JSONDecoder(object):

    It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
    their corresponding ``float`` values, which is outside the JSON spec.
    """

    _scanner = Scanner(ANYTHING)
    __all__ = ['__init__', 'decode', 'raw_decode']
    """

    def __init__(self, encoding=None, object_hook=None, parse_float=None,
            parse_int=None, parse_constant=None, strict=True):
        """
        ``encoding`` determines the encoding used to interpret any ``str``
        """``encoding`` determines the encoding used to interpret any ``str``
        objects decoded by this instance (utf-8 by default).  It has no
        effect when decoding ``unicode`` objects.

@@ -302,21 +302,26 @@ class JSONDecoder(object):
        for JSON integers (e.g. float).

        ``parse_constant``, if specified, will be called with one of the
        following strings: -Infinity, Infinity, NaN, null, true, false.
        following strings: -Infinity, Infinity, NaN.
        This can be used to raise an exception if invalid JSON numbers
        are encountered.

        """
        self.encoding = encoding
        self.object_hook = object_hook
        self.parse_float = parse_float
        self.parse_int = parse_int
        self.parse_constant = parse_constant
        self.parse_float = parse_float or float
        self.parse_int = parse_int or int
        self.parse_constant = parse_constant or _CONSTANTS.__getitem__
        self.strict = strict
        self.parse_object = JSONObject
        self.parse_array = JSONArray
        self.parse_string = scanstring
        self.scan_once = make_scanner(self)

    def decode(self, s, _w=WHITESPACE.match):
        """
        Return the Python representation of ``s`` (a ``str`` or ``unicode``
        """Return the Python representation of ``s`` (a ``str`` or ``unicode``
        instance containing a JSON document)

        """
        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
        end = _w(s, end).end()
@@ -324,20 +329,17 @@ class JSONDecoder(object):
            raise ValueError(errmsg("Extra data", s, end, len(s)))
        return obj

    def raw_decode(self, s, **kw):
        """
        Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning
    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning
        with a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.

        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.

        """
        kw.setdefault('context', self)
        try:
            obj, end = self._scanner.iterscan(s, **kw).next()
            obj, end = self.scan_once(s, idx)
        except StopIteration:
            raise ValueError("No JSON object could be decoded")
        return obj, end

__all__ = ['JSONDecoder']
+210 −165

File changed.

Preview size limit exceeded, changes collapsed.

+56 −58

File changed.

Preview size limit exceeded, changes collapsed.

+5 −14
Original line number Diff line number Diff line
r"""
Using simplejson from the shell to validate and
r"""Using simplejson from the shell to validate and
pretty-print::

    $ echo '{"json":"obj"}' | python -msimplejson
    $ echo '{"json":"obj"}' | python -msimplejson.tool
    {
        "json": "obj"
    }
    $ echo '{ 1.2:3.4}' | python -msimplejson
    $ echo '{ 1.2:3.4}' | python -msimplejson.tool
    Expecting property name: line 1 column 2 (char 2)

Note that the JSON produced by this module's default settings
is a subset of YAML, so it may be used as a serializer for that as well.
"""
import django.utils.simplejson

#
# Pretty printer:
#     curl http://mochikit.com/examples/ajax_tables/domains.json | python -msimplejson.tool
#
from django.utils import simplejson

def main():
    import sys
Loading