summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2010-10-30 07:29:44 (GMT)
committerRaymond Hettinger <python@rcn.com>2010-10-30 07:29:44 (GMT)
commitcbba8d4c7a5b77ef60c088b5070b919b32a1b861 (patch)
tree7c2b4561d548e954073f0e34807e04db19d0d484
parent5306234655e6d7f398761214bf0e71491c3c7211 (diff)
downloadcpython-cbba8d4c7a5b77ef60c088b5070b919b32a1b861.zip
cpython-cbba8d4c7a5b77ef60c088b5070b919b32a1b861.tar.gz
cpython-cbba8d4c7a5b77ef60c088b5070b919b32a1b861.tar.bz2
Backport r72961 fixing issue #6105: json.dumps not following OrderedDict iteration order.
-rw-r--r--Lib/json/tests/test_encode_basestring_ascii.py8
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/_json.c27
3 files changed, 32 insertions, 5 deletions
diff --git a/Lib/json/tests/test_encode_basestring_ascii.py b/Lib/json/tests/test_encode_basestring_ascii.py
index 62abe5b..02889f0 100644
--- a/Lib/json/tests/test_encode_basestring_ascii.py
+++ b/Lib/json/tests/test_encode_basestring_ascii.py
@@ -1,6 +1,8 @@
from unittest import TestCase
import json.encoder
+from json import dumps
+from collections import OrderedDict
CASES = [
(u'/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'),
@@ -37,3 +39,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}')
diff --git a/Misc/NEWS b/Misc/NEWS
index 665271e..eeff4a7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -63,6 +63,8 @@ Core and Builtins
Library
-------
+- Issue #6105: json.dumps now respects OrderedDict's iteration order.
+
- Issue #9295: Fix a crash under Windows when calling close() on a file
object with custom buffering from two threads at once.
diff --git a/Modules/_json.c b/Modules/_json.c
index d81721a..de7e171 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -2071,8 +2071,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;
@@ -2083,7 +2084,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) {
@@ -2117,10 +2118,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 (PyString_Check(key) || PyUnicode_Check(key)) {
@@ -2143,6 +2146,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
goto bail;
}
else if (skipkeys) {
+ Py_DECREF(key);
continue;
}
else {
@@ -2156,6 +2160,10 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
goto bail;
}
+ value = PyObject_GetItem(dct, key);
+ if (value == NULL)
+ goto bail;
+
encoded = encoder_encode_string(s, kstr);
Py_CLEAR(kstr);
if (encoded == NULL)
@@ -2170,7 +2178,13 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
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;
@@ -2189,6 +2203,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;