From 8052d1411177164ec0e5e053785aedfe9463d67d Mon Sep 17 00:00:00 2001 From: Vanya Sergeev Date: Wed, 17 Sep 2014 02:07:50 -0700 Subject: [PATCH] add support for unpacking maps with array keys Fixes #10 --- test_umsgpack.py | 10 +++++++--- umsgpack.py | 23 +++++++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/test_umsgpack.py b/test_umsgpack.py index 04e2906..b61f519 100644 --- a/test_umsgpack.py +++ b/test_umsgpack.py @@ -128,7 +128,11 @@ # Complex Array [ "complex array", [ True, 0x01, umsgpack.Ext(0x03, b"foo"), 0xff, { 1: False, 2: u"abc" }, b"\x80", [ 1, 2, 3], u"abc" ], b"\x98\xc3\x01\xc7\x03\x03\x66\x6f\x6f\xcc\xff\x82\x01\xc2\x02\xa3\x61\x62\x63\xc4\x01\x80\x93\x01\x02\x03\xa3\x61\x62\x63" ], # Complex Map - [ "complex map", { 1 : [{1: 2, 3: 4}, {}], 2: 1, 3: [False, u"def"], 4: {0x100000000: u"a", 0xffffffff: u"b"}}, b"\x84\x01\x92\x82\x01\x02\x03\x04\x80\x02\x01\x03\x92\xc2\xa3\x64\x65\x66\x04\x82\xcf\x00\x00\x00\x01\x00\x00\x00\x00\xa1\x61\xce\xff\xff\xff\xff\xa1\x62" ] + [ "complex map", { 1 : [{1: 2, 3: 4}, {}], 2: 1, 3: [False, u"def"], 4: {0x100000000: u"a", 0xffffffff: u"b"}}, b"\x84\x01\x92\x82\x01\x02\x03\x04\x80\x02\x01\x03\x92\xc2\xa3\x64\x65\x66\x04\x82\xcf\x00\x00\x00\x01\x00\x00\x00\x00\xa1\x61\xce\xff\xff\xff\xff\xa1\x62" ], + # Map with Tuple Keys + [ "map with tuple keys", {(u"foo", False, 3) : True, (3e6, -5): u"def"}, b"\x82\x92\xcb\x41\x46\xe3\x60\x00\x00\x00\x00\xfb\xa3\x64\x65\x66\x93\xa3\x66\x6f\x6f\xc2\x03\xc3" ], + # Map with Complex Tuple Keys + [ "map with complex tuple keys", {(u"foo", (1,2,3), 3) : -5}, b"\x81\x93\xa3\x66\x6f\x6f\x93\x01\x02\x03\x03\xfb" ] ] pack_exception_test_vectors = [ @@ -176,10 +180,10 @@ [ "insufficient data ext 8-bit", b"\xc7\x05\x05\x01\x02\x03", umsgpack.InsufficientDataException ], [ "insufficient data ext 16-bit", b"\xc8\x01\x00\x05\x01\x02\x03", umsgpack.InsufficientDataException ], [ "insufficient data ext 32-bit", b"\xc9\x00\x01\x00\x00\x05\x01\x02\x03", umsgpack.InsufficientDataException ], - # Unhashable key { 1 : False, [1,2,3] : True } - [ "unhashable key", b"\x82\x01\xc2\x93\x01\x02\x03\xc3", umsgpack.UnhashableKeyException ], # Unhashable key { 1 : True, { 1 : 1 } : False } [ "unhashable key", b"\x82\x01\xc3\x81\x01\x01\xc2", umsgpack.UnhashableKeyException ], + # Unhashable key { [ 1, 2, {} ] : True } + [ "unhashable key", b"\x81\x93\x01\x02\x80\xc3", umsgpack.UnhashableKeyException ], # Key duplicate { 1 : True, 1 : False } [ "duplicate key", b"\x82\x01\xc3\x01\xc2", umsgpack.DuplicateKeyException ], # Reserved code (0xc1) diff --git a/umsgpack.py b/umsgpack.py index 9620ea7..30b9de6 100644 --- a/umsgpack.py +++ b/umsgpack.py @@ -1,4 +1,4 @@ -# u-msgpack-python v1.6 - vsergeev at gmail +# u-msgpack-python v1.8 - vsergeev at gmail # https://github.com/vsergeev/u-msgpack-python # # u-msgpack-python is a lightweight MessagePack serializer and deserializer @@ -31,7 +31,7 @@ # THE SOFTWARE. # """ -u-msgpack-python v1.6 - vsergeev at gmail +u-msgpack-python v1.8 - vsergeev at gmail https://github.com/vsergeev/u-msgpack-python u-msgpack-python is a lightweight MessagePack serializer and deserializer @@ -44,7 +44,7 @@ License: MIT """ -version = (1,6) +version = (1,8) "Module version tuple" import struct @@ -531,6 +531,11 @@ def _unpack_array(code, read_fn): return [_unpackb(read_fn) for i in range(length)] +def _deep_list_to_tuple(x): + if isinstance(x, list): + return tuple([_deep_list_to_tuple(e) for e in x]) + return x + def _unpack_map(code, read_fn): if (ord(code) & 0xf0) == 0x80: length = (ord(code) & ~0xf0) @@ -546,15 +551,21 @@ def _unpack_map(code, read_fn): # Unpack key k = _unpackb(read_fn) - if not isinstance(k, collections.Hashable): - raise UnhashableKeyException("encountered unhashable key type: %s" % str(type(k))) + if isinstance(k, list): + # Attempt to convert list into a hashable tuple + k = _deep_list_to_tuple(k) + elif not isinstance(k, collections.Hashable): + raise UnhashableKeyException("encountered unhashable key: %s, %s" % (str(k), str(type(k)))) elif k in d: raise DuplicateKeyException("encountered duplicate key: %s, %s" % (str(k), str(type(k)))) # Unpack value v = _unpackb(read_fn) - d[k] = v + try: + d[k] = v + except TypeError: + raise UnhashableKeyException("encountered unhashable key: %s" % str(k)) return d ########################################