* Fix-up a TODO (support the sort_key option).

* Fix an error where True/False were being written-out
  as title-cased strings when used a dictionary keys.
* Speed-up iteration over dicts by looping over items()
  rather than keys() followed by value lookups.
* TODO:  sort only by keys, not keys and values.
This commit is contained in:
Raymond Hettinger 2009-05-27 09:58:34 +00:00
parent 81c0dcee65
commit bcf6f92dc5
3 changed files with 47 additions and 22 deletions

View File

@ -233,7 +233,7 @@ class JSONEncoder(object):
if (_one_shot and c_make_encoder is not None if (_one_shot and c_make_encoder is not None
and not self.indent and not self.sort_keys): and not self.indent):
_iterencode = c_make_encoder( _iterencode = c_make_encoder(
markers, self.default, _encoder, self.indent, markers, self.default, _encoder, self.indent,
self.key_separator, self.item_separator, self.sort_keys, self.key_separator, self.item_separator, self.sort_keys,

View File

@ -43,3 +43,8 @@ class TestEncodeBaseStringAscii(TestCase):
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
s = json.dumps(OrderedDict(items)) s = json.dumps(OrderedDict(items))
self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}')
def test_sorted_dict(self):
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
s = json.dumps(dict(items), sort_keys=True)
self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}')

View File

@ -1334,9 +1334,9 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
static PyObject *empty_dict = NULL; static PyObject *empty_dict = NULL;
PyObject *kstr = NULL; PyObject *kstr = NULL;
PyObject *ident = NULL; PyObject *ident = NULL;
PyObject *key = NULL;
PyObject *value = NULL;
PyObject *it = NULL; PyObject *it = NULL;
PyObject *items;
PyObject *item = NULL;
int skipkeys; int skipkeys;
Py_ssize_t idx; Py_ssize_t idx;
@ -1379,16 +1379,38 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
*/ */
} }
/* TODO: C speedup not implemented for sort_keys */ items = PyObject_CallMethod(dct, "items", ""); /* XXX key=itemgetter(0) */
if (items == NULL)
goto bail;
if (PyObject_IsTrue(s->sort_keys)) {
PyObject *rv;
PyObject *itemlist;
itemlist = PySequence_List(items);
Py_DECREF(items);
if (itemlist == NULL)
goto bail;
it = PyObject_GetIter(dct); rv = PyObject_CallMethod(itemlist, "sort", "");
if (it == NULL) if (rv == NULL) {
Py_DECREF(itemlist);
goto bail;
}
items = itemlist;
}
it = PyObject_GetIter(items);
Py_DECREF(items);
if (it == NULL)
goto bail; goto bail;
skipkeys = PyObject_IsTrue(s->skipkeys); skipkeys = PyObject_IsTrue(s->skipkeys);
idx = 0; idx = 0;
while ((key = PyIter_Next(it)) != NULL) { while ((item = PyIter_Next(it)) != NULL) {
PyObject *encoded; PyObject *encoded, *key, *value;
if (!PyTuple_Check(item) || Py_SIZE(item) != 2) {
PyErr_SetString(PyExc_ValueError, "items must return 2-tuples");
goto bail;
}
key = PyTuple_GET_ITEM(item, 0);
if (PyUnicode_Check(key)) { if (PyUnicode_Check(key)) {
Py_INCREF(key); Py_INCREF(key);
kstr = key; kstr = key;
@ -1398,18 +1420,20 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
if (kstr == NULL) if (kstr == NULL)
goto bail; goto bail;
} }
else if (key == Py_True || key == Py_False || key == Py_None) {
/* This must come before the PyLong_Check because
True and False are also 1 and 0.*/
kstr = _encoded_const(key);
if (kstr == NULL)
goto bail;
}
else if (PyLong_Check(key)) { else if (PyLong_Check(key)) {
kstr = PyObject_Str(key); kstr = PyObject_Str(key);
if (kstr == NULL) if (kstr == NULL)
goto bail; goto bail;
} }
else if (key == Py_True || key == Py_False || key == Py_None) {
kstr = _encoded_const(key);
if (kstr == NULL)
goto bail;
}
else if (skipkeys) { else if (skipkeys) {
Py_DECREF(key); Py_DECREF(item);
continue; continue;
} }
else { else {
@ -1435,14 +1459,11 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
if (PyList_Append(rval, s->key_separator)) if (PyList_Append(rval, s->key_separator))
goto bail; goto bail;
value = PyObject_GetItem(dct, key); value = PyTuple_GET_ITEM(item, 1);
if (value == NULL)
goto bail;
if (encoder_listencode_obj(s, rval, value, indent_level)) if (encoder_listencode_obj(s, rval, value, indent_level))
goto bail; goto bail;
idx += 1; idx += 1;
Py_CLEAR(value); Py_DECREF(item);
Py_DECREF(key);
} }
if (PyErr_Occurred()) if (PyErr_Occurred())
goto bail; goto bail;
@ -1466,8 +1487,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
bail: bail:
Py_XDECREF(it); Py_XDECREF(it);
Py_XDECREF(key); Py_XDECREF(item);
Py_XDECREF(value);
Py_XDECREF(kstr); Py_XDECREF(kstr);
Py_XDECREF(ident); Py_XDECREF(ident);
return -1; return -1;