Changeset 391 for python/trunk/Lib/json


Ignore:
Timestamp:
Mar 19, 2014, 11:31:01 PM (11 years ago)
Author:
dmik
Message:

python: Merge vendor 2.7.6 to trunk.

Location:
python/trunk
Files:
22 edited
2 copied

Legend:

Unmodified
Added
Removed
  • python/trunk

  • python/trunk/Lib/json/__init__.py

    r2 r391  
    1 r"""A simple, fast, extensible JSON encoder and decoder
    2 
    3 JSON (JavaScript Object Notation) <http://json.org> is a subset of
     1r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of
    42JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
    53interchange format.
    64
    7 json exposes an API familiar to uses of the standard library
    8 marshal and pickle modules.
     5:mod:`json` exposes an API familiar to users of the standard library
     6:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
     7version of the :mod:`json` library contained in Python 2.6, but maintains
     8compatibility with Python 2.4 and Python 2.5 and (currently) has
     9significant performance advantages, even without using the optional C
     10extension for speedups.
    911
    1012Encoding basic Python object hierarchies::
     
    3032
    3133    >>> import json
    32     >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
     34    >>> json.dumps([1,2,3,{'4': 5, '6': 7}], sort_keys=True, separators=(',',':'))
    3335    '[1,2,3,{"4":5,"6":7}]'
    3436
    35 Pretty printing (using repr() because of extraneous whitespace in the output)::
    36 
    37     >>> import json
    38     >>> print repr(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4))
    39     '{\n    "4": 5, \n    "6": 7\n}'
     37Pretty printing::
     38
     39    >>> import json
     40    >>> print json.dumps({'4': 5, '6': 7}, sort_keys=True,
     41    ...                  indent=4, separators=(',', ': '))
     42    {
     43        "4": 5,
     44        "6": 7
     45    }
    4046
    4147Decoding JSON::
    4248
    4349    >>> import json
    44     >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
    45     [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
    46     >>> json.loads('"\\"foo\\bar"')
    47     u'"foo\x08ar'
     50    >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
     51    >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
     52    True
     53    >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
     54    True
    4855    >>> from StringIO import StringIO
    4956    >>> io = StringIO('["streaming API"]')
    50     >>> json.load(io)
    51     [u'streaming API']
     57    >>> json.load(io)[0] == 'streaming API'
     58    True
    5259
    5360Specializing JSON object decoding::
     
    6269    ...     object_hook=as_complex)
    6370    (1+2j)
    64     >>> import decimal
    65     >>> json.loads('1.1', parse_float=decimal.Decimal)
    66     Decimal('1.1')
    67 
    68 Extending JSONEncoder::
    69 
    70     >>> import json
    71     >>> class ComplexEncoder(json.JSONEncoder):
    72     ...     def default(self, obj):
    73     ...         if isinstance(obj, complex):
    74     ...             return [obj.real, obj.imag]
    75     ...         return json.JSONEncoder.default(self, obj)
     71    >>> from decimal import Decimal
     72    >>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1')
     73    True
     74
     75Specializing JSON object encoding::
     76
     77    >>> import json
     78    >>> def encode_complex(obj):
     79    ...     if isinstance(obj, complex):
     80    ...         return [obj.real, obj.imag]
     81    ...     raise TypeError(repr(o) + " is not JSON serializable")
    7682    ...
    77     >>> dumps(2 + 1j, cls=ComplexEncoder)
     83    >>> json.dumps(2 + 1j, default=encode_complex)
    7884    '[2.0, 1.0]'
    79     >>> ComplexEncoder().encode(2 + 1j)
     85    >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
    8086    '[2.0, 1.0]'
    81     >>> list(ComplexEncoder().iterencode(2 + 1j))
    82     ['[', '2.0', ', ', '1.0', ']']
    83 
    84 
    85 Using json.tool from the shell to validate and
    86 pretty-print::
    87 
    88     $ echo '{"json":"obj"}' | python -mjson.tool
     87    >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
     88    '[2.0, 1.0]'
     89
     90
     91Using json.tool from the shell to validate and pretty-print::
     92
     93    $ echo '{"json":"obj"}' | python -m json.tool
    8994    {
    9095        "json": "obj"
    9196    }
    92     $ echo '{ 1.2:3.4}' | python -mjson.tool
    93     Expecting property name: line 1 column 2 (char 2)
    94 
    95 Note that the JSON produced by this module's default settings
    96 is a subset of YAML, so it may be used as a serializer for that as well.
    97 
     97    $ echo '{ 1.2:3.4}' | python -m json.tool
     98    Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
    9899"""
    99 
    100 __version__ = '1.9'
     100__version__ = '2.0.9'
    101101__all__ = [
    102102    'dump', 'dumps', 'load', 'loads',
     
    122122def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
    123123        allow_nan=True, cls=None, indent=None, separators=None,
    124         encoding='utf-8', default=None, **kw):
     124        encoding='utf-8', default=None, sort_keys=False, **kw):
    125125    """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
    126126    ``.write()``-supporting file-like object).
    127127
    128     If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
     128    If ``skipkeys`` is true then ``dict`` keys that are not basic types
    129129    (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
    130130    will be skipped instead of raising a ``TypeError``.
    131131
    132     If ``ensure_ascii`` is ``False``, then the some chunks written to ``fp``
    133     may be ``unicode`` instances, subject to normal Python ``str`` to
    134     ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
    135     understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
    136     to cause an error.
    137 
    138     If ``check_circular`` is ``False``, then the circular reference check
     132    If ``ensure_ascii`` is true (the default), all non-ASCII characters in the
     133    output are escaped with ``\uXXXX`` sequences, and the result is a ``str``
     134    instance consisting of ASCII characters only.  If ``ensure_ascii`` is
     135    ``False``, some chunks written to ``fp`` may be ``unicode`` instances.
     136    This usually happens because the input contains unicode strings or the
     137    ``encoding`` parameter is used. Unless ``fp.write()`` explicitly
     138    understands ``unicode`` (as in ``codecs.getwriter``) this is likely to
     139    cause an error.
     140
     141    If ``check_circular`` is false, then the circular reference check
    139142    for container types will be skipped and a circular reference will
    140143    result in an ``OverflowError`` (or worse).
    141144
    142     If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
     145    If ``allow_nan`` is false, then it will be a ``ValueError`` to
    143146    serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
    144147    in strict compliance of the JSON specification, instead of using the
    145148    JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
    146149
    147     If ``indent`` is a non-negative integer, then JSON array elements and object
    148     members will be pretty-printed with that indent level. An indent level
    149     of 0 will only insert newlines. ``None`` is the most compact representation.
     150    If ``indent`` is a non-negative integer, then JSON array elements and
     151    object members will be pretty-printed with that indent level. An indent
     152    level of 0 will only insert newlines. ``None`` is the most compact
     153    representation.  Since the default item separator is ``', '``,  the
     154    output might include trailing whitespace when ``indent`` is specified.
     155    You can use ``separators=(',', ': ')`` to avoid this.
    150156
    151157    If ``separators`` is an ``(item_separator, dict_separator)`` tuple
     
    158164    of obj or raise TypeError. The default simply raises TypeError.
    159165
     166    If *sort_keys* is ``True`` (default: ``False``), then the output of
     167    dictionaries will be sorted by key.
     168
    160169    To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
    161170    ``.default()`` method to serialize additional types), specify it with
    162     the ``cls`` kwarg.
     171    the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
    163172
    164173    """
    165174    # cached encoder
    166     if (skipkeys is False and ensure_ascii is True and
    167         check_circular is True and allow_nan is True and
     175    if (not skipkeys and ensure_ascii and
     176        check_circular and allow_nan and
    168177        cls is None and indent is None and separators is None and
    169         encoding == 'utf-8' and default is None and not kw):
     178        encoding == 'utf-8' and default is None and not sort_keys and not kw):
    170179        iterable = _default_encoder.iterencode(obj)
    171180    else:
     
    175184            check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    176185            separators=separators, encoding=encoding,
    177             default=default, **kw).iterencode(obj)
     186            default=default, sort_keys=sort_keys, **kw).iterencode(obj)
    178187    # could accelerate with writelines in some versions of Python, at
    179188    # a debuggability cost
     
    184193def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
    185194        allow_nan=True, cls=None, indent=None, separators=None,
    186         encoding='utf-8', default=None, **kw):
     195        encoding='utf-8', default=None, sort_keys=False, **kw):
    187196    """Serialize ``obj`` to a JSON formatted ``str``.
    188197
    189     If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
     198    If ``skipkeys`` is false then ``dict`` keys that are not basic types
    190199    (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
    191200    will be skipped instead of raising a ``TypeError``.
    192201
    193     If ``ensure_ascii`` is ``False``, then the return value will be a
    194     ``unicode`` instance subject to normal Python ``str`` to ``unicode``
    195     coercion rules instead of being escaped to an ASCII ``str``.
    196 
    197     If ``check_circular`` is ``False``, then the circular reference check
     202    If ``ensure_ascii`` is false, all non-ASCII characters are not escaped, and
     203    the return value may be a ``unicode`` instance. See ``dump`` for details.
     204
     205    If ``check_circular`` is false, then the circular reference check
    198206    for container types will be skipped and a circular reference will
    199207    result in an ``OverflowError`` (or worse).
    200208
    201     If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
     209    If ``allow_nan`` is false, then it will be a ``ValueError`` to
    202210    serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
    203211    strict compliance of the JSON specification, instead of using the
     
    207215    object members will be pretty-printed with that indent level. An indent
    208216    level of 0 will only insert newlines. ``None`` is the most compact
    209     representation.
     217    representation.  Since the default item separator is ``', '``,  the
     218    output might include trailing whitespace when ``indent`` is specified.
     219    You can use ``separators=(',', ': ')`` to avoid this.
    210220
    211221    If ``separators`` is an ``(item_separator, dict_separator)`` tuple
     
    218228    of obj or raise TypeError. The default simply raises TypeError.
    219229
     230    If *sort_keys* is ``True`` (default: ``False``), then the output of
     231    dictionaries will be sorted by key.
     232
    220233    To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
    221234    ``.default()`` method to serialize additional types), specify it with
    222     the ``cls`` kwarg.
     235    the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
    223236
    224237    """
    225238    # cached encoder
    226     if (skipkeys is False and ensure_ascii is True and
    227         check_circular is True and allow_nan is True and
     239    if (not skipkeys and ensure_ascii and
     240        check_circular and allow_nan and
    228241        cls is None and indent is None and separators is None and
    229         encoding == 'utf-8' and default is None and not kw):
     242        encoding == 'utf-8' and default is None and not sort_keys and not kw):
    230243        return _default_encoder.encode(obj)
    231244    if cls is None:
     
    235248        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    236249        separators=separators, encoding=encoding, default=default,
    237         **kw).encode(obj)
    238 
    239 
    240 _default_decoder = JSONDecoder(encoding=None, object_hook=None)
     250        sort_keys=sort_keys, **kw).encode(obj)
     251
     252
     253_default_decoder = JSONDecoder(encoding=None, object_hook=None,
     254                               object_pairs_hook=None)
    241255
    242256
    243257def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
    244         parse_int=None, parse_constant=None, **kw):
    245     """Deserialize ``fp`` (a ``.read()``-supporting file-like object
    246     containing a JSON document) to a Python object.
     258        parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
     259    """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
     260    a JSON document) to a Python object.
    247261
    248262    If the contents of ``fp`` is encoded with an ASCII based encoding other
     
    258272    can be used to implement custom decoders (e.g. JSON-RPC class hinting).
    259273
     274    ``object_pairs_hook`` is an optional function that will be called with the
     275    result of any object literal decoded with an ordered list of pairs.  The
     276    return value of ``object_pairs_hook`` will be used instead of the ``dict``.
     277    This feature can be used to implement custom decoders that rely on the
     278    order that the key and value pairs are decoded (for example,
     279    collections.OrderedDict will remember the order of insertion). If
     280    ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority.
     281
    260282    To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
    261     kwarg.
     283    kwarg; otherwise ``JSONDecoder`` is used.
    262284
    263285    """
     
    265287        encoding=encoding, cls=cls, object_hook=object_hook,
    266288        parse_float=parse_float, parse_int=parse_int,
    267         parse_constant=parse_constant, **kw)
     289        parse_constant=parse_constant, object_pairs_hook=object_pairs_hook,
     290        **kw)
    268291
    269292
    270293def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
    271         parse_int=None, parse_constant=None, **kw):
     294        parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
    272295    """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
    273296    document) to a Python object.
     
    283306    can be used to implement custom decoders (e.g. JSON-RPC class hinting).
    284307
     308    ``object_pairs_hook`` is an optional function that will be called with the
     309    result of any object literal decoded with an ordered list of pairs.  The
     310    return value of ``object_pairs_hook`` will be used instead of the ``dict``.
     311    This feature can be used to implement custom decoders that rely on the
     312    order that the key and value pairs are decoded (for example,
     313    collections.OrderedDict will remember the order of insertion). If
     314    ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority.
     315
    285316    ``parse_float``, if specified, will be called with the string
    286317    of every JSON float to be decoded. By default this is equivalent to
     
    299330
    300331    To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
    301     kwarg.
     332    kwarg; otherwise ``JSONDecoder`` is used.
    302333
    303334    """
    304335    if (cls is None and encoding is None and object_hook is None and
    305336            parse_int is None and parse_float is None and
    306             parse_constant is None and not kw):
     337            parse_constant is None and object_pairs_hook is None and not kw):
    307338        return _default_decoder.decode(s)
    308339    if cls is None:
     
    310341    if object_hook is not None:
    311342        kw['object_hook'] = object_hook
     343    if object_pairs_hook is not None:
     344        kw['object_pairs_hook'] = object_pairs_hook
    312345    if parse_float is not None:
    313346        kw['parse_float'] = parse_float
  • python/trunk/Lib/json/decoder.py

    r2 r391  
    11"""Implementation of JSONDecoder
    22"""
    3 
    43import re
    54import sys
    6 
    7 from json.scanner import Scanner, pattern
     5import struct
     6
     7from json import scanner
    88try:
    99    from _json import scanstring as c_scanstring
     
    1515FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
    1616
    17 NaN, PosInf, NegInf = float('nan'), float('inf'), float('-inf')
     17def _floatconstants():
     18    _BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
     19    if sys.byteorder != 'big':
     20        _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
     21    nan, inf = struct.unpack('dd', _BYTES)
     22    return nan, inf, -inf
     23
     24NaN, PosInf, NegInf = _floatconstants()
    1825
    1926
     
    2128    lineno = doc.count('\n', 0, pos) + 1
    2229    if lineno == 1:
    23         colno = pos
     30        colno = pos + 1
    2431    else:
    2532        colno = pos - doc.rindex('\n', 0, pos)
     
    2835
    2936def errmsg(msg, doc, pos, end=None):
     37    # Note that this function is called from _json
    3038    lineno, colno = linecol(doc, pos)
    3139    if end is None:
    3240        fmt = '{0}: line {1} column {2} (char {3})'
    3341        return fmt.format(msg, lineno, colno, pos)
     42        #fmt = '%s: line %d column %d (char %d)'
     43        #return fmt % (msg, lineno, colno, pos)
    3444    endlineno, endcolno = linecol(doc, end)
    3545    fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})'
    3646    return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end)
     47    #fmt = '%s: line %d column %d - line %d column %d (char %d - %d)'
     48    #return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end)
    3749
    3850
     
    4153    'Infinity': PosInf,
    4254    'NaN': NaN,
    43     'true': True,
    44     'false': False,
    45     'null': None,
    4655}
    47 
    48 
    49 def JSONConstant(match, context, c=_CONSTANTS):
    50     s = match.group(0)
    51     fn = getattr(context, 'parse_constant', None)
    52     if fn is None:
    53         rval = c[s]
    54     else:
    55         rval = fn(s)
    56     return rval, None
    57 pattern('(-?Infinity|NaN|true|false|null)')(JSONConstant)
    58 
    59 
    60 def JSONNumber(match, context):
    61     match = JSONNumber.regex.match(match.string, *match.span())
    62     integer, frac, exp = match.groups()
    63     if frac or exp:
    64         fn = getattr(context, 'parse_float', None) or float
    65         res = fn(integer + (frac or '') + (exp or ''))
    66     else:
    67         fn = getattr(context, 'parse_int', None) or int
    68         res = fn(integer)
    69     return res, None
    70 pattern(r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?')(JSONNumber)
    71 
    7256
    7357STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
     
    7963DEFAULT_ENCODING = "utf-8"
    8064
    81 
    82 def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match):
     65def py_scanstring(s, end, encoding=None, strict=True,
     66        _b=BACKSLASH, _m=STRINGCHUNK.match):
     67    """Scan the string s for a JSON string. End is the index of the
     68    character in s after the quote that started the JSON string.
     69    Unescapes all valid JSON string escape sequences and raises ValueError
     70    on attempt to decode an invalid string. If strict is False then literal
     71    control characters are allowed in the string.
     72
     73    Returns a tuple of the decoded string and the index of the character in s
     74    after the end quote."""
    8375    if encoding is None:
    8476        encoding = DEFAULT_ENCODING
     
    9385        end = chunk.end()
    9486        content, terminator = chunk.groups()
     87        # Content is contains zero or more unescaped string characters
    9588        if content:
    9689            if not isinstance(content, unicode):
    9790                content = unicode(content, encoding)
    9891            _append(content)
     92        # Terminator is the end of string, a literal control character,
     93        # or a backslash denoting that an escape sequence follows
    9994        if terminator == '"':
    10095            break
    10196        elif terminator != '\\':
    10297            if strict:
     98                #msg = "Invalid control character %r at" % (terminator,)
    10399                msg = "Invalid control character {0!r} at".format(terminator)
    104100                raise ValueError(errmsg(msg, s, end))
     
    111107            raise ValueError(
    112108                errmsg("Unterminated string starting at", s, begin))
     109        # If not a unicode escape sequence, must be in the lookup table
    113110        if esc != 'u':
    114111            try:
    115                 m = _b[esc]
     112                char = _b[esc]
    116113            except KeyError:
    117                 msg = "Invalid \\escape: {0!r}".format(esc)
     114                msg = "Invalid \\escape: " + repr(esc)
    118115                raise ValueError(errmsg(msg, s, end))
    119116            end += 1
    120117        else:
     118            # Unicode escape sequence
    121119            esc = s[end + 1:end + 5]
    122120            next_end = end + 5
    123             msg = "Invalid \\uXXXX escape"
    124             try:
    125                 if len(esc) != 4:
    126                     raise ValueError
    127                 uni = int(esc, 16)
    128                 if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
    129                     msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
    130                     if not s[end + 5:end + 7] == '\\u':
    131                         raise ValueError
    132                     esc2 = s[end + 7:end + 11]
    133                     if len(esc2) != 4:
    134                         raise ValueError
    135                     uni2 = int(esc2, 16)
    136                     uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
    137                     next_end += 6
    138                 m = unichr(uni)
    139             except ValueError:
     121            if len(esc) != 4:
     122                msg = "Invalid \\uXXXX escape"
    140123                raise ValueError(errmsg(msg, s, end))
     124            uni = int(esc, 16)
     125            # Check for surrogate pair on UCS-4 systems
     126            if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
     127                msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
     128                if not s[end + 5:end + 7] == '\\u':
     129                    raise ValueError(errmsg(msg, s, end))
     130                esc2 = s[end + 7:end + 11]
     131                if len(esc2) != 4:
     132                    raise ValueError(errmsg(msg, s, end))
     133                uni2 = int(esc2, 16)
     134                uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
     135                next_end += 6
     136            char = unichr(uni)
    141137            end = next_end
    142         _append(m)
     138        # Append the unescaped character
     139        _append(char)
    143140    return u''.join(chunks), end
    144141
    145142
    146 # Use speedup
    147 if c_scanstring is not None:
    148     scanstring = c_scanstring
    149 else:
    150     scanstring = py_scanstring
    151 
    152 def JSONString(match, context):
    153     encoding = getattr(context, 'encoding', None)
    154     strict = getattr(context, 'strict', True)
    155     return scanstring(match.string, match.end(), encoding, strict)
    156 pattern(r'"')(JSONString)
    157 
    158 
    159 WHITESPACE = re.compile(r'\s*', FLAGS)
    160 
    161 
    162 def JSONObject(match, context, _w=WHITESPACE.match):
    163     pairs = {}
    164     s = match.string
    165     end = _w(s, match.end()).end()
     143# Use speedup if available
     144scanstring = c_scanstring or py_scanstring
     145
     146WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
     147WHITESPACE_STR = ' \t\n\r'
     148
     149def JSONObject(s_and_end, encoding, strict, scan_once, object_hook,
     150               object_pairs_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
     151    s, end = s_and_end
     152    pairs = []
     153    pairs_append = pairs.append
     154    # Use a slice to prevent IndexError from being raised, the following
     155    # check will raise a more specific ValueError if the string is empty
    166156    nextchar = s[end:end + 1]
    167     # Trivial empty object
    168     if nextchar == '}':
    169         return pairs, end + 1
     157    # Normally we expect nextchar == '"'
    170158    if nextchar != '"':
    171         raise ValueError(errmsg("Expecting property name", s, end))
     159        if nextchar in _ws:
     160            end = _w(s, end).end()
     161            nextchar = s[end:end + 1]
     162        # Trivial empty object
     163        if nextchar == '}':
     164            if object_pairs_hook is not None:
     165                result = object_pairs_hook(pairs)
     166                return result, end + 1
     167            pairs = {}
     168            if object_hook is not None:
     169                pairs = object_hook(pairs)
     170            return pairs, end + 1
     171        elif nextchar != '"':
     172            raise ValueError(errmsg(
     173                "Expecting property name enclosed in double quotes", s, end))
    172174    end += 1
    173     encoding = getattr(context, 'encoding', None)
    174     strict = getattr(context, 'strict', True)
    175     iterscan = JSONScanner.iterscan
    176175    while True:
    177176        key, end = scanstring(s, end, encoding, strict)
    178         end = _w(s, end).end()
     177
     178        # To skip some function call overhead we optimize the fast paths where
     179        # the JSON key separator is ": " or just ":".
    179180        if s[end:end + 1] != ':':
    180             raise ValueError(errmsg("Expecting : delimiter", s, end))
    181         end = _w(s, end + 1).end()
    182         try:
    183             value, end = iterscan(s, idx=end, context=context).next()
     181            end = _w(s, end).end()
     182            if s[end:end + 1] != ':':
     183                raise ValueError(errmsg("Expecting ':' delimiter", s, end))
     184        end += 1
     185
     186        try:
     187            if s[end] in _ws:
     188                end += 1
     189                if s[end] in _ws:
     190                    end = _w(s, end + 1).end()
     191        except IndexError:
     192            pass
     193
     194        try:
     195            value, end = scan_once(s, end)
    184196        except StopIteration:
    185197            raise ValueError(errmsg("Expecting object", s, end))
    186         pairs[key] = value
    187         end = _w(s, end).end()
    188         nextchar = s[end:end + 1]
     198        pairs_append((key, value))
     199
     200        try:
     201            nextchar = s[end]
     202            if nextchar in _ws:
     203                end = _w(s, end + 1).end()
     204                nextchar = s[end]
     205        except IndexError:
     206            nextchar = ''
    189207        end += 1
     208
    190209        if nextchar == '}':
    191210            break
    192         if nextchar != ',':
    193             raise ValueError(errmsg("Expecting , delimiter", s, end - 1))
    194         end = _w(s, end).end()
    195         nextchar = s[end:end + 1]
     211        elif nextchar != ',':
     212            raise ValueError(errmsg("Expecting ',' delimiter", s, end - 1))
     213
     214        try:
     215            nextchar = s[end]
     216            if nextchar in _ws:
     217                end += 1
     218                nextchar = s[end]
     219                if nextchar in _ws:
     220                    end = _w(s, end + 1).end()
     221                    nextchar = s[end]
     222        except IndexError:
     223            nextchar = ''
     224
    196225        end += 1
    197226        if nextchar != '"':
    198             raise ValueError(errmsg("Expecting property name", s, end - 1))
    199     object_hook = getattr(context, 'object_hook', None)
     227            raise ValueError(errmsg(
     228                "Expecting property name enclosed in double quotes", s, end - 1))
     229    if object_pairs_hook is not None:
     230        result = object_pairs_hook(pairs)
     231        return result, end
     232    pairs = dict(pairs)
    200233    if object_hook is not None:
    201234        pairs = object_hook(pairs)
    202235    return pairs, end
    203 pattern(r'{')(JSONObject)
    204 
    205 
    206 def JSONArray(match, context, _w=WHITESPACE.match):
     236
     237def JSONArray(s_and_end, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
     238    s, end = s_and_end
    207239    values = []
    208     s = match.string
    209     end = _w(s, match.end()).end()
     240    nextchar = s[end:end + 1]
     241    if nextchar in _ws:
     242        end = _w(s, end + 1).end()
     243        nextchar = s[end:end + 1]
    210244    # Look-ahead for trivial empty array
    211     nextchar = s[end:end + 1]
    212245    if nextchar == ']':
    213246        return values, end + 1
    214     iterscan = JSONScanner.iterscan
     247    _append = values.append
    215248    while True:
    216249        try:
    217             value, end = iterscan(s, idx=end, context=context).next()
     250            value, end = scan_once(s, end)
    218251        except StopIteration:
    219252            raise ValueError(errmsg("Expecting object", s, end))
    220         values.append(value)
    221         end = _w(s, end).end()
     253        _append(value)
    222254        nextchar = s[end:end + 1]
     255        if nextchar in _ws:
     256            end = _w(s, end + 1).end()
     257            nextchar = s[end:end + 1]
    223258        end += 1
    224259        if nextchar == ']':
    225260            break
    226         if nextchar != ',':
    227             raise ValueError(errmsg("Expecting , delimiter", s, end))
    228         end = _w(s, end).end()
     261        elif nextchar != ',':
     262            raise ValueError(errmsg("Expecting ',' delimiter", s, end))
     263        try:
     264            if s[end] in _ws:
     265                end += 1
     266                if s[end] in _ws:
     267                    end = _w(s, end + 1).end()
     268        except IndexError:
     269            pass
     270
    229271    return values, end
    230 pattern(r'\[')(JSONArray)
    231 
    232 
    233 ANYTHING = [
    234     JSONObject,
    235     JSONArray,
    236     JSONString,
    237     JSONConstant,
    238     JSONNumber,
    239 ]
    240 
    241 JSONScanner = Scanner(ANYTHING)
    242 
    243272
    244273class JSONDecoder(object):
     
    269298    It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
    270299    their corresponding ``float`` values, which is outside the JSON spec.
     300
    271301    """
    272302
    273     _scanner = Scanner(ANYTHING)
    274     __all__ = ['__init__', 'decode', 'raw_decode']
    275 
    276303    def __init__(self, encoding=None, object_hook=None, parse_float=None,
    277             parse_int=None, parse_constant=None, strict=True):
     304            parse_int=None, parse_constant=None, strict=True,
     305            object_pairs_hook=None):
    278306        """``encoding`` determines the encoding used to interpret any ``str``
    279307        objects decoded by this instance (utf-8 by default).  It has no
     
    283311        strings of other encodings should be passed in as ``unicode``.
    284312
    285         ``object_hook``, if specified, will be called with the result of
    286         every JSON object decoded and its return value will be used in
     313        ``object_hook``, if specified, will be called with the result
     314        of every JSON object decoded and its return value will be used in
    287315        place of the given ``dict``.  This can be used to provide custom
    288316        deserializations (e.g. to support JSON-RPC class hinting).
     317
     318        ``object_pairs_hook``, if specified will be called with the result of
     319        every JSON object decoded with an ordered list of pairs.  The return
     320        value of ``object_pairs_hook`` will be used instead of the ``dict``.
     321        This feature can be used to implement custom decoders that rely on the
     322        order that the key and value pairs are decoded (for example,
     323        collections.OrderedDict will remember the order of insertion). If
     324        ``object_hook`` is also defined, the ``object_pairs_hook`` takes
     325        priority.
    289326
    290327        ``parse_float``, if specified, will be called with the string
     
    299336
    300337        ``parse_constant``, if specified, will be called with one of the
    301         following strings: -Infinity, Infinity, NaN, null, true, false.
     338        following strings: -Infinity, Infinity, NaN.
    302339        This can be used to raise an exception if invalid JSON numbers
    303340        are encountered.
     341
     342        If ``strict`` is false (true is the default), then control
     343        characters will be allowed inside strings.  Control characters in
     344        this context are those with character codes in the 0-31 range,
     345        including ``'\\t'`` (tab), ``'\\n'``, ``'\\r'`` and ``'\\0'``.
    304346
    305347        """
    306348        self.encoding = encoding
    307349        self.object_hook = object_hook
    308         self.parse_float = parse_float
    309         self.parse_int = parse_int
    310         self.parse_constant = parse_constant
     350        self.object_pairs_hook = object_pairs_hook
     351        self.parse_float = parse_float or float
     352        self.parse_int = parse_int or int
     353        self.parse_constant = parse_constant or _CONSTANTS.__getitem__
    311354        self.strict = strict
     355        self.parse_object = JSONObject
     356        self.parse_array = JSONArray
     357        self.parse_string = scanstring
     358        self.scan_once = scanner.make_scanner(self)
    312359
    313360    def decode(self, s, _w=WHITESPACE.match):
    314         """
    315         Return the Python representation of ``s`` (a ``str`` or ``unicode``
     361        """Return the Python representation of ``s`` (a ``str`` or ``unicode``
    316362        instance containing a JSON document)
    317363
     
    323369        return obj
    324370
    325     def raw_decode(self, s, **kw):
    326         """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning
    327         with a JSON document) and return a 2-tuple of the Python
     371    def raw_decode(self, s, idx=0):
     372        """Decode a JSON document from ``s`` (a ``str`` or ``unicode``
     373        beginning with a JSON document) and return a 2-tuple of the Python
    328374        representation and the index in ``s`` where the document ended.
    329375
     
    332378
    333379        """
    334         kw.setdefault('context', self)
    335         try:
    336             obj, end = self._scanner.iterscan(s, **kw).next()
     380        try:
     381            obj, end = self.scan_once(s, idx)
    337382        except StopIteration:
    338383            raise ValueError("No JSON object could be decoded")
  • python/trunk/Lib/json/encoder.py

    r2 r391  
    11"""Implementation of JSONEncoder
    22"""
    3 
    43import re
    5 import math
    64
    75try:
     
    97except ImportError:
    108    c_encode_basestring_ascii = None
    11 
    12 __all__ = ['JSONEncoder']
     9try:
     10    from _json import make_encoder as c_make_encoder
     11except ImportError:
     12    c_make_encoder = None
    1313
    1414ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
     
    2626for i in range(0x20):
    2727    ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
    28 
     28    #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
     29
     30INFINITY = float('inf')
    2931FLOAT_REPR = repr
    30 
    31 def floatstr(o, allow_nan=True):
    32     # Check for specials.  Note that this type of test is processor- and/or
    33     # platform-specific, so do tests which don't depend on the internals.
    34 
    35     if math.isnan(o):
    36         text = 'NaN'
    37     elif math.isinf(o):
    38         if math.copysign(1., o) == 1.:
    39             text = 'Infinity'
    40         else:
    41             text = '-Infinity'
    42     else:
    43         return FLOAT_REPR(o)
    44 
    45     if not allow_nan:
    46         msg = "Out of range float values are not JSON compliant: " + repr(o)
    47         raise ValueError(msg)
    48 
    49     return text
    50 
    5132
    5233def encode_basestring(s):
     
    6041
    6142def py_encode_basestring_ascii(s):
     43    """Return an ASCII-only JSON representation of a Python string
     44
     45    """
    6246    if isinstance(s, str) and HAS_UTF8.search(s) is not None:
    6347        s = s.decode('utf-8')
     
    7054            if n < 0x10000:
    7155                return '\\u{0:04x}'.format(n)
     56                #return '\\u%04x' % (n,)
    7257            else:
    7358                # surrogate pair
     
    7661                s2 = 0xdc00 | (n & 0x3ff)
    7762                return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
     63                #return '\\u%04x\\u%04x' % (s1, s2)
    7864    return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
    7965
    8066
    81 if c_encode_basestring_ascii is not None:
    82     encode_basestring_ascii = c_encode_basestring_ascii
    83 else:
    84     encode_basestring_ascii = py_encode_basestring_ascii
    85 
     67encode_basestring_ascii = (
     68    c_encode_basestring_ascii or py_encode_basestring_ascii)
    8669
    8770class JSONEncoder(object):
     
    11497
    11598    """
    116     __all__ = ['__init__', 'default', 'encode', 'iterencode']
    11799    item_separator = ', '
    118100    key_separator = ': '
     
    122104        """Constructor for JSONEncoder, with sensible defaults.
    123105
    124         If skipkeys is False, then it is a TypeError to attempt
     106        If skipkeys is false, then it is a TypeError to attempt
    125107        encoding of keys that are not str, int, long, float or None.  If
    126108        skipkeys is True, such items are simply skipped.
    127109
    128         If ensure_ascii is True, the output is guaranteed to be str
    129         objects with all incoming unicode characters escaped.  If
    130         ensure_ascii is false, the output will be unicode object.
    131 
    132         If check_circular is True, then lists, dicts, and custom encoded
     110        If *ensure_ascii* is true (the default), all non-ASCII
     111        characters in the output are escaped with \uXXXX sequences,
     112        and the results are str instances consisting of ASCII
     113        characters only.  If ensure_ascii is False, a result may be a
     114        unicode instance.  This usually happens if the input contains
     115        unicode strings or the *encoding* parameter is used.
     116
     117        If check_circular is true, then lists, dicts, and custom encoded
    133118        objects will be checked for circular references during encoding to
    134119        prevent an infinite recursion (which would cause an OverflowError).
    135120        Otherwise, no such check takes place.
    136121
    137         If allow_nan is True, then NaN, Infinity, and -Infinity will be
     122        If allow_nan is true, then NaN, Infinity, and -Infinity will be
    138123        encoded as such.  This behavior is not JSON specification compliant,
    139124        but is consistent with most JavaScript based encoders and decoders.
    140125        Otherwise, it will be a ValueError to encode such floats.
    141126
    142         If sort_keys is True, then the output of dictionaries will be
     127        If sort_keys is true, then the output of dictionaries will be
    143128        sorted by key; this is useful for regression tests to ensure
    144129        that JSON serializations can be compared on a day-to-day basis.
     
    147132        elements and object members will be pretty-printed with that
    148133        indent level.  An indent level of 0 will only insert newlines.
    149         None is the most compact representation.
     134        None is the most compact representation.  Since the default
     135        item separator is ', ',  the output might include trailing
     136        whitespace when indent is specified.  You can use
     137        separators=(',', ': ') to avoid this.
    150138
    151139        If specified, separators should be a (item_separator, key_separator)
     
    162150
    163151        """
     152
    164153        self.skipkeys = skipkeys
    165154        self.ensure_ascii = ensure_ascii
     
    168157        self.sort_keys = sort_keys
    169158        self.indent = indent
    170         self.current_indent_level = 0
    171159        if separators is not None:
    172160            self.item_separator, self.key_separator = separators
     
    175163        self.encoding = encoding
    176164
    177     def _newline_indent(self):
    178         return '\n' + (' ' * (self.indent * self.current_indent_level))
    179 
    180     def _iterencode_list(self, lst, markers=None):
    181         if not lst:
    182             yield '[]'
    183             return
    184         if markers is not None:
    185             markerid = id(lst)
    186             if markerid in markers:
    187                 raise ValueError("Circular reference detected")
    188             markers[markerid] = lst
    189         yield '['
    190         if self.indent is not None:
    191             self.current_indent_level += 1
    192             newline_indent = self._newline_indent()
    193             separator = self.item_separator + newline_indent
    194             yield newline_indent
    195         else:
    196             newline_indent = None
    197             separator = self.item_separator
    198         first = True
    199         for value in lst:
    200             if first:
    201                 first = False
    202             else:
    203                 yield separator
    204             for chunk in self._iterencode(value, markers):
    205                 yield chunk
    206         if newline_indent is not None:
    207             self.current_indent_level -= 1
    208             yield self._newline_indent()
    209         yield ']'
    210         if markers is not None:
    211             del markers[markerid]
    212 
    213     def _iterencode_dict(self, dct, markers=None):
    214         if not dct:
    215             yield '{}'
    216             return
    217         if markers is not None:
    218             markerid = id(dct)
    219             if markerid in markers:
    220                 raise ValueError("Circular reference detected")
    221             markers[markerid] = dct
    222         yield '{'
    223         key_separator = self.key_separator
    224         if self.indent is not None:
    225             self.current_indent_level += 1
    226             newline_indent = self._newline_indent()
    227             item_separator = self.item_separator + newline_indent
    228             yield newline_indent
    229         else:
    230             newline_indent = None
    231             item_separator = self.item_separator
    232         first = True
    233         if self.ensure_ascii:
    234             encoder = encode_basestring_ascii
    235         else:
    236             encoder = encode_basestring
    237         allow_nan = self.allow_nan
    238         if self.sort_keys:
    239             keys = dct.keys()
    240             keys.sort()
    241             items = [(k, dct[k]) for k in keys]
    242         else:
    243             items = dct.iteritems()
    244         _encoding = self.encoding
    245         _do_decode = (_encoding is not None
    246             and not (_encoding == 'utf-8'))
    247         for key, value in items:
    248             if isinstance(key, str):
    249                 if _do_decode:
    250                     key = key.decode(_encoding)
    251             elif isinstance(key, basestring):
    252                 pass
    253             # JavaScript is weakly typed for these, so it makes sense to
    254             # also allow them.  Many encoders seem to do something like this.
    255             elif isinstance(key, float):
    256                 key = floatstr(key, allow_nan)
    257             elif isinstance(key, (int, long)):
    258                 key = str(key)
    259             elif key is True:
    260                 key = 'true'
    261             elif key is False:
    262                 key = 'false'
    263             elif key is None:
    264                 key = 'null'
    265             elif self.skipkeys:
    266                 continue
    267             else:
    268                 raise TypeError("key {0!r} is not a string".format(key))
    269             if first:
    270                 first = False
    271             else:
    272                 yield item_separator
    273             yield encoder(key)
    274             yield key_separator
    275             for chunk in self._iterencode(value, markers):
    276                 yield chunk
    277         if newline_indent is not None:
    278             self.current_indent_level -= 1
    279             yield self._newline_indent()
    280         yield '}'
    281         if markers is not None:
    282             del markers[markerid]
    283 
    284     def _iterencode(self, o, markers=None):
    285         if isinstance(o, basestring):
    286             if self.ensure_ascii:
    287                 encoder = encode_basestring_ascii
    288             else:
    289                 encoder = encode_basestring
    290             _encoding = self.encoding
    291             if (_encoding is not None and isinstance(o, str)
    292                     and not (_encoding == 'utf-8')):
    293                 o = o.decode(_encoding)
    294             yield encoder(o)
    295         elif o is None:
    296             yield 'null'
    297         elif o is True:
    298             yield 'true'
    299         elif o is False:
    300             yield 'false'
    301         elif isinstance(o, (int, long)):
    302             yield str(o)
    303         elif isinstance(o, float):
    304             yield floatstr(o, self.allow_nan)
    305         elif isinstance(o, (list, tuple)):
    306             for chunk in self._iterencode_list(o, markers):
    307                 yield chunk
    308         elif isinstance(o, dict):
    309             for chunk in self._iterencode_dict(o, markers):
    310                 yield chunk
    311         else:
    312             if markers is not None:
    313                 markerid = id(o)
    314                 if markerid in markers:
    315                     raise ValueError("Circular reference detected")
    316                 markers[markerid] = o
    317             for chunk in self._iterencode_default(o, markers):
    318                 yield chunk
    319             if markers is not None:
    320                 del markers[markerid]
    321 
    322     def _iterencode_default(self, o, markers=None):
    323         newobj = self.default(o)
    324         return self._iterencode(newobj, markers)
    325 
    326165    def default(self, o):
    327         """Implement this method in a subclass such that it returns a serializable
    328         object for ``o``, or calls the base implementation (to raise a
    329         ``TypeError``).
    330 
    331         For example, to support arbitrary iterators, you could implement
    332         default like this::
     166        """Implement this method in a subclass such that it returns
     167        a serializable object for ``o``, or calls the base implementation
     168        (to raise a ``TypeError``).
     169
     170        For example, to support arbitrary iterators, you could
     171        implement default like this::
    333172
    334173            def default(self, o):
     
    339178                else:
    340179                    return list(iterable)
     180                # Let the base class default method raise the TypeError
    341181                return JSONEncoder.default(self, o)
    342182
     
    365205        # exceptions aren't as detailed.  The list call should be roughly
    366206        # equivalent to the PySequence_Fast that ''.join() would do.
    367         chunks = list(self.iterencode(o))
     207        chunks = self.iterencode(o, _one_shot=True)
     208        if not isinstance(chunks, (list, tuple)):
     209            chunks = list(chunks)
    368210        return ''.join(chunks)
    369211
    370     def iterencode(self, o):
    371         """Encode the given object and yield each string representation as
    372         available.
     212    def iterencode(self, o, _one_shot=False):
     213        """Encode the given object and yield each string
     214        representation as available.
    373215
    374216        For example::
     
    382224        else:
    383225            markers = None
    384         return self._iterencode(o, markers)
     226        if self.ensure_ascii:
     227            _encoder = encode_basestring_ascii
     228        else:
     229            _encoder = encode_basestring
     230        if self.encoding != 'utf-8':
     231            def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
     232                if isinstance(o, str):
     233                    o = o.decode(_encoding)
     234                return _orig_encoder(o)
     235
     236        def floatstr(o, allow_nan=self.allow_nan,
     237                _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
     238            # Check for specials.  Note that this type of test is processor
     239            # and/or platform-specific, so do tests which don't depend on the
     240            # internals.
     241
     242            if o != o:
     243                text = 'NaN'
     244            elif o == _inf:
     245                text = 'Infinity'
     246            elif o == _neginf:
     247                text = '-Infinity'
     248            else:
     249                return _repr(o)
     250
     251            if not allow_nan:
     252                raise ValueError(
     253                    "Out of range float values are not JSON compliant: " +
     254                    repr(o))
     255
     256            return text
     257
     258
     259        if (_one_shot and c_make_encoder is not None
     260                and self.indent is None and not self.sort_keys):
     261            _iterencode = c_make_encoder(
     262                markers, self.default, _encoder, self.indent,
     263                self.key_separator, self.item_separator, self.sort_keys,
     264                self.skipkeys, self.allow_nan)
     265        else:
     266            _iterencode = _make_iterencode(
     267                markers, self.default, _encoder, self.indent, floatstr,
     268                self.key_separator, self.item_separator, self.sort_keys,
     269                self.skipkeys, _one_shot)
     270        return _iterencode(o, 0)
     271
     272def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
     273        _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
     274        ## HACK: hand-optimized bytecode; turn globals into locals
     275        ValueError=ValueError,
     276        basestring=basestring,
     277        dict=dict,
     278        float=float,
     279        id=id,
     280        int=int,
     281        isinstance=isinstance,
     282        list=list,
     283        long=long,
     284        str=str,
     285        tuple=tuple,
     286    ):
     287
     288    def _iterencode_list(lst, _current_indent_level):
     289        if not lst:
     290            yield '[]'
     291            return
     292        if markers is not None:
     293            markerid = id(lst)
     294            if markerid in markers:
     295                raise ValueError("Circular reference detected")
     296            markers[markerid] = lst
     297        buf = '['
     298        if _indent is not None:
     299            _current_indent_level += 1
     300            newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
     301            separator = _item_separator + newline_indent
     302            buf += newline_indent
     303        else:
     304            newline_indent = None
     305            separator = _item_separator
     306        first = True
     307        for value in lst:
     308            if first:
     309                first = False
     310            else:
     311                buf = separator
     312            if isinstance(value, basestring):
     313                yield buf + _encoder(value)
     314            elif value is None:
     315                yield buf + 'null'
     316            elif value is True:
     317                yield buf + 'true'
     318            elif value is False:
     319                yield buf + 'false'
     320            elif isinstance(value, (int, long)):
     321                yield buf + str(value)
     322            elif isinstance(value, float):
     323                yield buf + _floatstr(value)
     324            else:
     325                yield buf
     326                if isinstance(value, (list, tuple)):
     327                    chunks = _iterencode_list(value, _current_indent_level)
     328                elif isinstance(value, dict):
     329                    chunks = _iterencode_dict(value, _current_indent_level)
     330                else:
     331                    chunks = _iterencode(value, _current_indent_level)
     332                for chunk in chunks:
     333                    yield chunk
     334        if newline_indent is not None:
     335            _current_indent_level -= 1
     336            yield '\n' + (' ' * (_indent * _current_indent_level))
     337        yield ']'
     338        if markers is not None:
     339            del markers[markerid]
     340
     341    def _iterencode_dict(dct, _current_indent_level):
     342        if not dct:
     343            yield '{}'
     344            return
     345        if markers is not None:
     346            markerid = id(dct)
     347            if markerid in markers:
     348                raise ValueError("Circular reference detected")
     349            markers[markerid] = dct
     350        yield '{'
     351        if _indent is not None:
     352            _current_indent_level += 1
     353            newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
     354            item_separator = _item_separator + newline_indent
     355            yield newline_indent
     356        else:
     357            newline_indent = None
     358            item_separator = _item_separator
     359        first = True
     360        if _sort_keys:
     361            items = sorted(dct.items(), key=lambda kv: kv[0])
     362        else:
     363            items = dct.iteritems()
     364        for key, value in items:
     365            if isinstance(key, basestring):
     366                pass
     367            # JavaScript is weakly typed for these, so it makes sense to
     368            # also allow them.  Many encoders seem to do something like this.
     369            elif isinstance(key, float):
     370                key = _floatstr(key)
     371            elif key is True:
     372                key = 'true'
     373            elif key is False:
     374                key = 'false'
     375            elif key is None:
     376                key = 'null'
     377            elif isinstance(key, (int, long)):
     378                key = str(key)
     379            elif _skipkeys:
     380                continue
     381            else:
     382                raise TypeError("key " + repr(key) + " is not a string")
     383            if first:
     384                first = False
     385            else:
     386                yield item_separator
     387            yield _encoder(key)
     388            yield _key_separator
     389            if isinstance(value, basestring):
     390                yield _encoder(value)
     391            elif value is None:
     392                yield 'null'
     393            elif value is True:
     394                yield 'true'
     395            elif value is False:
     396                yield 'false'
     397            elif isinstance(value, (int, long)):
     398                yield str(value)
     399            elif isinstance(value, float):
     400                yield _floatstr(value)
     401            else:
     402                if isinstance(value, (list, tuple)):
     403                    chunks = _iterencode_list(value, _current_indent_level)
     404                elif isinstance(value, dict):
     405                    chunks = _iterencode_dict(value, _current_indent_level)
     406                else:
     407                    chunks = _iterencode(value, _current_indent_level)
     408                for chunk in chunks:
     409                    yield chunk
     410        if newline_indent is not None:
     411            _current_indent_level -= 1
     412            yield '\n' + (' ' * (_indent * _current_indent_level))
     413        yield '}'
     414        if markers is not None:
     415            del markers[markerid]
     416
     417    def _iterencode(o, _current_indent_level):
     418        if isinstance(o, basestring):
     419            yield _encoder(o)
     420        elif o is None:
     421            yield 'null'
     422        elif o is True:
     423            yield 'true'
     424        elif o is False:
     425            yield 'false'
     426        elif isinstance(o, (int, long)):
     427            yield str(o)
     428        elif isinstance(o, float):
     429            yield _floatstr(o)
     430        elif isinstance(o, (list, tuple)):
     431            for chunk in _iterencode_list(o, _current_indent_level):
     432                yield chunk
     433        elif isinstance(o, dict):
     434            for chunk in _iterencode_dict(o, _current_indent_level):
     435                yield chunk
     436        else:
     437            if markers is not None:
     438                markerid = id(o)
     439                if markerid in markers:
     440                    raise ValueError("Circular reference detected")
     441                markers[markerid] = o
     442            o = _default(o)
     443            for chunk in _iterencode(o, _current_indent_level):
     444                yield chunk
     445            if markers is not None:
     446                del markers[markerid]
     447
     448    return _iterencode
  • python/trunk/Lib/json/scanner.py

    r2 r391  
    1 """Iterator based sre token scanner
     1"""JSON token scanner
     2"""
     3import re
     4try:
     5    from _json import make_scanner as c_make_scanner
     6except ImportError:
     7    c_make_scanner = None
    28
    3 """
     9__all__ = ['make_scanner']
    410
    5 import re
    6 import sre_parse
    7 import sre_compile
    8 import sre_constants
     11NUMBER_RE = re.compile(
     12    r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
     13    (re.VERBOSE | re.MULTILINE | re.DOTALL))
    914
    10 from re import VERBOSE, MULTILINE, DOTALL
    11 from sre_constants import BRANCH, SUBPATTERN
     15def py_make_scanner(context):
     16    parse_object = context.parse_object
     17    parse_array = context.parse_array
     18    parse_string = context.parse_string
     19    match_number = NUMBER_RE.match
     20    encoding = context.encoding
     21    strict = context.strict
     22    parse_float = context.parse_float
     23    parse_int = context.parse_int
     24    parse_constant = context.parse_constant
     25    object_hook = context.object_hook
     26    object_pairs_hook = context.object_pairs_hook
    1227
    13 __all__ = ['Scanner', 'pattern']
     28    def _scan_once(string, idx):
     29        try:
     30            nextchar = string[idx]
     31        except IndexError:
     32            raise StopIteration
    1433
    15 FLAGS = (VERBOSE | MULTILINE | DOTALL)
     34        if nextchar == '"':
     35            return parse_string(string, idx + 1, encoding, strict)
     36        elif nextchar == '{':
     37            return parse_object((string, idx + 1), encoding, strict,
     38                _scan_once, object_hook, object_pairs_hook)
     39        elif nextchar == '[':
     40            return parse_array((string, idx + 1), _scan_once)
     41        elif nextchar == 'n' and string[idx:idx + 4] == 'null':
     42            return None, idx + 4
     43        elif nextchar == 't' and string[idx:idx + 4] == 'true':
     44            return True, idx + 4
     45        elif nextchar == 'f' and string[idx:idx + 5] == 'false':
     46            return False, idx + 5
    1647
    17 class Scanner(object):
    18     def __init__(self, lexicon, flags=FLAGS):
    19         self.actions = [None]
    20         # Combine phrases into a compound pattern
    21         s = sre_parse.Pattern()
    22         s.flags = flags
    23         p = []
    24         for idx, token in enumerate(lexicon):
    25             phrase = token.pattern
    26             try:
    27                 subpattern = sre_parse.SubPattern(s,
    28                     [(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))])
    29             except sre_constants.error:
    30                 raise
    31             p.append(subpattern)
    32             self.actions.append(token)
     48        m = match_number(string, idx)
     49        if m is not None:
     50            integer, frac, exp = m.groups()
     51            if frac or exp:
     52                res = parse_float(integer + (frac or '') + (exp or ''))
     53            else:
     54                res = parse_int(integer)
     55            return res, m.end()
     56        elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
     57            return parse_constant('NaN'), idx + 3
     58        elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
     59            return parse_constant('Infinity'), idx + 8
     60        elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
     61            return parse_constant('-Infinity'), idx + 9
     62        else:
     63            raise StopIteration
    3364
    34         s.groups = len(p) + 1 # NOTE(guido): Added to make SRE validation work
    35         p = sre_parse.SubPattern(s, [(BRANCH, (None, p))])
    36         self.scanner = sre_compile.compile(p)
     65    return _scan_once
    3766
    38     def iterscan(self, string, idx=0, context=None):
    39         """Yield match, end_idx for each match
    40 
    41         """
    42         match = self.scanner.scanner(string, idx).match
    43         actions = self.actions
    44         lastend = idx
    45         end = len(string)
    46         while True:
    47             m = match()
    48             if m is None:
    49                 break
    50             matchbegin, matchend = m.span()
    51             if lastend == matchend:
    52                 break
    53             action = actions[m.lastindex]
    54             if action is not None:
    55                 rval, next_pos = action(m, context)
    56                 if next_pos is not None and next_pos != matchend:
    57                     # "fast forward" the scanner
    58                     matchend = next_pos
    59                     match = self.scanner.scanner(string, matchend).match
    60                 yield rval, matchend
    61             lastend = matchend
    62 
    63 
    64 def pattern(pattern, flags=FLAGS):
    65     def decorator(fn):
    66         fn.pattern = pattern
    67         fn.regex = re.compile(pattern, flags)
    68         return fn
    69     return decorator
     67make_scanner = c_make_scanner or py_make_scanner
  • python/trunk/Lib/json/tests/__init__.py

    r2 r391  
    11import os
    22import sys
     3import json
     4import doctest
    35import unittest
    4 import doctest
     6
     7from test import test_support
     8
     9# import json with and without accelerations
     10cjson = test_support.import_fresh_module('json', fresh=['_json'])
     11pyjson = test_support.import_fresh_module('json', blocked=['_json'])
     12
     13# create two base classes that will be used by the other tests
     14class PyTest(unittest.TestCase):
     15    json = pyjson
     16    loads = staticmethod(pyjson.loads)
     17    dumps = staticmethod(pyjson.dumps)
     18
     19@unittest.skipUnless(cjson, 'requires _json')
     20class CTest(unittest.TestCase):
     21    if cjson is not None:
     22        json = cjson
     23        loads = staticmethod(cjson.loads)
     24        dumps = staticmethod(cjson.dumps)
     25
     26# test PyTest and CTest checking if the functions come from the right module
     27class TestPyTest(PyTest):
     28    def test_pyjson(self):
     29        self.assertEqual(self.json.scanner.make_scanner.__module__,
     30                         'json.scanner')
     31        self.assertEqual(self.json.decoder.scanstring.__module__,
     32                         'json.decoder')
     33        self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__,
     34                         'json.encoder')
     35
     36class TestCTest(CTest):
     37    def test_cjson(self):
     38        self.assertEqual(self.json.scanner.make_scanner.__module__, '_json')
     39        self.assertEqual(self.json.decoder.scanstring.__module__, '_json')
     40        self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json')
     41        self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__,
     42                         '_json')
     43
    544
    645here = os.path.dirname(__file__)
     
    1857
    1958def additional_tests():
    20     import json
    21     import json.encoder
    22     import json.decoder
    2359    suite = unittest.TestSuite()
    2460    for mod in (json, json.encoder, json.decoder):
    2561        suite.addTest(doctest.DocTestSuite(mod))
     62    suite.addTest(TestPyTest('test_pyjson'))
     63    suite.addTest(TestCTest('test_cjson'))
    2664    return suite
    2765
  • python/trunk/Lib/json/tests/test_decode.py

    r2 r391  
    11import decimal
    2 from unittest import TestCase
     2from StringIO import StringIO
     3from collections import OrderedDict
     4from json.tests import PyTest, CTest
    35
    4 import json
    56
    6 class TestDecode(TestCase):
     7class TestDecode(object):
    78    def test_decimal(self):
    8         rval = json.loads('1.1', parse_float=decimal.Decimal)
    9         self.assert_(isinstance(rval, decimal.Decimal))
    10         self.assertEquals(rval, decimal.Decimal('1.1'))
     9        rval = self.loads('1.1', parse_float=decimal.Decimal)
     10        self.assertTrue(isinstance(rval, decimal.Decimal))
     11        self.assertEqual(rval, decimal.Decimal('1.1'))
    1112
    1213    def test_float(self):
    13         rval = json.loads('1', parse_int=float)
    14         self.assert_(isinstance(rval, float))
    15         self.assertEquals(rval, 1.0)
     14        rval = self.loads('1', parse_int=float)
     15        self.assertTrue(isinstance(rval, float))
     16        self.assertEqual(rval, 1.0)
     17
     18    def test_decoder_optimizations(self):
     19        # Several optimizations were made that skip over calls to
     20        # the whitespace regex, so this test is designed to try and
     21        # exercise the uncommon cases. The array cases are already covered.
     22        rval = self.loads('{   "key"    :    "value"    ,  "k":"v"    }')
     23        self.assertEqual(rval, {"key":"value", "k":"v"})
     24
     25    def test_empty_objects(self):
     26        self.assertEqual(self.loads('{}'), {})
     27        self.assertEqual(self.loads('[]'), [])
     28        self.assertEqual(self.loads('""'), u"")
     29        self.assertIsInstance(self.loads('""'), unicode)
     30
     31    def test_object_pairs_hook(self):
     32        s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}'
     33        p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4),
     34             ("qrt", 5), ("pad", 6), ("hoy", 7)]
     35        self.assertEqual(self.loads(s), eval(s))
     36        self.assertEqual(self.loads(s, object_pairs_hook=lambda x: x), p)
     37        self.assertEqual(self.json.load(StringIO(s),
     38                                        object_pairs_hook=lambda x: x), p)
     39        od = self.loads(s, object_pairs_hook=OrderedDict)
     40        self.assertEqual(od, OrderedDict(p))
     41        self.assertEqual(type(od), OrderedDict)
     42        # the object_pairs_hook takes priority over the object_hook
     43        self.assertEqual(self.loads(s, object_pairs_hook=OrderedDict,
     44                                    object_hook=lambda x: None),
     45                         OrderedDict(p))
     46        # check that empty objects literals work (see #17368)
     47        self.assertEqual(self.loads('{}', object_pairs_hook=OrderedDict),
     48                         OrderedDict())
     49        self.assertEqual(self.loads('{"empty": {}}',
     50                                    object_pairs_hook=OrderedDict),
     51                         OrderedDict([('empty', OrderedDict())]))
     52
     53    def test_extra_data(self):
     54        s = '[1, 2, 3]5'
     55        msg = 'Extra data'
     56        self.assertRaisesRegexp(ValueError, msg, self.loads, s)
     57
     58    def test_invalid_escape(self):
     59        s = '["abc\\y"]'
     60        msg = 'escape'
     61        self.assertRaisesRegexp(ValueError, msg, self.loads, s)
     62
     63class TestPyDecode(TestDecode, PyTest): pass
     64class TestCDecode(TestDecode, CTest): pass
  • python/trunk/Lib/json/tests/test_default.py

    r2 r391  
    1 from unittest import TestCase
     1from json.tests import PyTest, CTest
    22
    3 import json
    43
    5 class TestDefault(TestCase):
     4class TestDefault(object):
    65    def test_default(self):
    7         self.assertEquals(
    8             json.dumps(type, default=repr),
    9             json.dumps(repr(type)))
     6        self.assertEqual(
     7            self.dumps(type, default=repr),
     8            self.dumps(repr(type)))
     9
     10
     11class TestPyDefault(TestDefault, PyTest): pass
     12class TestCDefault(TestDefault, CTest): pass
  • python/trunk/Lib/json/tests/test_dump.py

    r2 r391  
    1 from unittest import TestCase
    21from cStringIO import StringIO
     2from json.tests import PyTest, CTest
    33
    4 import json
    54
    6 class TestDump(TestCase):
     5class TestDump(object):
    76    def test_dump(self):
    87        sio = StringIO()
    9         json.dump({}, sio)
    10         self.assertEquals(sio.getvalue(), '{}')
     8        self.json.dump({}, sio)
     9        self.assertEqual(sio.getvalue(), '{}')
    1110
    1211    def test_dumps(self):
    13         self.assertEquals(json.dumps({}), '{}')
     12        self.assertEqual(self.dumps({}), '{}')
     13
     14    def test_encode_truefalse(self):
     15        self.assertEqual(self.dumps(
     16                 {True: False, False: True}, sort_keys=True),
     17                 '{"false": true, "true": false}')
     18        self.assertEqual(self.dumps(
     19                {2: 3.0, 4.0: 5L, False: 1, 6L: True}, sort_keys=True),
     20                '{"false": 1, "2": 3.0, "4.0": 5, "6": true}')
     21
     22    # Issue 16228: Crash on encoding resized list
     23    def test_encode_mutated(self):
     24        a = [object()] * 10
     25        def crasher(obj):
     26            del a[-1]
     27        self.assertEqual(self.dumps(a, default=crasher),
     28                 '[null, null, null, null, null]')
     29
     30
     31class TestPyDump(TestDump, PyTest): pass
     32class TestCDump(TestDump, CTest): pass
  • python/trunk/Lib/json/tests/test_encode_basestring_ascii.py

    r2 r391  
    1 from unittest import TestCase
     1from collections import OrderedDict
     2from json.tests import PyTest, CTest
    23
    3 import json.encoder
    44
    55CASES = [
     
    2222]
    2323
    24 class TestEncodeBaseStringAscii(TestCase):
    25     def test_py_encode_basestring_ascii(self):
    26         self._test_encode_basestring_ascii(json.encoder.py_encode_basestring_ascii)
     24class TestEncodeBasestringAscii(object):
     25    def test_encode_basestring_ascii(self):
     26        fname = self.json.encoder.encode_basestring_ascii.__name__
     27        for input_string, expect in CASES:
     28            result = self.json.encoder.encode_basestring_ascii(input_string)
     29            self.assertEqual(result, expect,
     30                '{0!r} != {1!r} for {2}({3!r})'.format(
     31                    result, expect, fname, input_string))
    2732
    28     def test_c_encode_basestring_ascii(self):
    29         self._test_encode_basestring_ascii(json.encoder.c_encode_basestring_ascii)
     33    def test_ordered_dict(self):
     34        # See issue 6105
     35        items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
     36        s = self.dumps(OrderedDict(items))
     37        self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}')
    3038
    31     def _test_encode_basestring_ascii(self, encode_basestring_ascii):
    32         fname = encode_basestring_ascii.__name__
    33         for input_string, expect in CASES:
    34             result = encode_basestring_ascii(input_string)
    35             self.assertEquals(result, expect)
     39
     40class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass
     41class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass
  • python/trunk/Lib/json/tests/test_fail.py

    r2 r391  
    1 from unittest import TestCase
     1from json.tests import PyTest, CTest
    22
    3 import json
    4 
    5 # Fri Dec 30 18:57:26 2005
     3# 2007-10-05
    64JSONDOCS = [
    75    # http://json.org/JSON_checker/test/fail1.json
     
    108    '["Unclosed array"',
    119    # http://json.org/JSON_checker/test/fail3.json
    12     '{unquoted_key: "keys must be quoted}',
     10    '{unquoted_key: "keys must be quoted"}',
    1311    # http://json.org/JSON_checker/test/fail4.json
    1412    '["extra comma",]',
     
    3634    '["Illegal backslash escape: \\x15"]',
    3735    # http://json.org/JSON_checker/test/fail16.json
    38     '["Illegal backslash escape: \\\'"]',
     36    '[\\naked]',
    3937    # http://json.org/JSON_checker/test/fail17.json
    4038    '["Illegal backslash escape: \\017"]',
     
    5351    # http://json.org/JSON_checker/test/fail24.json
    5452    "['single quote']",
     53    # http://json.org/JSON_checker/test/fail25.json
     54    '["\ttab\tcharacter\tin\tstring\t"]',
     55    # http://json.org/JSON_checker/test/fail26.json
     56    '["tab\\   character\\   in\\  string\\  "]',
     57    # http://json.org/JSON_checker/test/fail27.json
     58    '["line\nbreak"]',
     59    # http://json.org/JSON_checker/test/fail28.json
     60    '["line\\\nbreak"]',
     61    # http://json.org/JSON_checker/test/fail29.json
     62    '[0e]',
     63    # http://json.org/JSON_checker/test/fail30.json
     64    '[0e+]',
     65    # http://json.org/JSON_checker/test/fail31.json
     66    '[0e+-1]',
     67    # http://json.org/JSON_checker/test/fail32.json
     68    '{"Comma instead if closing brace": true,',
     69    # http://json.org/JSON_checker/test/fail33.json
     70    '["mismatch"}',
    5571    # http://code.google.com/p/simplejson/issues/detail?id=3
    5672    u'["A\u001FZ control characters in string"]',
     
    6278}
    6379
    64 class TestFail(TestCase):
     80class TestFail(object):
    6581    def test_failures(self):
    6682        for idx, doc in enumerate(JSONDOCS):
    6783            idx = idx + 1
    6884            if idx in SKIPS:
    69                 json.loads(doc)
     85                self.loads(doc)
    7086                continue
    7187            try:
    72                 json.loads(doc)
     88                self.loads(doc)
    7389            except ValueError:
    7490                pass
    7591            else:
    76                 self.fail("Expected failure for fail%d.json: %r" % (idx, doc))
     92                self.fail("Expected failure for fail{0}.json: {1!r}".format(idx, doc))
     93
     94    def test_non_string_keys_dict(self):
     95        data = {'a' : 1, (1, 2) : 2}
     96
     97        #This is for c encoder
     98        self.assertRaises(TypeError, self.dumps, data)
     99
     100        #This is for python encoder
     101        self.assertRaises(TypeError, self.dumps, data, indent=True)
     102
     103
     104class TestPyFail(TestFail, PyTest): pass
     105class TestCFail(TestFail, CTest): pass
  • python/trunk/Lib/json/tests/test_float.py

    r2 r391  
    11import math
    2 from unittest import TestCase
     2from json.tests import PyTest, CTest
    33
    4 import json
    54
    6 class TestFloat(TestCase):
     5class TestFloat(object):
    76    def test_floats(self):
    8         for num in [1617161771.7650001, math.pi, math.pi**100, math.pi**-100]:
    9             self.assertEquals(float(json.dumps(num)), num)
     7        for num in [1617161771.7650001, math.pi, math.pi**100,
     8                    math.pi**-100, 3.1]:
     9            self.assertEqual(float(self.dumps(num)), num)
     10            self.assertEqual(self.loads(self.dumps(num)), num)
     11            self.assertEqual(self.loads(unicode(self.dumps(num))), num)
     12
     13    def test_ints(self):
     14        for num in [1, 1L, 1<<32, 1<<64]:
     15            self.assertEqual(self.dumps(num), str(num))
     16            self.assertEqual(int(self.dumps(num)), num)
     17            self.assertEqual(self.loads(self.dumps(num)), num)
     18            self.assertEqual(self.loads(unicode(self.dumps(num))), num)
     19
     20    def test_out_of_range(self):
     21        self.assertEqual(self.loads('[23456789012E666]'), [float('inf')])
     22        self.assertEqual(self.loads('[-23456789012E666]'), [float('-inf')])
     23
     24    def test_allow_nan(self):
     25        for val in (float('inf'), float('-inf'), float('nan')):
     26            out = self.dumps([val])
     27            if val == val:  # inf
     28                self.assertEqual(self.loads(out), [val])
     29            else:  # nan
     30                res = self.loads(out)
     31                self.assertEqual(len(res), 1)
     32                self.assertNotEqual(res[0], res[0])
     33            self.assertRaises(ValueError, self.dumps, [val], allow_nan=False)
     34
     35
     36class TestPyFloat(TestFloat, PyTest): pass
     37class TestCFloat(TestFloat, CTest): pass
  • python/trunk/Lib/json/tests/test_indent.py

    r2 r391  
    1 from unittest import TestCase
     1import textwrap
     2from StringIO import StringIO
     3from json.tests import PyTest, CTest
    24
    3 import json
    4 import textwrap
    55
    6 class TestIndent(TestCase):
     6class TestIndent(object):
    77    def test_indent(self):
    88        h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth',
     
    3131
    3232
    33         d1 = json.dumps(h)
    34         d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': '))
     33        d1 = self.dumps(h)
     34        d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': '))
    3535
    36         h1 = json.loads(d1)
    37         h2 = json.loads(d2)
     36        h1 = self.loads(d1)
     37        h2 = self.loads(d2)
    3838
    39         self.assertEquals(h1, h)
    40         self.assertEquals(h2, h)
    41         self.assertEquals(d2, expect)
     39        self.assertEqual(h1, h)
     40        self.assertEqual(h2, h)
     41        self.assertEqual(d2, expect)
     42
     43    def test_indent0(self):
     44        h = {3: 1}
     45        def check(indent, expected):
     46            d1 = self.dumps(h, indent=indent)
     47            self.assertEqual(d1, expected)
     48
     49            sio = StringIO()
     50            self.json.dump(h, sio, indent=indent)
     51            self.assertEqual(sio.getvalue(), expected)
     52
     53        # indent=0 should emit newlines
     54        check(0, '{\n"3": 1\n}')
     55        # indent=None is more compact
     56        check(None, '{"3": 1}')
     57
     58
     59class TestPyIndent(TestIndent, PyTest): pass
     60class TestCIndent(TestIndent, CTest): pass
  • python/trunk/Lib/json/tests/test_pass1.py

    r2 r391  
    1 from unittest import TestCase
     1from json.tests import PyTest, CTest
    22
    3 import json
    43
    54# from http://json.org/JSON_checker/test/pass1.json
     
    1918        "e": 0.123456789e-12,
    2019        "E": 1.234567890E+34,
    21         "":  23456789012E666,
     20        "":  23456789012E66,
    2221        "zero": 0,
    2322        "one": 1,
     
    3029        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
    3130        "digit": "0123456789",
     31        "0123456789": "digit",
    3232        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
    3333        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
     
    4545,
    4646
    47 4 , 5        ,          6           ,7        ],
    48         "compact": [1,2,3,4,5,6,7],
     474 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
    4948        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
    5049        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
     
    5756,
    5857
    59 1066
    60 
    61 
     581066,
     591e1,
     600.1e1,
     611e-1,
     621e00,2e+00,2e-00
    6263,"rosebud"]
    6364'''
    6465
    65 class TestPass1(TestCase):
     66class TestPass1(object):
    6667    def test_parse(self):
    6768        # test in/out equivalence and parsing
    68         res = json.loads(JSON)
    69         out = json.dumps(res)
    70         self.assertEquals(res, json.loads(out))
    71         try:
    72             json.dumps(res, allow_nan=False)
    73         except ValueError:
    74             pass
    75         else:
    76             self.fail("23456789012E666 should be out of range")
     69        res = self.loads(JSON)
     70        out = self.dumps(res)
     71        self.assertEqual(res, self.loads(out))
     72
     73
     74class TestPyPass1(TestPass1, PyTest): pass
     75class TestCPass1(TestPass1, CTest): pass
  • python/trunk/Lib/json/tests/test_pass2.py

    r2 r391  
    1 from unittest import TestCase
    2 import json
     1from json.tests import PyTest, CTest
     2
    33
    44# from http://json.org/JSON_checker/test/pass2.json
     
    77'''
    88
    9 class TestPass2(TestCase):
     9class TestPass2(object):
    1010    def test_parse(self):
    1111        # test in/out equivalence and parsing
    12         res = json.loads(JSON)
    13         out = json.dumps(res)
    14         self.assertEquals(res, json.loads(out))
     12        res = self.loads(JSON)
     13        out = self.dumps(res)
     14        self.assertEqual(res, self.loads(out))
     15
     16
     17class TestPyPass2(TestPass2, PyTest): pass
     18class TestCPass2(TestPass2, CTest): pass
  • python/trunk/Lib/json/tests/test_pass3.py

    r2 r391  
    1 from unittest import TestCase
     1from json.tests import PyTest, CTest
    22
    3 import json
    43
    54# from http://json.org/JSON_checker/test/pass3.json
     
    1312'''
    1413
    15 class TestPass3(TestCase):
     14
     15class TestPass3(object):
    1616    def test_parse(self):
    1717        # test in/out equivalence and parsing
    18         res = json.loads(JSON)
    19         out = json.dumps(res)
    20         self.assertEquals(res, json.loads(out))
     18        res = self.loads(JSON)
     19        out = self.dumps(res)
     20        self.assertEqual(res, self.loads(out))
     21
     22
     23class TestPyPass3(TestPass3, PyTest): pass
     24class TestCPass3(TestPass3, CTest): pass
  • python/trunk/Lib/json/tests/test_recursion.py

    r2 r391  
    1 from unittest import TestCase
     1from json.tests import PyTest, CTest
    22
    3 import json
    43
    54class JSONTestObject:
     
    76
    87
    9 class RecursiveJSONEncoder(json.JSONEncoder):
    10     recurse = False
    11     def default(self, o):
    12         if o is JSONTestObject:
    13             if self.recurse:
    14                 return [JSONTestObject]
    15             else:
    16                 return 'JSONTestObject'
    17         return json.JSONEncoder.default(o)
    18 
    19 
    20 class TestRecursion(TestCase):
     8class TestRecursion(object):
    219    def test_listrecursion(self):
    2210        x = []
    2311        x.append(x)
    2412        try:
    25             json.dumps(x)
     13            self.dumps(x)
    2614        except ValueError:
    2715            pass
     
    3220        x.append(y)
    3321        try:
    34             json.dumps(x)
     22            self.dumps(x)
    3523        except ValueError:
    3624            pass
     
    4028        x = [y, y]
    4129        # ensure that the marker is cleared
    42         json.dumps(x)
     30        self.dumps(x)
    4331
    4432    def test_dictrecursion(self):
     
    4634        x["test"] = x
    4735        try:
    48             json.dumps(x)
     36            self.dumps(x)
    4937        except ValueError:
    5038            pass
     
    5442        y = {"a": x, "b": x}
    5543        # ensure that the marker is cleared
    56         json.dumps(x)
     44        self.dumps(x)
    5745
    5846    def test_defaultrecursion(self):
     47        class RecursiveJSONEncoder(self.json.JSONEncoder):
     48            recurse = False
     49            def default(self, o):
     50                if o is JSONTestObject:
     51                    if self.recurse:
     52                        return [JSONTestObject]
     53                    else:
     54                        return 'JSONTestObject'
     55                return pyjson.JSONEncoder.default(o)
     56
    5957        enc = RecursiveJSONEncoder()
    60         self.assertEquals(enc.encode(JSONTestObject), '"JSONTestObject"')
     58        self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"')
    6159        enc.recurse = True
    6260        try:
     
    6664        else:
    6765            self.fail("didn't raise ValueError on default recursion")
     66
     67
     68    def test_highly_nested_objects_decoding(self):
     69        # test that loading highly-nested objects doesn't segfault when C
     70        # accelerations are used. See #12017
     71        # str
     72        with self.assertRaises(RuntimeError):
     73            self.loads('{"a":' * 100000 + '1' + '}' * 100000)
     74        with self.assertRaises(RuntimeError):
     75            self.loads('{"a":' * 100000 + '[1]' + '}' * 100000)
     76        with self.assertRaises(RuntimeError):
     77            self.loads('[' * 100000 + '1' + ']' * 100000)
     78        # unicode
     79        with self.assertRaises(RuntimeError):
     80            self.loads(u'{"a":' * 100000 + u'1' + u'}' * 100000)
     81        with self.assertRaises(RuntimeError):
     82            self.loads(u'{"a":' * 100000 + u'[1]' + u'}' * 100000)
     83        with self.assertRaises(RuntimeError):
     84            self.loads(u'[' * 100000 + u'1' + u']' * 100000)
     85
     86    def test_highly_nested_objects_encoding(self):
     87        # See #12051
     88        l, d = [], {}
     89        for x in xrange(100000):
     90            l, d = [l], {'k':d}
     91        with self.assertRaises(RuntimeError):
     92            self.dumps(l)
     93        with self.assertRaises(RuntimeError):
     94            self.dumps(d)
     95
     96    def test_endless_recursion(self):
     97        # See #12051
     98        class EndlessJSONEncoder(self.json.JSONEncoder):
     99            def default(self, o):
     100                """If check_circular is False, this will keep adding another list."""
     101                return [o]
     102
     103        with self.assertRaises(RuntimeError):
     104            EndlessJSONEncoder(check_circular=False).encode(5j)
     105
     106
     107class TestPyRecursion(TestRecursion, PyTest): pass
     108class TestCRecursion(TestRecursion, CTest): pass
  • python/trunk/Lib/json/tests/test_scanstring.py

    r2 r391  
    11import sys
    2 import decimal
    3 from unittest import TestCase
     2from json.tests import PyTest, CTest
    43
    5 import json
    6 import json.decoder
    74
    8 class TestScanString(TestCase):
    9     def test_py_scanstring(self):
    10         self._test_scanstring(json.decoder.py_scanstring)
    11 
    12     def test_c_scanstring(self):
    13         self._test_scanstring(json.decoder.c_scanstring)
    14 
    15     def _test_scanstring(self, scanstring):
    16         self.assertEquals(
     5class TestScanstring(object):
     6    def test_scanstring(self):
     7        scanstring = self.json.decoder.scanstring
     8        self.assertEqual(
    179            scanstring('"z\\ud834\\udd20x"', 1, None, True),
    1810            (u'z\U0001d120x', 16))
    1911
    2012        if sys.maxunicode == 65535:
    21             self.assertEquals(
     13            self.assertEqual(
    2214                scanstring(u'"z\U0001d120x"', 1, None, True),
    2315                (u'z\U0001d120x', 6))
    2416        else:
    25             self.assertEquals(
     17            self.assertEqual(
    2618                scanstring(u'"z\U0001d120x"', 1, None, True),
    2719                (u'z\U0001d120x', 5))
    2820
    29         self.assertEquals(
     21        self.assertEqual(
    3022            scanstring('"\\u007b"', 1, None, True),
    3123            (u'{', 8))
    3224
    33         self.assertEquals(
     25        self.assertEqual(
    3426            scanstring('"A JSON payload should be an object or array, not a string."', 1, None, True),
    3527            (u'A JSON payload should be an object or array, not a string.', 60))
    3628
    37         self.assertEquals(
     29        self.assertEqual(
    3830            scanstring('["Unclosed array"', 2, None, True),
    3931            (u'Unclosed array', 17))
    4032
    41         self.assertEquals(
     33        self.assertEqual(
    4234            scanstring('["extra comma",]', 2, None, True),
    4335            (u'extra comma', 14))
    4436
    45         self.assertEquals(
     37        self.assertEqual(
    4638            scanstring('["double extra comma",,]', 2, None, True),
    4739            (u'double extra comma', 21))
    4840
    49         self.assertEquals(
     41        self.assertEqual(
    5042            scanstring('["Comma after the close"],', 2, None, True),
    5143            (u'Comma after the close', 24))
    5244
    53         self.assertEquals(
     45        self.assertEqual(
    5446            scanstring('["Extra close"]]', 2, None, True),
    5547            (u'Extra close', 14))
    5648
    57         self.assertEquals(
     49        self.assertEqual(
    5850            scanstring('{"Extra comma": true,}', 2, None, True),
    5951            (u'Extra comma', 14))
    6052
    61         self.assertEquals(
     53        self.assertEqual(
    6254            scanstring('{"Extra value after close": true} "misplaced quoted value"', 2, None, True),
    6355            (u'Extra value after close', 26))
    6456
    65         self.assertEquals(
     57        self.assertEqual(
    6658            scanstring('{"Illegal expression": 1 + 2}', 2, None, True),
    6759            (u'Illegal expression', 21))
    6860
    69         self.assertEquals(
     61        self.assertEqual(
    7062            scanstring('{"Illegal invocation": alert()}', 2, None, True),
    7163            (u'Illegal invocation', 21))
    7264
    73         self.assertEquals(
     65        self.assertEqual(
    7466            scanstring('{"Numbers cannot have leading zeroes": 013}', 2, None, True),
    7567            (u'Numbers cannot have leading zeroes', 37))
    7668
    77         self.assertEquals(
     69        self.assertEqual(
    7870            scanstring('{"Numbers cannot be hex": 0x14}', 2, None, True),
    7971            (u'Numbers cannot be hex', 24))
    8072
    81         self.assertEquals(
     73        self.assertEqual(
    8274            scanstring('[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]', 21, None, True),
    8375            (u'Too deep', 30))
    8476
    85         self.assertEquals(
     77        self.assertEqual(
    8678            scanstring('{"Missing colon" null}', 2, None, True),
    8779            (u'Missing colon', 16))
    8880
    89         self.assertEquals(
     81        self.assertEqual(
    9082            scanstring('{"Double colon":: null}', 2, None, True),
    9183            (u'Double colon', 15))
    9284
    93         self.assertEquals(
     85        self.assertEqual(
    9486            scanstring('{"Comma instead of colon", null}', 2, None, True),
    9587            (u'Comma instead of colon', 25))
    9688
    97         self.assertEquals(
     89        self.assertEqual(
    9890            scanstring('["Colon instead of comma": false]', 2, None, True),
    9991            (u'Colon instead of comma', 25))
    10092
    101         self.assertEquals(
     93        self.assertEqual(
    10294            scanstring('["Bad value", truth]', 2, None, True),
    10395            (u'Bad value', 12))
    10496
    10597    def test_issue3623(self):
    106         self.assertRaises(ValueError, json.decoder.scanstring, b"xxx", 1,
     98        self.assertRaises(ValueError, self.json.decoder.scanstring, b"xxx", 1,
    10799                          "xxx")
    108100        self.assertRaises(UnicodeDecodeError,
    109                           json.encoder.encode_basestring_ascii, b"xx\xff")
     101                          self.json.encoder.encode_basestring_ascii, b"xx\xff")
     102
     103    def test_overflow(self):
     104        with self.assertRaises(OverflowError):
     105            self.json.decoder.scanstring(b"xxx", sys.maxsize+1)
     106
     107
     108class TestPyScanstring(TestScanstring, PyTest): pass
     109class TestCScanstring(TestScanstring, CTest): pass
  • python/trunk/Lib/json/tests/test_separators.py

    r2 r391  
    11import textwrap
    2 from unittest import TestCase
    3 
    4 import json
     2from json.tests import PyTest, CTest
    53
    64
    7 class TestSeparators(TestCase):
     5class TestSeparators(object):
    86    def test_separators(self):
    97        h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth',
     
    3230
    3331
    34         d1 = json.dumps(h)
    35         d2 = json.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : '))
     32        d1 = self.dumps(h)
     33        d2 = self.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : '))
    3634
    37         h1 = json.loads(d1)
    38         h2 = json.loads(d2)
     35        h1 = self.loads(d1)
     36        h2 = self.loads(d2)
    3937
    40         self.assertEquals(h1, h)
    41         self.assertEquals(h2, h)
    42         self.assertEquals(d2, expect)
     38        self.assertEqual(h1, h)
     39        self.assertEqual(h2, h)
     40        self.assertEqual(d2, expect)
     41
     42
     43class TestPySeparators(TestSeparators, PyTest): pass
     44class TestCSeparators(TestSeparators, CTest): pass
  • python/trunk/Lib/json/tests/test_speedups.py

    r2 r391  
    1 import decimal
    2 from unittest import TestCase
     1from json.tests import CTest
    32
    4 from json import decoder
    5 from json import encoder
    63
    7 class TestSpeedups(TestCase):
     4class TestSpeedups(CTest):
    85    def test_scanstring(self):
    9         self.assertEquals(decoder.scanstring.__module__, "_json")
    10         self.assert_(decoder.scanstring is decoder.c_scanstring)
     6        self.assertEqual(self.json.decoder.scanstring.__module__, "_json")
     7        self.assertIs(self.json.decoder.scanstring, self.json.decoder.c_scanstring)
    118
    129    def test_encode_basestring_ascii(self):
    13         self.assertEquals(encoder.encode_basestring_ascii.__module__, "_json")
    14         self.assert_(encoder.encode_basestring_ascii is
    15                           encoder.c_encode_basestring_ascii)
     10        self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__,
     11                         "_json")
     12        self.assertIs(self.json.encoder.encode_basestring_ascii,
     13                      self.json.encoder.c_encode_basestring_ascii)
     14
     15class TestDecode(CTest):
     16    def test_make_scanner(self):
     17        self.assertRaises(AttributeError, self.json.scanner.c_make_scanner, 1)
     18
     19    def test_make_encoder(self):
     20        self.assertRaises(TypeError, self.json.encoder.c_make_encoder,
     21            None,
     22            "\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75",
     23            None)
  • python/trunk/Lib/json/tests/test_unicode.py

    r2 r391  
    1 from unittest import TestCase
     1from collections import OrderedDict
     2from json.tests import PyTest, CTest
    23
    3 import json
    44
    5 class TestUnicode(TestCase):
     5class TestUnicode(object):
    66    def test_encoding1(self):
    7         encoder = json.JSONEncoder(encoding='utf-8')
     7        encoder = self.json.JSONEncoder(encoding='utf-8')
    88        u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
    99        s = u.encode('utf-8')
    1010        ju = encoder.encode(u)
    1111        js = encoder.encode(s)
    12         self.assertEquals(ju, js)
     12        self.assertEqual(ju, js)
    1313
    1414    def test_encoding2(self):
    1515        u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
    1616        s = u.encode('utf-8')
    17         ju = json.dumps(u, encoding='utf-8')
    18         js = json.dumps(s, encoding='utf-8')
    19         self.assertEquals(ju, js)
     17        ju = self.dumps(u, encoding='utf-8')
     18        js = self.dumps(s, encoding='utf-8')
     19        self.assertEqual(ju, js)
    2020
    2121    def test_encoding3(self):
    2222        u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
    23         j = json.dumps(u)
    24         self.assertEquals(j, '"\\u03b1\\u03a9"')
     23        j = self.dumps(u)
     24        self.assertEqual(j, '"\\u03b1\\u03a9"')
    2525
    2626    def test_encoding4(self):
    2727        u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
    28         j = json.dumps([u])
    29         self.assertEquals(j, '["\\u03b1\\u03a9"]')
     28        j = self.dumps([u])
     29        self.assertEqual(j, '["\\u03b1\\u03a9"]')
    3030
    3131    def test_encoding5(self):
    3232        u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
    33         j = json.dumps(u, ensure_ascii=False)
    34         self.assertEquals(j, u'"{0}"'.format(u))
     33        j = self.dumps(u, ensure_ascii=False)
     34        self.assertEqual(j, u'"{0}"'.format(u))
    3535
    3636    def test_encoding6(self):
    3737        u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
    38         j = json.dumps([u], ensure_ascii=False)
    39         self.assertEquals(j, u'["{0}"]'.format(u))
     38        j = self.dumps([u], ensure_ascii=False)
     39        self.assertEqual(j, u'["{0}"]'.format(u))
    4040
    4141    def test_big_unicode_encode(self):
    4242        u = u'\U0001d120'
    43         self.assertEquals(json.dumps(u), '"\\ud834\\udd20"')
    44         self.assertEquals(json.dumps(u, ensure_ascii=False), u'"\U0001d120"')
     43        self.assertEqual(self.dumps(u), '"\\ud834\\udd20"')
     44        self.assertEqual(self.dumps(u, ensure_ascii=False), u'"\U0001d120"')
    4545
    4646    def test_big_unicode_decode(self):
    4747        u = u'z\U0001d120x'
    48         self.assertEquals(json.loads('"' + u + '"'), u)
    49         self.assertEquals(json.loads('"z\\ud834\\udd20x"'), u)
     48        self.assertEqual(self.loads('"' + u + '"'), u)
     49        self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u)
    5050
    5151    def test_unicode_decode(self):
    5252        for i in range(0, 0xd7ff):
    5353            u = unichr(i)
    54             js = '"\\u{0:04x}"'.format(i)
    55             self.assertEquals(json.loads(js), u)
     54            s = '"\\u{0:04x}"'.format(i)
     55            self.assertEqual(self.loads(s), u)
     56
     57    def test_object_pairs_hook_with_unicode(self):
     58        s = u'{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}'
     59        p = [(u"xkd", 1), (u"kcw", 2), (u"art", 3), (u"hxm", 4),
     60             (u"qrt", 5), (u"pad", 6), (u"hoy", 7)]
     61        self.assertEqual(self.loads(s), eval(s))
     62        self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p)
     63        od = self.loads(s, object_pairs_hook = OrderedDict)
     64        self.assertEqual(od, OrderedDict(p))
     65        self.assertEqual(type(od), OrderedDict)
     66        # the object_pairs_hook takes priority over the object_hook
     67        self.assertEqual(self.loads(s,
     68                                    object_pairs_hook = OrderedDict,
     69                                    object_hook = lambda x: None),
     70                         OrderedDict(p))
     71
     72    def test_default_encoding(self):
     73        self.assertEqual(self.loads(u'{"a": "\xe9"}'.encode('utf-8')),
     74            {'a': u'\xe9'})
     75
     76    def test_unicode_preservation(self):
     77        self.assertEqual(type(self.loads(u'""')), unicode)
     78        self.assertEqual(type(self.loads(u'"a"')), unicode)
     79        self.assertEqual(type(self.loads(u'["a"]')[0]), unicode)
     80        # Issue 10038.
     81        self.assertEqual(type(self.loads('"foo"')), unicode)
     82
     83    def test_bad_encoding(self):
     84        self.assertRaises(UnicodeEncodeError, self.loads, '"a"', u"rat\xe9")
     85        self.assertRaises(TypeError, self.loads, '"a"', 1)
     86
     87
     88class TestPyUnicode(TestUnicode, PyTest): pass
     89class TestCUnicode(TestUnicode, CTest): pass
  • python/trunk/Lib/json/tool.py

    r2 r391  
    33Usage::
    44
    5     $ echo '{"json":"obj"}' | python -mjson.tool
     5    $ echo '{"json":"obj"}' | python -m json.tool
    66    {
    77        "json": "obj"
    88    }
    9     $ echo '{ 1.2:3.4}' | python -mjson.tool
    10     Expecting property name: line 1 column 2 (char 2)
     9    $ echo '{ 1.2:3.4}' | python -m json.tool
     10    Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
    1111
    1212"""
     
    2525        outfile = open(sys.argv[2], 'wb')
    2626    else:
    27         raise SystemExit("{0} [infile [outfile]]".format(sys.argv[0]))
    28     try:
    29         obj = json.load(infile)
    30     except ValueError, e:
    31         raise SystemExit(e)
    32     json.dump(obj, outfile, sort_keys=True, indent=4)
    33     outfile.write('\n')
     27        raise SystemExit(sys.argv[0] + " [infile [outfile]]")
     28    with infile:
     29        try:
     30            obj = json.load(infile)
     31        except ValueError, e:
     32            raise SystemExit(e)
     33    with outfile:
     34        json.dump(obj, outfile, sort_keys=True,
     35                  indent=4, separators=(',', ': '))
     36        outfile.write('\n')
    3437
    3538
Note: See TracChangeset for help on using the changeset viewer.