Kaydet (Commit) 91852ca6 authored tarafından Raymond Hettinger's avatar Raymond Hettinger

Issue 5381: Add object_pairs_hook to the json module.

üst 2124599e
...@@ -166,7 +166,7 @@ Basic Usage ...@@ -166,7 +166,7 @@ Basic Usage
:func:`dump`. :func:`dump`.
.. function:: load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, **kw]]]]]]]) .. function:: load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]])
Deserialize *fp* (a ``.read()``-supporting file-like object containing a JSON Deserialize *fp* (a ``.read()``-supporting file-like object containing a JSON
document) to a Python object. document) to a Python object.
...@@ -182,6 +182,17 @@ Basic Usage ...@@ -182,6 +182,17 @@ Basic Usage
*object_hook* will be used instead of the :class:`dict`. This feature can be used *object_hook* will be used instead of the :class:`dict`. This feature can be used
to implement custom decoders (e.g. JSON-RPC class hinting). to implement custom decoders (e.g. JSON-RPC class hinting).
*object_pairs_hook* is an optional function that will be called with the
result of any object literal decode with an ordered list of pairs. The
return value of *object_pairs_hook* will be used instead of the
:class:`dict`. This feature can be used to implement custom decoders that
rely on the order that the key and value pairs are decoded (for example,
:func:`collections.OrderedDict` will remember the order of insertion). If
*object_hook* is also defined, the *object_pairs_hook* takes priority.
.. versionchanged:: 2.7
Added support for *object_pairs_hook*.
*parse_float*, if specified, will be called with the string of every JSON *parse_float*, if specified, will be called with the string of every JSON
float to be decoded. By default, this is equivalent to ``float(num_str)``. float to be decoded. By default, this is equivalent to ``float(num_str)``.
This can be used to use another datatype or parser for JSON floats This can be used to use another datatype or parser for JSON floats
...@@ -202,7 +213,7 @@ Basic Usage ...@@ -202,7 +213,7 @@ Basic Usage
class. class.
.. function:: loads(s[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, **kw]]]]]]]) .. function:: loads(s[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]])
Deserialize *s* (a :class:`str` or :class:`unicode` instance containing a JSON Deserialize *s* (a :class:`str` or :class:`unicode` instance containing a JSON
document) to a Python object. document) to a Python object.
...@@ -218,7 +229,7 @@ Basic Usage ...@@ -218,7 +229,7 @@ Basic Usage
Encoders and decoders Encoders and decoders
--------------------- ---------------------
.. class:: JSONDecoder([encoding[, object_hook[, parse_float[, parse_int[, parse_constant[, strict]]]]]]) .. class:: JSONDecoder([encoding[, object_hook[, parse_float[, parse_int[, parse_constant[, strict[, object_pairs_hook]]]]]]])
Simple JSON decoder. Simple JSON decoder.
...@@ -259,6 +270,17 @@ Encoders and decoders ...@@ -259,6 +270,17 @@ Encoders and decoders
:class:`dict`. This can be used to provide custom deserializations (e.g. to :class:`dict`. This can be used to provide custom deserializations (e.g. to
support JSON-RPC class hinting). support JSON-RPC class hinting).
*object_pairs_hook*, if specified will be called with the result of every
JSON object decoded with an ordered list of pairs. The return value of
*object_pairs_hook* will be used instead of the :class:`dict`. This
feature can be used to implement custom decoders that rely on the order
that the key and value pairs are decoded (for example,
:func:`collections.OrderedDict` will remember the order of insertion). If
*object_hook* is also defined, the *object_pairs_hook* takes priority.
.. versionchanged:: 2.7
Added support for *object_pairs_hook*.
*parse_float*, if specified, will be called with the string of every JSON *parse_float*, if specified, will be called with the string of every JSON
float to be decoded. By default, this is equivalent to ``float(num_str)``. float to be decoded. By default, this is equivalent to ``float(num_str)``.
This can be used to use another datatype or parser for JSON floats This can be used to use another datatype or parser for JSON floats
......
...@@ -238,11 +238,12 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, ...@@ -238,11 +238,12 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
**kw).encode(obj) **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, 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 """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
a JSON document) to a Python object. a JSON document) to a Python object.
...@@ -265,11 +266,11 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, ...@@ -265,11 +266,11 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
return loads(fp.read(), return loads(fp.read(),
encoding=encoding, cls=cls, object_hook=object_hook, encoding=encoding, cls=cls, object_hook=object_hook,
parse_float=parse_float, parse_int=parse_int, 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, 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 """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
document) to a Python object. document) to a Python object.
...@@ -304,12 +305,14 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, ...@@ -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 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_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) return _default_decoder.decode(s)
if cls is None: if cls is None:
cls = JSONDecoder cls = JSONDecoder
if object_hook is not None: if object_hook is not None:
kw['object_hook'] = object_hook 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: if parse_float is not None:
kw['parse_float'] = parse_float kw['parse_float'] = parse_float
if parse_int is not None: if parse_int is not None:
......
...@@ -147,8 +147,9 @@ WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) ...@@ -147,8 +147,9 @@ WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
WHITESPACE_STR = ' \t\n\r' WHITESPACE_STR = ' \t\n\r'
def JSONObject((s, end), encoding, strict, scan_once, object_hook, def JSONObject((s, end), encoding, strict, scan_once, object_hook,
_w=WHITESPACE.match, _ws=WHITESPACE_STR): object_pairs_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
pairs = {} pairs = []
pairs_append = pairs.append
# Use a slice to prevent IndexError from being raised, the following # Use a slice to prevent IndexError from being raised, the following
# check will raise a more specific ValueError if the string is empty # check will raise a more specific ValueError if the string is empty
nextchar = s[end:end + 1] nextchar = s[end:end + 1]
...@@ -187,7 +188,7 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook, ...@@ -187,7 +188,7 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,
value, end = scan_once(s, end) value, end = scan_once(s, end)
except StopIteration: except StopIteration:
raise ValueError(errmsg("Expecting object", s, end)) raise ValueError(errmsg("Expecting object", s, end))
pairs[key] = value pairs_append((key, value))
try: try:
nextchar = s[end] nextchar = s[end]
...@@ -218,6 +219,10 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook, ...@@ -218,6 +219,10 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,
if nextchar != '"': if nextchar != '"':
raise ValueError(errmsg("Expecting property name", s, end - 1)) 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: if object_hook is not None:
pairs = object_hook(pairs) pairs = object_hook(pairs)
return pairs, end return pairs, end
...@@ -289,7 +294,8 @@ class JSONDecoder(object): ...@@ -289,7 +294,8 @@ class JSONDecoder(object):
""" """
def __init__(self, encoding=None, object_hook=None, parse_float=None, 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`` """``encoding`` determines the encoding used to interpret any ``str``
objects decoded by this instance (utf-8 by default). It has no objects decoded by this instance (utf-8 by default). It has no
effect when decoding ``unicode`` objects. effect when decoding ``unicode`` objects.
...@@ -320,6 +326,7 @@ class JSONDecoder(object): ...@@ -320,6 +326,7 @@ class JSONDecoder(object):
""" """
self.encoding = encoding self.encoding = encoding
self.object_hook = object_hook self.object_hook = object_hook
self.object_pairs_hook = object_pairs_hook
self.parse_float = parse_float or float self.parse_float = parse_float or float
self.parse_int = parse_int or int self.parse_int = parse_int or int
self.parse_constant = parse_constant or _CONSTANTS.__getitem__ self.parse_constant = parse_constant or _CONSTANTS.__getitem__
......
...@@ -2,6 +2,7 @@ import decimal ...@@ -2,6 +2,7 @@ import decimal
from unittest import TestCase from unittest import TestCase
import json import json
from collections import OrderedDict
class TestDecode(TestCase): class TestDecode(TestCase):
def test_decimal(self): def test_decimal(self):
...@@ -20,3 +21,18 @@ class TestDecode(TestCase): ...@@ -20,3 +21,18 @@ class TestDecode(TestCase):
# exercise the uncommon cases. The array cases are already covered. # exercise the uncommon cases. The array cases are already covered.
rval = json.loads('{ "key" : "value" , "k":"v" }') rval = json.loads('{ "key" : "value" , "k":"v" }')
self.assertEquals(rval, {"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))
from unittest import TestCase from unittest import TestCase
import json import json
from collections import OrderedDict
class TestUnicode(TestCase): class TestUnicode(TestCase):
def test_encoding1(self): def test_encoding1(self):
...@@ -54,6 +55,21 @@ class TestUnicode(TestCase): ...@@ -54,6 +55,21 @@ class TestUnicode(TestCase):
s = '"\\u{0:04x}"'.format(i) s = '"\\u{0:04x}"'.format(i)
self.assertEquals(json.loads(s), u) 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): def test_default_encoding(self):
self.assertEquals(json.loads(u'{"a": "\xe9"}'.encode('utf-8')), self.assertEquals(json.loads(u'{"a": "\xe9"}'.encode('utf-8')),
{'a': u'\xe9'}) {'a': u'\xe9'})
......
...@@ -181,6 +181,9 @@ Core and Builtins ...@@ -181,6 +181,9 @@ Core and Builtins
Library Library
------- -------
- Issue #5381: Added object_pairs_hook to the json module. This allows
OrderedDicts to be built by the decoder.
- Issue #2110: Add support for thousands separator and 'n' type - Issue #2110: Add support for thousands separator and 'n' type
specifier to Decimal.__format__ specifier to Decimal.__format__
......
...@@ -35,6 +35,7 @@ typedef struct _PyScannerObject { ...@@ -35,6 +35,7 @@ typedef struct _PyScannerObject {
PyObject *encoding; PyObject *encoding;
PyObject *strict; PyObject *strict;
PyObject *object_hook; PyObject *object_hook;
PyObject *pairs_hook;
PyObject *parse_float; PyObject *parse_float;
PyObject *parse_int; PyObject *parse_int;
PyObject *parse_constant; PyObject *parse_constant;
...@@ -44,6 +45,7 @@ static PyMemberDef scanner_members[] = { ...@@ -44,6 +45,7 @@ static PyMemberDef scanner_members[] = {
{"encoding", T_OBJECT, offsetof(PyScannerObject, encoding), READONLY, "encoding"}, {"encoding", T_OBJECT, offsetof(PyScannerObject, encoding), READONLY, "encoding"},
{"strict", T_OBJECT, offsetof(PyScannerObject, strict), READONLY, "strict"}, {"strict", T_OBJECT, offsetof(PyScannerObject, strict), READONLY, "strict"},
{"object_hook", T_OBJECT, offsetof(PyScannerObject, object_hook), READONLY, "object_hook"}, {"object_hook", T_OBJECT, offsetof(PyScannerObject, object_hook), READONLY, "object_hook"},
{"object_pairs_hook", T_OBJECT, offsetof(PyScannerObject, pairs_hook), READONLY, "object_pairs_hook"},
{"parse_float", T_OBJECT, offsetof(PyScannerObject, parse_float), READONLY, "parse_float"}, {"parse_float", T_OBJECT, offsetof(PyScannerObject, parse_float), READONLY, "parse_float"},
{"parse_int", T_OBJECT, offsetof(PyScannerObject, parse_int), READONLY, "parse_int"}, {"parse_int", T_OBJECT, offsetof(PyScannerObject, parse_int), READONLY, "parse_int"},
{"parse_constant", T_OBJECT, offsetof(PyScannerObject, parse_constant), READONLY, "parse_constant"}, {"parse_constant", T_OBJECT, offsetof(PyScannerObject, parse_constant), READONLY, "parse_constant"},
...@@ -891,6 +893,7 @@ scanner_traverse(PyObject *self, visitproc visit, void *arg) ...@@ -891,6 +893,7 @@ scanner_traverse(PyObject *self, visitproc visit, void *arg)
Py_VISIT(s->encoding); Py_VISIT(s->encoding);
Py_VISIT(s->strict); Py_VISIT(s->strict);
Py_VISIT(s->object_hook); Py_VISIT(s->object_hook);
Py_VISIT(s->pairs_hook);
Py_VISIT(s->parse_float); Py_VISIT(s->parse_float);
Py_VISIT(s->parse_int); Py_VISIT(s->parse_int);
Py_VISIT(s->parse_constant); Py_VISIT(s->parse_constant);
...@@ -906,6 +909,7 @@ scanner_clear(PyObject *self) ...@@ -906,6 +909,7 @@ scanner_clear(PyObject *self)
Py_CLEAR(s->encoding); Py_CLEAR(s->encoding);
Py_CLEAR(s->strict); Py_CLEAR(s->strict);
Py_CLEAR(s->object_hook); Py_CLEAR(s->object_hook);
Py_CLEAR(s->pairs_hook);
Py_CLEAR(s->parse_float); Py_CLEAR(s->parse_float);
Py_CLEAR(s->parse_int); Py_CLEAR(s->parse_int);
Py_CLEAR(s->parse_constant); Py_CLEAR(s->parse_constant);
...@@ -923,13 +927,17 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_ ...@@ -923,13 +927,17 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
*/ */
char *str = PyString_AS_STRING(pystr); char *str = PyString_AS_STRING(pystr);
Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1; Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1;
PyObject *rval = PyDict_New(); PyObject *rval;
PyObject *pairs;
PyObject *item;
PyObject *key = NULL; PyObject *key = NULL;
PyObject *val = NULL; PyObject *val = NULL;
char *encoding = PyString_AS_STRING(s->encoding); char *encoding = PyString_AS_STRING(s->encoding);
int strict = PyObject_IsTrue(s->strict); int strict = PyObject_IsTrue(s->strict);
Py_ssize_t next_idx; Py_ssize_t next_idx;
if (rval == NULL)
pairs = PyList_New(0);
if (pairs == NULL)
return NULL; return NULL;
/* skip whitespace after { */ /* skip whitespace after { */
...@@ -962,11 +970,16 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_ ...@@ -962,11 +970,16 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
if (val == NULL) if (val == NULL)
goto bail; goto bail;
if (PyDict_SetItem(rval, key, val) == -1) item = PyTuple_Pack(2, key, val);
if (item == NULL)
goto bail; goto bail;
Py_CLEAR(key); Py_CLEAR(key);
Py_CLEAR(val); Py_CLEAR(val);
if (PyList_Append(pairs, item) == -1) {
Py_DECREF(item);
goto bail;
}
Py_DECREF(item);
idx = next_idx; idx = next_idx;
/* skip whitespace before } or , */ /* skip whitespace before } or , */
...@@ -992,6 +1005,23 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_ ...@@ -992,6 +1005,23 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
raise_errmsg("Expecting object", pystr, end_idx); raise_errmsg("Expecting object", pystr, end_idx);
goto bail; goto bail;
} }
/* if pairs_hook is not None: rval = object_pairs_hook(pairs) */
if (s->pairs_hook != Py_None) {
val = PyObject_CallFunctionObjArgs(s->pairs_hook, pairs, NULL);
if (val == NULL)
goto bail;
Py_DECREF(pairs);
*next_idx_ptr = idx + 1;
return val;
}
rval = PyObject_CallFunctionObjArgs((PyObject *)(&PyDict_Type),
pairs, NULL);
if (rval == NULL)
goto bail;
Py_CLEAR(pairs);
/* if object_hook is not None: rval = object_hook(rval) */ /* if object_hook is not None: rval = object_hook(rval) */
if (s->object_hook != Py_None) { if (s->object_hook != Py_None) {
val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL); val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL);
...@@ -1006,7 +1036,7 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_ ...@@ -1006,7 +1036,7 @@ _parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
bail: bail:
Py_XDECREF(key); Py_XDECREF(key);
Py_XDECREF(val); Py_XDECREF(val);
Py_DECREF(rval); Py_XDECREF(pairs);
return NULL; return NULL;
} }
...@@ -1021,12 +1051,16 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss ...@@ -1021,12 +1051,16 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
*/ */
Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr); Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr);
Py_ssize_t end_idx = PyUnicode_GET_SIZE(pystr) - 1; Py_ssize_t end_idx = PyUnicode_GET_SIZE(pystr) - 1;
PyObject *val = NULL; PyObject *rval;
PyObject *rval = PyDict_New(); PyObject *pairs;
PyObject *item;
PyObject *key = NULL; PyObject *key = NULL;
PyObject *val = NULL;
int strict = PyObject_IsTrue(s->strict); int strict = PyObject_IsTrue(s->strict);
Py_ssize_t next_idx; Py_ssize_t next_idx;
if (rval == NULL)
pairs = PyList_New(0);
if (pairs == NULL)
return NULL; return NULL;
/* skip whitespace after { */ /* skip whitespace after { */
...@@ -1059,11 +1093,16 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss ...@@ -1059,11 +1093,16 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
if (val == NULL) if (val == NULL)
goto bail; goto bail;
if (PyDict_SetItem(rval, key, val) == -1) item = PyTuple_Pack(2, key, val);
if (item == NULL)
goto bail; goto bail;
Py_CLEAR(key); Py_CLEAR(key);
Py_CLEAR(val); Py_CLEAR(val);
if (PyList_Append(pairs, item) == -1) {
Py_DECREF(item);
goto bail;
}
Py_DECREF(item);
idx = next_idx; idx = next_idx;
/* skip whitespace before } or , */ /* skip whitespace before } or , */
...@@ -1091,6 +1130,22 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss ...@@ -1091,6 +1130,22 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
goto bail; goto bail;
} }
/* if pairs_hook is not None: rval = object_pairs_hook(pairs) */
if (s->pairs_hook != Py_None) {
val = PyObject_CallFunctionObjArgs(s->pairs_hook, pairs, NULL);
if (val == NULL)
goto bail;
Py_DECREF(pairs);
*next_idx_ptr = idx + 1;
return val;
}
rval = PyObject_CallFunctionObjArgs((PyObject *)(&PyDict_Type),
pairs, NULL);
if (rval == NULL)
goto bail;
Py_CLEAR(pairs);
/* if object_hook is not None: rval = object_hook(rval) */ /* if object_hook is not None: rval = object_hook(rval) */
if (s->object_hook != Py_None) { if (s->object_hook != Py_None) {
val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL); val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL);
...@@ -1105,7 +1160,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss ...@@ -1105,7 +1160,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
bail: bail:
Py_XDECREF(key); Py_XDECREF(key);
Py_XDECREF(val); Py_XDECREF(val);
Py_DECREF(rval); Py_XDECREF(pairs);
return NULL; return NULL;
} }
...@@ -1648,6 +1703,7 @@ scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -1648,6 +1703,7 @@ scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
s->encoding = NULL; s->encoding = NULL;
s->strict = NULL; s->strict = NULL;
s->object_hook = NULL; s->object_hook = NULL;
s->pairs_hook = NULL;
s->parse_float = NULL; s->parse_float = NULL;
s->parse_int = NULL; s->parse_int = NULL;
s->parse_constant = NULL; s->parse_constant = NULL;
...@@ -1688,6 +1744,9 @@ scanner_init(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -1688,6 +1744,9 @@ scanner_init(PyObject *self, PyObject *args, PyObject *kwds)
if (s->strict == NULL) if (s->strict == NULL)
goto bail; goto bail;
s->object_hook = PyObject_GetAttrString(ctx, "object_hook"); s->object_hook = PyObject_GetAttrString(ctx, "object_hook");
if (s->object_hook == NULL)
goto bail;
s->pairs_hook = PyObject_GetAttrString(ctx, "object_pairs_hook");
if (s->object_hook == NULL) if (s->object_hook == NULL)
goto bail; goto bail;
s->parse_float = PyObject_GetAttrString(ctx, "parse_float"); s->parse_float = PyObject_GetAttrString(ctx, "parse_float");
...@@ -1706,6 +1765,7 @@ bail: ...@@ -1706,6 +1765,7 @@ bail:
Py_CLEAR(s->encoding); Py_CLEAR(s->encoding);
Py_CLEAR(s->strict); Py_CLEAR(s->strict);
Py_CLEAR(s->object_hook); Py_CLEAR(s->object_hook);
Py_CLEAR(s->pairs_hook);
Py_CLEAR(s->parse_float); Py_CLEAR(s->parse_float);
Py_CLEAR(s->parse_int); Py_CLEAR(s->parse_int);
Py_CLEAR(s->parse_constant); Py_CLEAR(s->parse_constant);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment