@@ -1793,6 +1793,76 @@ _encoder_iterate_dict_lock_held(PyEncoderObject *s, PyUnicodeWriter *writer,
17931793 return 0 ;
17941794}
17951795
1796+ /* Sort the (key, value) pairs in separate groups, because keys of
1797+ different types are not comparable: strings, numbers and None.
1798+ Unsupported keys are skipped if skipkeys is true and reported otherwise.
1799+ Return a new list, or NULL on error. */
1800+ static PyObject *
1801+ encoder_sort_items (PyObject * items , int skipkeys )
1802+ {
1803+ enum {STRINGS , NUMBERS , NONES , NGROUPS };
1804+ PyObject * groups [NGROUPS ] = {NULL };
1805+ PyObject * result = NULL ;
1806+
1807+ for (int i = 0 ; i < NGROUPS ; i ++ ) {
1808+ groups [i ] = PyList_New (0 );
1809+ if (groups [i ] == NULL ) {
1810+ goto done ;
1811+ }
1812+ }
1813+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (items ); i ++ ) {
1814+ PyObject * item = PyList_GET_ITEM (items , i );
1815+ if (!PyTuple_Check (item ) || PyTuple_GET_SIZE (item ) != 2 ) {
1816+ PyErr_SetString (PyExc_ValueError , "items must return 2-tuples" );
1817+ goto done ;
1818+ }
1819+ PyObject * key = PyTuple_GET_ITEM (item , 0 );
1820+ int group ;
1821+ if (PyUnicode_Check (key )) {
1822+ group = STRINGS ;
1823+ }
1824+ else if (key == Py_None ) {
1825+ group = NONES ;
1826+ }
1827+ else if (PyLong_Check (key ) || PyFloat_Check (key )) { // includes bool
1828+ group = NUMBERS ;
1829+ }
1830+ else if (skipkeys ) {
1831+ continue ;
1832+ }
1833+ else {
1834+ PyErr_Format (PyExc_TypeError ,
1835+ "keys must be str, int, float, bool or None, "
1836+ "not %.100s" , Py_TYPE (key )-> tp_name );
1837+ goto done ;
1838+ }
1839+ if (PyList_Append (groups [group ], item ) < 0 ) {
1840+ goto done ;
1841+ }
1842+ }
1843+ /* There is at most one None key. */
1844+ if (PyList_Sort (groups [STRINGS ]) < 0 ||
1845+ PyList_Sort (groups [NUMBERS ]) < 0 )
1846+ {
1847+ goto done ;
1848+ }
1849+ result = groups [STRINGS ];
1850+ groups [STRINGS ] = NULL ;
1851+ for (int i = STRINGS + 1 ; i < NGROUPS ; i ++ ) {
1852+ Py_ssize_t size = PyList_GET_SIZE (result );
1853+ if (PyList_SetSlice (result , size , size , groups [i ]) < 0 ) {
1854+ Py_CLEAR (result );
1855+ goto done ;
1856+ }
1857+ }
1858+
1859+ done :
1860+ for (int i = 0 ; i < NGROUPS ; i ++ ) {
1861+ Py_XDECREF (groups [i ]);
1862+ }
1863+ return result ;
1864+ }
1865+
17961866static int
17971867encoder_listencode_dict (PyEncoderObject * s , PyUnicodeWriter * writer ,
17981868 PyObject * dct ,
@@ -1837,10 +1907,21 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
18371907
18381908 if (s -> sort_keys || !PyAnyDict_CheckExact (dct )) {
18391909 PyObject * items = PyMapping_Items (dct );
1840- if (items == NULL || (s -> sort_keys && PyList_Sort (items ) < 0 )) {
1841- Py_XDECREF (items );
1910+ if (items == NULL ) {
18421911 goto bail ;
18431912 }
1913+ if (s -> sort_keys && PyList_Sort (items ) < 0 ) {
1914+ if (!PyErr_ExceptionMatches (PyExc_TypeError )) {
1915+ Py_DECREF (items );
1916+ goto bail ;
1917+ }
1918+ /* Keys of different types are not comparable. */
1919+ PyErr_Clear ();
1920+ Py_SETREF (items , encoder_sort_items (items , s -> skipkeys ));
1921+ if (items == NULL ) {
1922+ goto bail ;
1923+ }
1924+ }
18441925
18451926 int result ;
18461927 Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST (items );
0 commit comments