diff options
author | Raymond Hettinger <python@rcn.com> | 2010-10-30 07:29:44 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2010-10-30 07:29:44 (GMT) |
commit | cbba8d4c7a5b77ef60c088b5070b919b32a1b861 (patch) | |
tree | 7c2b4561d548e954073f0e34807e04db19d0d484 | |
parent | 5306234655e6d7f398761214bf0e71491c3c7211 (diff) | |
download | cpython-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.py | 8 | ||||
-rw-r--r-- | Misc/NEWS | 2 | ||||
-rw-r--r-- | Modules/_json.c | 27 |
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}') @@ -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; |