From 419fe6cf42196d7490dff211faeeeceeb649d633 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Mon, 12 May 2025 11:28:18 -0500 Subject: [PATCH 1/5] add logic to convert dict list key to tuple --- msgpack/unpack.h | 19 +++++++++++++++++++ test/test_case.py | 3 +++ 2 files changed, 22 insertions(+) diff --git a/msgpack/unpack.h b/msgpack/unpack.h index 58a2f4f5..4bd5fc48 100644 --- a/msgpack/unpack.h +++ b/msgpack/unpack.h @@ -199,6 +199,25 @@ static inline int unpack_callback_map_item(unpack_user* u, unsigned int current, if (PyUnicode_CheckExact(k)) { PyUnicode_InternInPlace(&k); } + if (PyList_CheckExact(k)) { + Py_ssize_t list_size = PyList_Size(k); + PyObject* tuple = PyTuple_New(list_size); + + if (tuple == NULL) { + return -1; + } + + for (Py_ssize_t i = 0; i < list_size; i++) { + PyObject* item = PyList_GetItem(k, i); + Py_INCREF(item); + if (PyTuple_SetItem(tuple, i, item) != 0) { + Py_DECREF(tuple); + return -1; + } + } + Py_DECREF(k); + k = tuple; + } if (u->has_pairs_hook) { msgpack_unpack_object item = PyTuple_Pack(2, k, v); if (!item) diff --git a/test/test_case.py b/test/test_case.py index c4c615e3..39028d7f 100644 --- a/test/test_case.py +++ b/test/test_case.py @@ -134,3 +134,6 @@ def test_match(): def test_unicode(): assert unpackb(packb("foobar"), use_list=1) == "foobar" + +def test_dict_tuple_key(): + unpackb(packb({(1, 2): 3}), strict_map_key=False) From fbaa8ed6c87d069770f678782d1ac9383a93d0ae Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Mon, 12 May 2025 11:51:37 -0500 Subject: [PATCH 2/5] fix formatting --- test/test_case.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_case.py b/test/test_case.py index 39028d7f..a85634ca 100644 --- a/test/test_case.py +++ b/test/test_case.py @@ -135,5 +135,6 @@ def test_match(): def test_unicode(): assert unpackb(packb("foobar"), use_list=1) == "foobar" + def test_dict_tuple_key(): unpackb(packb({(1, 2): 3}), strict_map_key=False) From 30b0c6c5072be1aa4afac32083bd0c2b9329d292 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Mon, 12 May 2025 11:59:39 -0500 Subject: [PATCH 3/5] add pure python logic --- msgpack/fallback.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msgpack/fallback.py b/msgpack/fallback.py index b02e47cf..5f624b8f 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -529,6 +529,8 @@ def _unpack(self, execute=EX_CONSTRUCT): raise ValueError("%s is not allowed for map key" % str(type(key))) if isinstance(key, str): key = sys.intern(key) + if isinstance(key, list): + key = tuple(key) ret[key] = self._unpack(EX_CONSTRUCT) if self._object_hook is not None: ret = self._object_hook(ret) From 887f102a7b58a87d45e24fbba5ee615ce14d4d3f Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Wed, 14 May 2025 19:23:26 -0500 Subject: [PATCH 4/5] else if --- msgpack/fallback.py | 2 +- msgpack/unpack.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/msgpack/fallback.py b/msgpack/fallback.py index 5f624b8f..4307bc83 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -529,7 +529,7 @@ def _unpack(self, execute=EX_CONSTRUCT): raise ValueError("%s is not allowed for map key" % str(type(key))) if isinstance(key, str): key = sys.intern(key) - if isinstance(key, list): + elif isinstance(key, list): key = tuple(key) ret[key] = self._unpack(EX_CONSTRUCT) if self._object_hook is not None: diff --git a/msgpack/unpack.h b/msgpack/unpack.h index 4bd5fc48..28a0b049 100644 --- a/msgpack/unpack.h +++ b/msgpack/unpack.h @@ -198,8 +198,7 @@ static inline int unpack_callback_map_item(unpack_user* u, unsigned int current, } if (PyUnicode_CheckExact(k)) { PyUnicode_InternInPlace(&k); - } - if (PyList_CheckExact(k)) { + } else if (PyList_CheckExact(k)) { Py_ssize_t list_size = PyList_Size(k); PyObject* tuple = PyTuple_New(list_size); From 08400e0c986d8bcaedb16adaaf31b2baddd46092 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Thu, 15 May 2025 09:23:14 -0500 Subject: [PATCH 5/5] use type() is list for exact checking --- msgpack/fallback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgpack/fallback.py b/msgpack/fallback.py index 4307bc83..8fcc1d7e 100644 --- a/msgpack/fallback.py +++ b/msgpack/fallback.py @@ -529,7 +529,7 @@ def _unpack(self, execute=EX_CONSTRUCT): raise ValueError("%s is not allowed for map key" % str(type(key))) if isinstance(key, str): key = sys.intern(key) - elif isinstance(key, list): + elif type(key) is list: key = tuple(key) ret[key] = self._unpack(EX_CONSTRUCT) if self._object_hook is not None: