From 3383010a9dd237d274c280f88264f2fcdd44c6d9 Mon Sep 17 00:00:00 2001 From: thelastbackspace <23155651+thelastbackspace@users.noreply.github.com> Date: Wed, 4 Nov 2026 23:14:55 +0100 Subject: [PATCH] serialize: handle dicts whose keys can't be sorted serialize_object/deserialize_object walked small dicts with sorted(), which raises TypeError for mixed key types like {'A': 1, 2: 2}. Fall back to insertion order when sorting fails, and walk the unpickled dict in its own order on the way back, which is the order the buffers were extracted in. Closes #1057 --- ipyparallel/serialize/serialize.py | 11 +++++++++-- ipyparallel/tests/test_serialize.py | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) 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: