Skip to content

Commit 9607578

Browse files
msgpack: support UUID extended type
Tarantool supports UUID type since version 2.4.1 [1]. This patch introduced the support of Tarantool UUID type in msgpack decoders and encoders. The Tarantool UUID type is mapped to the native Python uuid.UUID type. 1. tarantool/tarantool#4268 Closed #202
1 parent 24a618c commit 9607578

File tree

6 files changed

+88
-5
lines changed

6 files changed

+88
-5
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
### Added
1010
- Decimal type support (#203).
11+
- UUID type support (#202).
1112

1213
### Changed
1314
- Bump msgpack requirement to 1.0.4 (PR #223).

Diff for: tarantool/ext_types/packer.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
from decimal import Decimal
2+
from uuid import UUID
23
from msgpack import ExtType
34

45
import tarantool.ext_types.decimal as ext_decimal
6+
import tarantool.ext_types.uuid as ext_uuid
7+
8+
encoders = [
9+
{'type': Decimal, 'ext': ext_decimal},
10+
{'type': UUID, 'ext': ext_uuid },
11+
]
512

613
def default(obj):
7-
if isinstance(obj, Decimal):
8-
return ExtType(ext_decimal.EXT_ID, ext_decimal.encode(obj))
14+
for encoder in encoders:
15+
if isinstance(obj, encoder['type']):
16+
return ExtType(encoder['ext'].EXT_ID, encoder['ext'].encode(obj))
917
raise TypeError("Unknown type: %r" % (obj,))

Diff for: tarantool/ext_types/unpacker.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
from decimal import Decimal
22

33
import tarantool.ext_types.decimal as ext_decimal
4+
import tarantool.ext_types.uuid as ext_uuid
5+
6+
decoders = {
7+
ext_decimal.EXT_ID: ext_decimal.decode,
8+
ext_uuid.EXT_ID : ext_uuid.decode ,
9+
}
410

511
def ext_hook(code, data):
6-
if code == ext_decimal.EXT_ID:
7-
return ext_decimal.decode(data)
12+
if decoders[code]:
13+
return decoders[code](data)
814
raise NotImplementedError("Unknown msgpack type: %d" % (code,))

Diff for: tarantool/ext_types/uuid.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from uuid import UUID
2+
3+
# https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-uuid-type
4+
#
5+
# The UUID MessagePack representation looks like this:
6+
# +--------+------------+-----------------+
7+
# | MP_EXT | MP_UUID | UuidValue |
8+
# | = d8 | = 2 | = 16-byte value |
9+
# +--------+------------+-----------------+
10+
11+
EXT_ID = 2
12+
13+
def encode(obj):
14+
return obj.bytes
15+
16+
def decode(data):
17+
return UUID(bytes=data)

Diff for: test/suites/lib/skip.py

+11
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,14 @@ def skip_or_run_decimal_test(func):
143143

144144
return skip_or_run_test_pcall_require(func, 'decimal',
145145
'does not support decimal type')
146+
147+
def skip_or_run_UUID_test(func):
148+
"""Decorator to skip or run UUID-related tests depending on
149+
the tarantool version.
150+
151+
Tarantool supports UUID type only since 2.4.1 version.
152+
See https://github.com/tarantool/tarantool/issues/4268
153+
"""
154+
155+
return skip_or_run_test_tarantool(func, '2.4.1',
156+
'does not support UUID type')

Diff for: test/suites/test_ext_types.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44

55
import sys
66
import unittest
7+
import uuid
78
import decimal
89
import warnings
910
import tarantool
1011

1112
from .lib.tarantool_server import TarantoolServer
12-
from .lib.skip import skip_or_run_decimal_test
13+
from .lib.skip import skip_or_run_decimal_test, skip_or_run_UUID_test
1314
from tarantool.error import MsgpackError, MsgpackWarning
1415

1516
class TestSuite_ExtTypes(unittest.TestCase):
@@ -24,6 +25,7 @@ def setUpClass(self):
2425
self.adm = self.srv.admin
2526
self.adm(r"""
2627
_, decimal = pcall(require, 'decimal')
28+
_, uuid = pcall(require, 'uuid')
2729
2830
box.schema.space.create('test')
2931
box.space['test']:create_index('primary', {
@@ -200,6 +202,44 @@ def test_decimal_encode_with_precision_loss(self):
200202
""" % (i, decimal_case['result'])),
201203
[True])
202204

205+
206+
UUID_cases = [
207+
"ae28d4f6-076c-49dd-8227-7f9fae9592d0",
208+
"b3121301-9300-4038-a652-ead943fb9c39",
209+
"dfa69f02-92e6-44a5-abb5-84b39292ff93",
210+
"8b69a1ce-094a-4e21-a5dc-4cdae7cd8960",
211+
"25932334-1d42-4686-9299-ec1a7165227c",
212+
]
213+
214+
@skip_or_run_UUID_test
215+
def test_UUID_decode(self):
216+
for i in range(len(self.UUID_cases)):
217+
with self.subTest(msg=str(i)):
218+
UUID_case = self.UUID_cases[i]
219+
220+
self.adm("box.space['test']:replace{%d, uuid.fromstr('%s')}" % (i, UUID_case))
221+
222+
self.assertSequenceEqual(
223+
self.con.select('test', i),
224+
[[i, uuid.UUID(UUID_case)]])
225+
226+
@skip_or_run_UUID_test
227+
def test_UUID_encode(self):
228+
for i in range(len(self.UUID_cases)):
229+
with self.subTest(msg=str(i)):
230+
UUID_case = self.UUID_cases[i]
231+
232+
self.con.insert('test', [i, uuid.UUID(UUID_case)])
233+
234+
self.assertSequenceEqual(
235+
self.con.eval("""
236+
local tuple = box.space['test']:get(%d)
237+
assert(tuple ~= nil)
238+
239+
return tuple[2] == uuid.fromstr('%s')
240+
""" % (i, UUID_case)),
241+
[True])
242+
203243
@classmethod
204244
def tearDownClass(self):
205245
self.con.close()

0 commit comments

Comments
 (0)