diff -r d9e83e426565 Lib/json/__init__.py --- a/Lib/json/__init__.py Fri Jun 26 02:50:21 2015 -0700 +++ b/Lib/json/__init__.py Sat Jun 27 11:06:17 2015 -0400 @@ -153,7 +153,8 @@ of obj or raise TypeError. The default simply raises TypeError. If *sort_keys* is ``True`` (default: ``False``), then the output of - dictionaries will be sorted by key. + dictionaries will be sorted by key. If *sort_keys* is a callable, + it will be used as the sort key function. To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the ``.default()`` method to serialize additional types), specify it with diff -r d9e83e426565 Lib/json/encoder.py --- a/Lib/json/encoder.py Fri Jun 26 02:50:21 2015 -0700 +++ b/Lib/json/encoder.py Sat Jun 27 11:06:17 2015 -0400 @@ -128,6 +128,7 @@ If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis. + If sort_keys is a callable, it will be used as the sort key function. If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that @@ -244,7 +245,8 @@ if (_one_shot and c_make_encoder is not None - and self.indent is None): + and self.indent is None + and not callable(self.sort_keys)): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, @@ -349,7 +351,11 @@ item_separator = _item_separator first = True if _sort_keys: - items = sorted(dct.items(), key=lambda kv: kv[0]) + if callable(_sort_keys): + sorter = lambda kv: _sort_keys(kv[0]) + else: + sorter = lambda kv: kv[0] + items = sorted(dct.items(), key=sorter) else: items = dct.items() for key, value in items: diff -r d9e83e426565 Lib/test/test_json/test_sort.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/test/test_json/test_sort.py Sat Jun 27 11:06:17 2015 -0400 @@ -0,0 +1,17 @@ +from io import StringIO +from test.test_json import PyTest, CTest + + +class TestSort: + # Issue 24518 + def test_callable_sort_keys(self): + data = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5} + is_odd = lambda n: n % 2 + sio = StringIO() + self.json.dump(data, sio, sort_keys=is_odd) + result = sio.getvalue() + self.assertTrue(result.find("2") < result.find("1")) + self.assertTrue(result.find("4") < result.find("3")) + +class TestPyIndent(TestSort, PyTest): pass +class TestCIndent(TestSort, CTest): pass