Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c8d952d

Browse files
committed
Issue 6105: json encoder to respect iteration order of its inputs.
1 parent 0ffaaa6 commit c8d952d

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

Lib/json/tests/test_encode_basestring_ascii.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from unittest import TestCase
22

33
import json.encoder
4+
from json import dumps
5+
from collections import OrderedDict
46

57
CASES = [
68
('/\\"\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 @@ def _test_encode_basestring_ascii(self, encode_basestring_ascii):
3537
self.assertEquals(result, expect,
3638
'{0!r} != {1!r} for {2}({3!r})'.format(
3739
result, expect, fname, input_string))
40+
41+
def test_ordered_dict(self):
42+
# See issue 6105
43+
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
44+
s = json.dumps(OrderedDict(items))
45+
self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}')

Modules/_json.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,8 +1334,9 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
13341334
static PyObject *empty_dict = NULL;
13351335
PyObject *kstr = NULL;
13361336
PyObject *ident = NULL;
1337-
PyObject *key, *value;
1338-
Py_ssize_t pos;
1337+
PyObject *key = NULL;
1338+
PyObject *value = NULL;
1339+
PyObject *it = NULL;
13391340
int skipkeys;
13401341
Py_ssize_t idx;
13411342

@@ -1346,7 +1347,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
13461347
if (open_dict == NULL || close_dict == NULL || empty_dict == NULL)
13471348
return -1;
13481349
}
1349-
if (PyDict_Size(dct) == 0)
1350+
if (Py_SIZE(dct) == 0)
13501351
return PyList_Append(rval, empty_dict);
13511352

13521353
if (s->markers != Py_None) {
@@ -1380,10 +1381,12 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
13801381

13811382
/* TODO: C speedup not implemented for sort_keys */
13821383

1383-
pos = 0;
1384+
it = PyObject_GetIter(dct);
1385+
if (it == NULL)
1386+
goto bail;
13841387
skipkeys = PyObject_IsTrue(s->skipkeys);
13851388
idx = 0;
1386-
while (PyDict_Next(dct, &pos, &key, &value)) {
1389+
while ((key = PyIter_Next(it)) != NULL) {
13871390
PyObject *encoded;
13881391

13891392
if (PyUnicode_Check(key)) {
@@ -1406,6 +1409,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
14061409
goto bail;
14071410
}
14081411
else if (skipkeys) {
1412+
Py_DECREF(key);
14091413
continue;
14101414
}
14111415
else {
@@ -1430,10 +1434,20 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
14301434
Py_DECREF(encoded);
14311435
if (PyList_Append(rval, s->key_separator))
14321436
goto bail;
1437+
1438+
value = PyObject_GetItem(dct, key);
1439+
if (value == NULL)
1440+
goto bail;
14331441
if (encoder_listencode_obj(s, rval, value, indent_level))
14341442
goto bail;
14351443
idx += 1;
1444+
Py_CLEAR(value);
1445+
Py_DECREF(key);
14361446
}
1447+
if (PyErr_Occurred())
1448+
goto bail;
1449+
Py_CLEAR(it);
1450+
14371451
if (ident != NULL) {
14381452
if (PyDict_DelItem(s->markers, ident))
14391453
goto bail;
@@ -1451,6 +1465,9 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
14511465
return 0;
14521466

14531467
bail:
1468+
Py_XDECREF(it);
1469+
Py_XDECREF(key);
1470+
Py_XDECREF(value);
14541471
Py_XDECREF(kstr);
14551472
Py_XDECREF(ident);
14561473
return -1;

0 commit comments

Comments
 (0)