diff options
author | Raymond Hettinger <python@rcn.com> | 2009-03-19 19:19:03 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2009-03-19 19:19:03 (GMT) |
commit | 91852ca673adcfa4e9ceacbb36f2cd45767efa58 (patch) | |
tree | 4b1d71bcc09823e096bc9124cb1424d12e08334c /Lib | |
parent | 2124599eaa739f66db8871d68334706f4aa373a6 (diff) | |
download | cpython-91852ca673adcfa4e9ceacbb36f2cd45767efa58.zip cpython-91852ca673adcfa4e9ceacbb36f2cd45767efa58.tar.gz cpython-91852ca673adcfa4e9ceacbb36f2cd45767efa58.tar.bz2 |
Issue 5381: Add object_pairs_hook to the json module.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/json/__init__.py | 13 | ||||
-rw-r--r-- | Lib/json/decoder.py | 15 | ||||
-rw-r--r-- | Lib/json/tests/test_decode.py | 16 | ||||
-rw-r--r-- | Lib/json/tests/test_unicode.py | 16 |
4 files changed, 51 insertions, 9 deletions
diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 4338a03..01c26d9 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -238,11 +238,12 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, **kw).encode(obj) -_default_decoder = JSONDecoder(encoding=None, object_hook=None) +_default_decoder = JSONDecoder(encoding=None, object_hook=None, + object_pairs_hook=None) def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): + parse_int=None, parse_constant=None, object_pairs_hook=None, **kw): """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing a JSON document) to a Python object. @@ -265,11 +266,11 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, return loads(fp.read(), encoding=encoding, cls=cls, object_hook=object_hook, parse_float=parse_float, parse_int=parse_int, - parse_constant=parse_constant, **kw) + parse_constant=parse_constant, object_pairs_hook=None, **kw) def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): + parse_int=None, parse_constant=None, object_pairs_hook=None, **kw): """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON document) to a Python object. @@ -304,12 +305,14 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, """ if (cls is None and encoding is None and object_hook is None and parse_int is None and parse_float is None and - parse_constant is None and not kw): + parse_constant is None and object_pairs_hook is None and not kw): return _default_decoder.decode(s) if cls is None: cls = JSONDecoder if object_hook is not None: kw['object_hook'] = object_hook + if object_pairs_hook is not None: + kw['object_pairs_hook'] = object_pairs_hook if parse_float is not None: kw['parse_float'] = parse_float if parse_int is not None: diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py index c7f04f9..44635a0 100644 --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -147,8 +147,9 @@ WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) WHITESPACE_STR = ' \t\n\r' def JSONObject((s, end), encoding, strict, scan_once, object_hook, - _w=WHITESPACE.match, _ws=WHITESPACE_STR): - pairs = {} + object_pairs_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR): + pairs = [] + pairs_append = pairs.append # Use a slice to prevent IndexError from being raised, the following # check will raise a more specific ValueError if the string is empty nextchar = s[end:end + 1] @@ -187,7 +188,7 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook, value, end = scan_once(s, end) except StopIteration: raise ValueError(errmsg("Expecting object", s, end)) - pairs[key] = value + pairs_append((key, value)) try: nextchar = s[end] @@ -218,6 +219,10 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook, if nextchar != '"': raise ValueError(errmsg("Expecting property name", s, end - 1)) + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + pairs = dict(pairs) if object_hook is not None: pairs = object_hook(pairs) return pairs, end @@ -289,7 +294,8 @@ class JSONDecoder(object): """ def __init__(self, encoding=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, strict=True): + parse_int=None, parse_constant=None, strict=True, + object_pairs_hook=None): """``encoding`` determines the encoding used to interpret any ``str`` objects decoded by this instance (utf-8 by default). It has no effect when decoding ``unicode`` objects. @@ -320,6 +326,7 @@ class JSONDecoder(object): """ self.encoding = encoding self.object_hook = object_hook + self.object_pairs_hook = object_pairs_hook self.parse_float = parse_float or float self.parse_int = parse_int or int self.parse_constant = parse_constant or _CONSTANTS.__getitem__ diff --git a/Lib/json/tests/test_decode.py b/Lib/json/tests/test_decode.py index 484cc94..0744b52 100644 --- a/Lib/json/tests/test_decode.py +++ b/Lib/json/tests/test_decode.py @@ -2,6 +2,7 @@ import decimal from unittest import TestCase import json +from collections import OrderedDict class TestDecode(TestCase): def test_decimal(self): @@ -20,3 +21,18 @@ class TestDecode(TestCase): # exercise the uncommon cases. The array cases are already covered. rval = json.loads('{ "key" : "value" , "k":"v" }') self.assertEquals(rval, {"key":"value", "k":"v"}) + + def test_object_pairs_hook(self): + s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' + p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), + ("qrt", 5), ("pad", 6), ("hoy", 7)] + self.assertEqual(json.loads(s), eval(s)) + self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) + od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(od, OrderedDict(p)) + self.assertEqual(type(od), OrderedDict) + # the object_pairs_hook takes priority over the object_hook + self.assertEqual(json.loads(s, + object_pairs_hook = OrderedDict, + object_hook = lambda x: None), + OrderedDict(p)) diff --git a/Lib/json/tests/test_unicode.py b/Lib/json/tests/test_unicode.py index 0b47cbb..13759f8 100644 --- a/Lib/json/tests/test_unicode.py +++ b/Lib/json/tests/test_unicode.py @@ -1,6 +1,7 @@ from unittest import TestCase import json +from collections import OrderedDict class TestUnicode(TestCase): def test_encoding1(self): @@ -54,6 +55,21 @@ class TestUnicode(TestCase): s = '"\\u{0:04x}"'.format(i) self.assertEquals(json.loads(s), u) + def test_object_pairs_hook_with_unicode(self): + s = u'{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' + p = [(u"xkd", 1), (u"kcw", 2), (u"art", 3), (u"hxm", 4), + (u"qrt", 5), (u"pad", 6), (u"hoy", 7)] + self.assertEqual(json.loads(s), eval(s)) + self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) + od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(od, OrderedDict(p)) + self.assertEqual(type(od), OrderedDict) + # the object_pairs_hook takes priority over the object_hook + self.assertEqual(json.loads(s, + object_pairs_hook = OrderedDict, + object_hook = lambda x: None), + OrderedDict(p)) + def test_default_encoding(self): self.assertEquals(json.loads(u'{"a": "\xe9"}'.encode('utf-8')), {'a': u'\xe9'}) |