Issue 6105: json encoder to respect iteration order of its inputs.

This commit is contained in:
Raymond Hettinger 2009-05-27 06:50:31 +00:00
parent 0ffaaa634d
commit c8d952dfe4
2 changed files with 30 additions and 5 deletions

View File

@ -1,6 +1,8 @@
from unittest import TestCase
import json.encoder
from json import dumps
from collections import OrderedDict
CASES = [
('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'),
@ -35,3 +37,9 @@ class TestEncodeBaseStringAscii(TestCase):
self.assertEquals(result, expect,
'{0!r} != {1!r} for {2}({3!r})'.format(
result, expect, fname, input_string))
def test_ordered_dict(self):
# See issue 6105
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
s = json.dumps(OrderedDict(items))
self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}')

View File

@ -1334,8 +1334,9 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
static PyObject *empty_dict = NULL;
PyObject *kstr = NULL;
PyObject *ident = NULL;
PyObject *key, *value;
Py_ssize_t pos;
PyObject *key = NULL;
PyObject *value = NULL;
PyObject *it = NULL;
int skipkeys;
Py_ssize_t idx;
@ -1346,7 +1347,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
if (open_dict == NULL || close_dict == NULL || empty_dict == NULL)
return -1;
}
if (PyDict_Size(dct) == 0)
if (Py_SIZE(dct) == 0)
return PyList_Append(rval, empty_dict);
if (s->markers != Py_None) {
@ -1380,10 +1381,12 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
/* TODO: C speedup not implemented for sort_keys */
pos = 0;
it = PyObject_GetIter(dct);
if (it == NULL)
goto bail;
skipkeys = PyObject_IsTrue(s->skipkeys);
idx = 0;
while (PyDict_Next(dct, &pos, &key, &value)) {
while ((key = PyIter_Next(it)) != NULL) {
PyObject *encoded;
if (PyUnicode_Check(key)) {
@ -1406,6 +1409,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
goto bail;
}
else if (skipkeys) {
Py_DECREF(key);
continue;
}
else {
@ -1430,10 +1434,20 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
Py_DECREF(encoded);
if (PyList_Append(rval, s->key_separator))
goto bail;
value = PyObject_GetItem(dct, key);
if (value == NULL)
goto bail;
if (encoder_listencode_obj(s, rval, value, indent_level))
goto bail;
idx += 1;
Py_CLEAR(value);
Py_DECREF(key);
}
if (PyErr_Occurred())
goto bail;
Py_CLEAR(it);
if (ident != NULL) {
if (PyDict_DelItem(s->markers, ident))
goto bail;
@ -1451,6 +1465,9 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
return 0;
bail:
Py_XDECREF(it);
Py_XDECREF(key);
Py_XDECREF(value);
Py_XDECREF(kstr);
Py_XDECREF(ident);
return -1;