]> granicus.if.org Git - python/commitdiff
* Fix-up a TODO (support the sort_key option).
authorRaymond Hettinger <python@rcn.com>
Wed, 27 May 2009 09:58:34 +0000 (09:58 +0000)
committerRaymond Hettinger <python@rcn.com>
Wed, 27 May 2009 09:58:34 +0000 (09:58 +0000)
* 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.

Lib/json/encoder.py
Lib/json/tests/test_encode_basestring_ascii.py
Modules/_json.c

index 3c306ab8e22762155d655b984ef08036040ffe31..2beb10e358bd61ad54cf7613a4afb31cbbcc4054 100644 (file)
@@ -233,7 +233,7 @@ class JSONEncoder(object):
 
 
         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(
                 markers, self.default, _encoder, self.indent,
                 self.key_separator, self.item_separator, self.sort_keys,
index 87114692ccfe92be5700bebf66d0861e70aa82b2..dbcb09af9ce603847159c06e32989d2bac20db99 100644 (file)
@@ -43,3 +43,8 @@ class TestEncodeBaseStringAscii(TestCase):
         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}')
+
+    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}')
index 90f57367caed916d9f33bc550d302906e71f08b8..f33503bfa0a00ecd7c847fbb26fe21b42d1ce2eb 100644 (file)
@@ -1334,9 +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 = NULL;
-    PyObject *value = NULL;
     PyObject *it = NULL;
+    PyObject *items;
+    PyObject *item = NULL;
     int skipkeys;
     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);
-    if (it == NULL)
+        rv = PyObject_CallMethod(itemlist, "sort", "");
+        if (rv == NULL) {
+            Py_DECREF(itemlist);
+            goto bail;
+        }
+        items = itemlist;
+    }
+    it = PyObject_GetIter(items);
+       Py_DECREF(items);
+       if (it == NULL)
         goto bail;
     skipkeys = PyObject_IsTrue(s->skipkeys);
     idx = 0;
-    while ((key = PyIter_Next(it)) != NULL) {
-        PyObject *encoded;
-
+    while ((item = PyIter_Next(it)) != NULL) {
+        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)) {
             Py_INCREF(key);
             kstr = key;
@@ -1398,18 +1420,20 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
             if (kstr == NULL)
                 goto bail;
         }
-        else if (PyLong_Check(key)) {
-            kstr = PyObject_Str(key);
+        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 (key == Py_True || key == Py_False || key == Py_None) {
-            kstr = _encoded_const(key);
+        else if (PyLong_Check(key)) {
+            kstr = PyObject_Str(key);
             if (kstr == NULL)
                 goto bail;
         }
         else if (skipkeys) {
-            Py_DECREF(key);
+            Py_DECREF(item);
             continue;
         }
         else {
@@ -1435,14 +1459,11 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
         if (PyList_Append(rval, s->key_separator))
             goto bail;
 
-        value = PyObject_GetItem(dct, key);
-        if (value == NULL)
-            goto bail;
+        value = PyTuple_GET_ITEM(item, 1);
         if (encoder_listencode_obj(s, rval, value, indent_level))
             goto bail;
         idx += 1;
-        Py_CLEAR(value);
-        Py_DECREF(key);
+        Py_DECREF(item);
     }
     if (PyErr_Occurred())
         goto bail;
@@ -1466,8 +1487,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ss
 
 bail:
     Py_XDECREF(it);
-    Py_XDECREF(key);
-    Py_XDECREF(value);
+    Py_XDECREF(item);
     Py_XDECREF(kstr);
     Py_XDECREF(ident);
     return -1;