diff --git a/ipyparallel/serialize/serialize.py b/ipyparallel/serialize/serialize.py index 327339bbf..60d860855 100644 --- a/ipyparallel/serialize/serialize.py +++ b/ipyparallel/serialize/serialize.py @@ -102,7 +102,12 @@ def serialize_object(obj, buffer_threshold=MAX_BYTES, item_threshold=MAX_ITEMS): buffers.extend(_extract_buffers(c, buffer_threshold)) elif istype(obj, dict) and len(obj) < item_threshold: cobj = {} - for k in sorted(obj): + try: + keys = sorted(obj) + except TypeError: + # keys that can't be ordered (e.g. mixed str and int) + keys = list(obj) + for k in keys: c = can(obj[k]) buffers.extend(_extract_buffers(c, buffer_threshold)) cobj[k] = c @@ -135,7 +140,9 @@ def deserialize_object(buffers, g=None): newobj = uncan_sequence(canned, g) elif istype(canned, dict) and len(canned) < MAX_ITEMS: newobj = {} - for k in sorted(canned): + # the unpickled dict keeps the key order serialize_object built it in, + # which is the order its buffers were extracted + for k in canned: c = canned[k] _restore_buffers(c, bufs) newobj[k] = uncan(c, g) diff --git a/ipyparallel/tests/test_serialize.py b/ipyparallel/tests/test_serialize.py index 46f614560..916b32405 100644 --- a/ipyparallel/tests/test_serialize.py +++ b/ipyparallel/tests/test_serialize.py @@ -148,6 +148,30 @@ def test_numpy_in_dict(): assert_array_equal(A, B) +def test_dict_unsortable_keys(): + d = {'A': 1, 2: 2} + bufs = serialize_object(d) + d2, r = deserialize_object(bufs) + assert r == [] + assert d2 == d + + +def test_numpy_in_dict_unsortable_keys(): + pytest.importorskip('numpy') + from numpy.testing import assert_array_equal + + A = new_array((100, 100), dtype='float64') + B = new_array((1000,), dtype='int32') + d = {'b': B, 1: A, 'c': 3} + bufs = serialize_object(d) + assert len(bufs) == 3 + d2, r = deserialize_object(bufs) + assert r == [] + assert d2['c'] == 3 + assert_array_equal(d2[1], A) + assert_array_equal(d2['b'], B) + + def test_class(): @interactive class C: