Upgrade simplejson to 3.6.0

This commit is contained in:
Matthew Jones
2014-08-06 15:37:54 -04:00
parent 15c2627968
commit 53a8e5c4c6
10 changed files with 228 additions and 123 deletions

View File

@@ -54,6 +54,6 @@ rax-default-network-flags-python-novaclient-ext==0.2.3 (rax_default_network_flag
rax-scheduled-images-python-novaclient-ext==0.2.1 (rax_scheduled_images_python_novaclient_ext/*) rax-scheduled-images-python-novaclient-ext==0.2.1 (rax_scheduled_images_python_novaclient_ext/*)
requests==2.3.0 (requests/*) requests==2.3.0 (requests/*)
setuptools==2.2 (setuptools/*, _markerlib/*, pkg_resources.py, easy_install.py, excluded bin/easy_install*) setuptools==2.2 (setuptools/*, _markerlib/*, pkg_resources.py, easy_install.py, excluded bin/easy_install*)
simplejson==3.3.3 (simplejson/*, excluded simplejson/_speedups.so) simplejson==3.6.0 (simplejson/*, excluded simplejson/_speedups.so)
six==1.6.1 (six.py) six==1.6.1 (six.py)
South==0.8.4 (south/*) South==0.8.4 (south/*)

View File

@@ -98,7 +98,7 @@ Using simplejson.tool from the shell to validate and pretty-print::
Expecting property name: line 1 column 3 (char 2) Expecting property name: line 1 column 3 (char 2)
""" """
from __future__ import absolute_import from __future__ import absolute_import
__version__ = '3.3.3' __version__ = '3.6.0'
__all__ = [ __all__ = [
'dump', 'dumps', 'load', 'loads', 'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
@@ -144,14 +144,15 @@ _default_encoder = JSONEncoder(
item_sort_key=None, item_sort_key=None,
for_json=False, for_json=False,
ignore_nan=False, ignore_nan=False,
int_as_string_bitcount=None,
) )
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None, allow_nan=True, cls=None, indent=None, separators=None,
encoding='utf-8', default=None, use_decimal=True, encoding='utf-8', default=None, use_decimal=True,
namedtuple_as_object=True, tuple_as_array=True, namedtuple_as_object=True, tuple_as_array=True,
bigint_as_string=False, sort_keys=False, item_sort_key=None, bigint_as_string=False, sort_keys=False, item_sort_key=None,
for_json=False, ignore_nan=False, **kw): for_json=False, ignore_nan=False, int_as_string_bitcount=None, **kw):
"""Serialize ``obj`` as a JSON formatted stream to ``fp`` (a """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
``.write()``-supporting file-like object). ``.write()``-supporting file-like object).
@@ -209,6 +210,10 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
lossy operation that will not round-trip correctly and should be used lossy operation that will not round-trip correctly and should be used
sparingly. sparingly.
If *int_as_string_bitcount* is a positive number (n), then int of size
greater than or equal to 2**n or lower than or equal to -2**n will be
encoded as strings.
If specified, *item_sort_key* is a callable used to sort the items in If specified, *item_sort_key* is a callable used to sort the items in
each dictionary. This is useful if you want to sort items other than each dictionary. This is useful if you want to sort items other than
in alphabetical order by key. This option takes precedence over in alphabetical order by key. This option takes precedence over
@@ -238,8 +243,8 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
cls is None and indent is None and separators is None and cls is None and indent is None and separators is None and
encoding == 'utf-8' and default is None and use_decimal encoding == 'utf-8' and default is None and use_decimal
and namedtuple_as_object and tuple_as_array and namedtuple_as_object and tuple_as_array
and not bigint_as_string and not item_sort_key and not bigint_as_string and int_as_string_bitcount is None
and not for_json and not ignore_nan and not kw): and not item_sort_key and not for_json and not ignore_nan and not kw):
iterable = _default_encoder.iterencode(obj) iterable = _default_encoder.iterencode(obj)
else: else:
if cls is None: if cls is None:
@@ -255,6 +260,7 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
item_sort_key=item_sort_key, item_sort_key=item_sort_key,
for_json=for_json, for_json=for_json,
ignore_nan=ignore_nan, ignore_nan=ignore_nan,
int_as_string_bitcount=int_as_string_bitcount,
**kw).iterencode(obj) **kw).iterencode(obj)
# could accelerate with writelines in some versions of Python, at # could accelerate with writelines in some versions of Python, at
# a debuggability cost # a debuggability cost
@@ -263,11 +269,11 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None, allow_nan=True, cls=None, indent=None, separators=None,
encoding='utf-8', default=None, use_decimal=True, encoding='utf-8', default=None, use_decimal=True,
namedtuple_as_object=True, tuple_as_array=True, namedtuple_as_object=True, tuple_as_array=True,
bigint_as_string=False, sort_keys=False, item_sort_key=None, bigint_as_string=False, sort_keys=False, item_sort_key=None,
for_json=False, ignore_nan=False, **kw): for_json=False, ignore_nan=False, int_as_string_bitcount=None, **kw):
"""Serialize ``obj`` to a JSON formatted ``str``. """Serialize ``obj`` to a JSON formatted ``str``.
If ``skipkeys`` is false then ``dict`` keys that are not basic types If ``skipkeys`` is false then ``dict`` keys that are not basic types
@@ -319,6 +325,10 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
or lower than -2**53 will be encoded as strings. This is to avoid the or lower than -2**53 will be encoded as strings. This is to avoid the
rounding that happens in Javascript otherwise. rounding that happens in Javascript otherwise.
If *int_as_string_bitcount* is a positive number (n), then int of size
greater than or equal to 2**n or lower than or equal to -2**n will be
encoded as strings.
If specified, *item_sort_key* is a callable used to sort the items in If specified, *item_sort_key* is a callable used to sort the items in
each dictionary. This is useful if you want to sort items other than each dictionary. This is useful if you want to sort items other than
in alphabetical order by key. This option takes precendence over in alphabetical order by key. This option takes precendence over
@@ -343,14 +353,16 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
""" """
# cached encoder # cached encoder
if (not skipkeys and ensure_ascii and if (
not skipkeys and ensure_ascii and
check_circular and allow_nan and check_circular and allow_nan and
cls is None and indent is None and separators is None and cls is None and indent is None and separators is None and
encoding == 'utf-8' and default is None and use_decimal encoding == 'utf-8' and default is None and use_decimal
and namedtuple_as_object and tuple_as_array and namedtuple_as_object and tuple_as_array
and not bigint_as_string and not sort_keys and not bigint_as_string and int_as_string_bitcount is None
and not item_sort_key and not for_json and not sort_keys and not item_sort_key and not for_json
and not ignore_nan and not kw): and not ignore_nan and not kw
):
return _default_encoder.encode(obj) return _default_encoder.encode(obj)
if cls is None: if cls is None:
cls = JSONEncoder cls = JSONEncoder
@@ -366,6 +378,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
item_sort_key=item_sort_key, item_sort_key=item_sort_key,
for_json=for_json, for_json=for_json,
ignore_nan=ignore_nan, ignore_nan=ignore_nan,
int_as_string_bitcount=int_as_string_bitcount,
**kw).encode(obj) **kw).encode(obj)

View File

@@ -384,6 +384,17 @@ class JSONDecoder(object):
have extraneous data at the end. have extraneous data at the end.
""" """
if idx < 0:
# Ensure that raw_decode bails on negative indexes, the regex
# would otherwise mask this behavior. #98
raise JSONDecodeError('Expecting value', s, idx)
if _PY3 and not isinstance(s, text_type): if _PY3 and not isinstance(s, text_type):
raise TypeError("Input string must be text, not bytes") raise TypeError("Input string must be text, not bytes")
# strip UTF-8 bom
if len(s) > idx:
ord0 = ord(s[idx])
if ord0 == 0xfeff:
idx += 1
elif ord0 == 0xef and s[idx:idx + 3] == '\xef\xbb\xbf':
idx += 3
return self.scan_once(s, idx=_w(s, idx).end()) return self.scan_once(s, idx=_w(s, idx).end())

View File

@@ -116,12 +116,14 @@ class JSONEncoder(object):
""" """
item_separator = ', ' item_separator = ', '
key_separator = ': ' key_separator = ': '
def __init__(self, skipkeys=False, ensure_ascii=True, def __init__(self, skipkeys=False, ensure_ascii=True,
check_circular=True, allow_nan=True, sort_keys=False, check_circular=True, allow_nan=True, sort_keys=False,
indent=None, separators=None, encoding='utf-8', default=None, indent=None, separators=None, encoding='utf-8', default=None,
use_decimal=True, namedtuple_as_object=True, use_decimal=True, namedtuple_as_object=True,
tuple_as_array=True, bigint_as_string=False, tuple_as_array=True, bigint_as_string=False,
item_sort_key=None, for_json=False, ignore_nan=False): item_sort_key=None, for_json=False, ignore_nan=False,
int_as_string_bitcount=None):
"""Constructor for JSONEncoder, with sensible defaults. """Constructor for JSONEncoder, with sensible defaults.
If skipkeys is false, then it is a TypeError to attempt If skipkeys is false, then it is a TypeError to attempt
@@ -180,6 +182,10 @@ class JSONEncoder(object):
or lower than -2**53 will be encoded as strings. This is to avoid the or lower than -2**53 will be encoded as strings. This is to avoid the
rounding that happens in Javascript otherwise. rounding that happens in Javascript otherwise.
If int_as_string_bitcount is a positive number (n), then int of size
greater than or equal to 2**n or lower than or equal to -2**n will be
encoded as strings.
If specified, item_sort_key is a callable used to sort the items in If specified, item_sort_key is a callable used to sort the items in
each dictionary. This is useful if you want to sort items other than each dictionary. This is useful if you want to sort items other than
in alphabetical order by key. in alphabetical order by key.
@@ -207,6 +213,7 @@ class JSONEncoder(object):
self.item_sort_key = item_sort_key self.item_sort_key = item_sort_key
self.for_json = for_json self.for_json = for_json
self.ignore_nan = ignore_nan self.ignore_nan = ignore_nan
self.int_as_string_bitcount = int_as_string_bitcount
if indent is not None and not isinstance(indent, string_types): if indent is not None and not isinstance(indent, string_types):
indent = indent * ' ' indent = indent * ' '
self.indent = indent self.indent = indent
@@ -315,8 +322,9 @@ class JSONEncoder(object):
return text return text
key_memo = {} key_memo = {}
int_as_string_bitcount = (
53 if self.bigint_as_string else self.int_as_string_bitcount)
if (_one_shot and c_make_encoder is not None if (_one_shot and c_make_encoder is not None
and self.indent is None): and self.indent is None):
_iterencode = c_make_encoder( _iterencode = c_make_encoder(
@@ -324,17 +332,17 @@ class JSONEncoder(object):
self.key_separator, self.item_separator, self.sort_keys, self.key_separator, self.item_separator, self.sort_keys,
self.skipkeys, self.allow_nan, key_memo, self.use_decimal, self.skipkeys, self.allow_nan, key_memo, self.use_decimal,
self.namedtuple_as_object, self.tuple_as_array, self.namedtuple_as_object, self.tuple_as_array,
self.bigint_as_string, self.item_sort_key, int_as_string_bitcount,
self.encoding, self.for_json, self.ignore_nan, self.item_sort_key, self.encoding, self.for_json,
Decimal) self.ignore_nan, Decimal)
else: else:
_iterencode = _make_iterencode( _iterencode = _make_iterencode(
markers, self.default, _encoder, self.indent, floatstr, markers, self.default, _encoder, self.indent, floatstr,
self.key_separator, self.item_separator, self.sort_keys, self.key_separator, self.item_separator, self.sort_keys,
self.skipkeys, _one_shot, self.use_decimal, self.skipkeys, _one_shot, self.use_decimal,
self.namedtuple_as_object, self.tuple_as_array, self.namedtuple_as_object, self.tuple_as_array,
self.bigint_as_string, self.item_sort_key, int_as_string_bitcount,
self.encoding, self.for_json, self.item_sort_key, self.encoding, self.for_json,
Decimal=Decimal) Decimal=Decimal)
try: try:
return _iterencode(o, 0) return _iterencode(o, 0)
@@ -372,7 +380,8 @@ class JSONEncoderForHTML(JSONEncoder):
def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
_key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
_use_decimal, _namedtuple_as_object, _tuple_as_array, _use_decimal, _namedtuple_as_object, _tuple_as_array,
_bigint_as_string, _item_sort_key, _encoding, _for_json, _int_as_string_bitcount, _item_sort_key,
_encoding,_for_json,
## HACK: hand-optimized bytecode; turn globals into locals ## HACK: hand-optimized bytecode; turn globals into locals
_PY3=PY3, _PY3=PY3,
ValueError=ValueError, ValueError=ValueError,
@@ -392,6 +401,26 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
elif _sort_keys and not _item_sort_key: elif _sort_keys and not _item_sort_key:
_item_sort_key = itemgetter(0) _item_sort_key = itemgetter(0)
if (_int_as_string_bitcount is not None and
(_int_as_string_bitcount <= 0 or
not isinstance(_int_as_string_bitcount, integer_types))):
raise TypeError("int_as_string_bitcount must be a positive integer")
def _encode_int(value):
skip_quoting = (
_int_as_string_bitcount is None
or
_int_as_string_bitcount < 1
)
if (
skip_quoting or
(-1 << _int_as_string_bitcount)
< value <
(1 << _int_as_string_bitcount)
):
return str(value)
return '"' + str(value) + '"'
def _iterencode_list(lst, _current_indent_level): def _iterencode_list(lst, _current_indent_level):
if not lst: if not lst:
yield '[]' yield '[]'
@@ -426,10 +455,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
elif value is False: elif value is False:
yield buf + 'false' yield buf + 'false'
elif isinstance(value, integer_types): elif isinstance(value, integer_types):
yield ((buf + str(value)) yield buf + _encode_int(value)
if (not _bigint_as_string or
(-1 << 53) < value < (1 << 53))
else (buf + '"' + str(value) + '"'))
elif isinstance(value, float): elif isinstance(value, float):
yield buf + _floatstr(value) yield buf + _floatstr(value)
elif _use_decimal and isinstance(value, Decimal): elif _use_decimal and isinstance(value, Decimal):
@@ -540,10 +566,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
elif value is False: elif value is False:
yield 'false' yield 'false'
elif isinstance(value, integer_types): elif isinstance(value, integer_types):
yield (str(value) yield _encode_int(value)
if (not _bigint_as_string or
(-1 << 53) < value < (1 << 53))
else ('"' + str(value) + '"'))
elif isinstance(value, float): elif isinstance(value, float):
yield _floatstr(value) yield _floatstr(value)
elif _use_decimal and isinstance(value, Decimal): elif _use_decimal and isinstance(value, Decimal):
@@ -585,10 +608,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
elif o is False: elif o is False:
yield 'false' yield 'false'
elif isinstance(o, integer_types): elif isinstance(o, integer_types):
yield (str(o) yield _encode_int(o)
if (not _bigint_as_string or
(-1 << 53) < o < (1 << 53))
else ('"' + str(o) + '"'))
elif isinstance(o, float): elif isinstance(o, float):
yield _floatstr(o) yield _floatstr(o)
else: else:

View File

@@ -118,6 +118,11 @@ def py_make_scanner(context):
raise JSONDecodeError(errmsg, string, idx) raise JSONDecodeError(errmsg, string, idx)
def scan_once(string, idx): def scan_once(string, idx):
if idx < 0:
# Ensure the same behavior as the C speedup, otherwise
# this would work for *some* negative string indices due
# to the behavior of __getitem__ for strings. #98
raise JSONDecodeError('Expecting value', string, idx)
try: try:
return _scan_once(string, idx) return _scan_once(string, idx)
finally: finally:

View File

@@ -3,19 +3,16 @@ import unittest
import doctest import doctest
import sys import sys
class OptionalExtensionTestSuite(unittest.TestSuite):
class NoExtensionTestSuite(unittest.TestSuite):
def run(self, result): def run(self, result):
import simplejson import simplejson
run = unittest.TestSuite.run simplejson._toggle_speedups(False)
run(self, result) result = unittest.TestSuite.run(self, result)
if simplejson._import_c_make_encoder() is None: simplejson._toggle_speedups(True)
TestMissingSpeedups().run(result)
else:
simplejson._toggle_speedups(False)
run(self, result)
simplejson._toggle_speedups(True)
return result return result
class TestMissingSpeedups(unittest.TestCase): class TestMissingSpeedups(unittest.TestCase):
def runTest(self): def runTest(self):
if hasattr(sys, 'pypy_translation_info'): if hasattr(sys, 'pypy_translation_info'):
@@ -23,6 +20,7 @@ class TestMissingSpeedups(unittest.TestCase):
elif hasattr(self, 'skipTest'): elif hasattr(self, 'skipTest'):
self.skipTest('_speedups.so is missing!') self.skipTest('_speedups.so is missing!')
def additional_tests(suite=None): def additional_tests(suite=None):
import simplejson import simplejson
import simplejson.encoder import simplejson.encoder
@@ -36,34 +34,45 @@ def additional_tests(suite=None):
def all_tests_suite(): def all_tests_suite():
suite = unittest.TestLoader().loadTestsFromNames([ def get_suite():
'simplejson.tests.test_bigint_as_string', return additional_tests(
'simplejson.tests.test_check_circular', unittest.TestLoader().loadTestsFromNames([
'simplejson.tests.test_decode', 'simplejson.tests.test_bitsize_int_as_string',
'simplejson.tests.test_default', 'simplejson.tests.test_bigint_as_string',
'simplejson.tests.test_dump', 'simplejson.tests.test_check_circular',
'simplejson.tests.test_encode_basestring_ascii', 'simplejson.tests.test_decode',
'simplejson.tests.test_encode_for_html', 'simplejson.tests.test_default',
'simplejson.tests.test_errors', 'simplejson.tests.test_dump',
'simplejson.tests.test_fail', 'simplejson.tests.test_encode_basestring_ascii',
'simplejson.tests.test_float', 'simplejson.tests.test_encode_for_html',
'simplejson.tests.test_indent', 'simplejson.tests.test_errors',
'simplejson.tests.test_pass1', 'simplejson.tests.test_fail',
'simplejson.tests.test_pass2', 'simplejson.tests.test_float',
'simplejson.tests.test_pass3', 'simplejson.tests.test_indent',
'simplejson.tests.test_recursion', 'simplejson.tests.test_pass1',
'simplejson.tests.test_scanstring', 'simplejson.tests.test_pass2',
'simplejson.tests.test_separators', 'simplejson.tests.test_pass3',
'simplejson.tests.test_speedups', 'simplejson.tests.test_recursion',
'simplejson.tests.test_unicode', 'simplejson.tests.test_scanstring',
'simplejson.tests.test_decimal', 'simplejson.tests.test_separators',
'simplejson.tests.test_tuple', 'simplejson.tests.test_speedups',
'simplejson.tests.test_namedtuple', 'simplejson.tests.test_unicode',
'simplejson.tests.test_tool', 'simplejson.tests.test_decimal',
'simplejson.tests.test_for_json', 'simplejson.tests.test_tuple',
]) 'simplejson.tests.test_namedtuple',
suite = additional_tests(suite) 'simplejson.tests.test_tool',
return OptionalExtensionTestSuite([suite]) 'simplejson.tests.test_for_json',
]))
suite = get_suite()
import simplejson
if simplejson._import_c_make_encoder() is None:
suite.addTest(TestMissingSpeedups())
else:
suite = unittest.TestSuite([
suite,
NoExtensionTestSuite([get_suite()]),
])
return suite
def main(): def main():

View File

@@ -1,7 +1,7 @@
from unittest import TestCase from unittest import TestCase
import simplejson as json import simplejson as json
from simplejson.compat import long_type
class TestBigintAsString(TestCase): class TestBigintAsString(TestCase):
# Python 2.5, at least the one that ships on Mac OS X, calculates # Python 2.5, at least the one that ships on Mac OS X, calculates
@@ -15,44 +15,53 @@ class TestBigintAsString(TestCase):
((-1 << 53) - 1, '-9007199254740993'), ((-1 << 53) - 1, '-9007199254740993'),
((-1 << 53) + 1, -9007199254740991)] ((-1 << 53) + 1, -9007199254740991)]
options = (
{"bigint_as_string": True},
{"int_as_string_bitcount": 53}
)
def test_ints(self): def test_ints(self):
for val, expect in self.values: for opts in self.options:
self.assertEqual( for val, expect in self.values:
val, self.assertEqual(
json.loads(json.dumps(val))) val,
self.assertEqual( json.loads(json.dumps(val)))
expect, self.assertEqual(
json.loads(json.dumps(val, bigint_as_string=True))) expect,
json.loads(json.dumps(val, **opts)))
def test_lists(self): def test_lists(self):
for val, expect in self.values: for opts in self.options:
val = [val, val] for val, expect in self.values:
expect = [expect, expect] val = [val, val]
self.assertEqual( expect = [expect, expect]
val, self.assertEqual(
json.loads(json.dumps(val))) val,
self.assertEqual( json.loads(json.dumps(val)))
expect, self.assertEqual(
json.loads(json.dumps(val, bigint_as_string=True))) expect,
json.loads(json.dumps(val, **opts)))
def test_dicts(self): def test_dicts(self):
for val, expect in self.values: for opts in self.options:
val = {'k': val} for val, expect in self.values:
expect = {'k': expect} val = {'k': val}
self.assertEqual( expect = {'k': expect}
val, self.assertEqual(
json.loads(json.dumps(val))) val,
self.assertEqual( json.loads(json.dumps(val)))
expect, self.assertEqual(
json.loads(json.dumps(val, bigint_as_string=True))) expect,
json.loads(json.dumps(val, **opts)))
def test_dict_keys(self): def test_dict_keys(self):
for val, _ in self.values: for opts in self.options:
expect = {str(val): 'value'} for val, _ in self.values:
val = {val: 'value'} expect = {str(val): 'value'}
self.assertEqual( val = {val: 'value'}
expect, self.assertEqual(
json.loads(json.dumps(val))) expect,
self.assertEqual( json.loads(json.dumps(val)))
expect, self.assertEqual(
json.loads(json.dumps(val, bigint_as_string=True))) expect,
json.loads(json.dumps(val, **opts)))

View File

@@ -86,3 +86,14 @@ class TestDecode(TestCase):
self.assertEqual( self.assertEqual(
({'a': {}}, 11), ({'a': {}}, 11),
cls().raw_decode(" \n{\"a\": {}}")) cls().raw_decode(" \n{\"a\": {}}"))
def test_bounds_checking(self):
# https://github.com/simplejson/simplejson/issues/98
j = json.decoder.JSONDecoder()
for i in [4, 5, 6, -1, -2, -3, -4, -5, -6]:
self.assertRaises(ValueError, j.scan_once, '1234', i)
self.assertRaises(ValueError, j.raw_decode, '1234', i)
x, y = sorted(['128931233', '472389423'], key=id)
diff = id(x) - id(y)
self.assertRaises(ValueError, j.scan_once, y, diff)
self.assertRaises(ValueError, j.raw_decode, y, i)

View File

@@ -1,20 +1,39 @@
import sys
import unittest
from unittest import TestCase from unittest import TestCase
from simplejson import encoder, scanner from simplejson import encoder, scanner
def has_speedups(): def has_speedups():
return encoder.c_make_encoder is not None return encoder.c_make_encoder is not None
class TestDecode(TestCase):
def test_make_scanner(self): def skip_if_speedups_missing(func):
def wrapper(*args, **kwargs):
if not has_speedups(): if not has_speedups():
return if hasattr(unittest, 'SkipTest'):
raise unittest.SkipTest("C Extension not available")
else:
sys.stdout.write("C Extension not available")
return
return func(*args, **kwargs)
return wrapper
class TestDecode(TestCase):
@skip_if_speedups_missing
def test_make_scanner(self):
self.assertRaises(AttributeError, scanner.c_make_scanner, 1) self.assertRaises(AttributeError, scanner.c_make_scanner, 1)
@skip_if_speedups_missing
def test_make_encoder(self): def test_make_encoder(self):
if not has_speedups(): self.assertRaises(
return TypeError,
self.assertRaises(TypeError, encoder.c_make_encoder, encoder.c_make_encoder,
None, None,
"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75", ("\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7"
None) "\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75"),
None
)

View File

@@ -1,8 +1,9 @@
import sys import sys
import codecs
from unittest import TestCase from unittest import TestCase
import simplejson as json import simplejson as json
from simplejson.compat import unichr, text_type, b, u from simplejson.compat import unichr, text_type, b, u, BytesIO
class TestUnicode(TestCase): class TestUnicode(TestCase):
def test_encoding1(self): def test_encoding1(self):
@@ -143,3 +144,10 @@ class TestUnicode(TestCase):
self.assertEqual( self.assertEqual(
json.dumps(c, ensure_ascii=False), json.dumps(c, ensure_ascii=False),
'"' + c + '"') '"' + c + '"')
def test_strip_bom(self):
content = u"\u3053\u3093\u306b\u3061\u308f"
json_doc = codecs.BOM_UTF8 + b(json.dumps(content))
self.assertEqual(json.load(BytesIO(json_doc)), content)
for doc in json_doc, json_doc.decode('utf8'):
self.assertEqual(json.loads(doc), content)