diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 25aa6b30..199744f2 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -43,9 +43,6 @@ jobs: # "This page is taking too long to load." error. Thus we use # pairwise testing. include: - - tarantool: '2.11' - python: '3.11' - msgpack-deps: 'msgpack-python==0.4.0' - tarantool: '2.11' python: '3.11' msgpack-deps: 'msgpack==0.5.0' diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f1e78b8..255846bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Allow to require specific server protocol version and features (#267). +### Changed +- Drop `msgpack-python` support. Use `msgpack` instead. + +### Fixed +- Parsing of E-notation Tarantool decimals with positive exponent (PR #298). + ## 1.0.0 - 2023-04-17 ### Changed diff --git a/tarantool/msgpack_ext/decimal.py b/tarantool/msgpack_ext/decimal.py index 545ee07d..f1654784 100644 --- a/tarantool/msgpack_ext/decimal.py +++ b/tarantool/msgpack_ext/decimal.py @@ -56,6 +56,8 @@ from decimal import Decimal +import msgpack + from tarantool.error import MsgpackError, MsgpackWarning, warn EXT_ID = 1 @@ -353,7 +355,12 @@ def decode(data, _): :raise: :exc:`~tarantool.error.MsgpackError` """ - scale = data[0] + # A decimal starts with mp_int or mp_uint followed by raw bytes. + unpacker = msgpack.Unpacker() + unpacker.feed(data) + + scale = unpacker.unpack() + scale_size = unpacker.tell() sign = get_str_sign(data[-1] & 0x0f) @@ -362,7 +369,7 @@ def decode(data, _): add_str_digit(data[-1] >> 4, digits_reverted, scale) - for i in range(len(data) - 2, 0, -1): + for i in range(len(data) - 2, scale_size - 1, -1): add_str_digit(data[i] & 0x0f, digits_reverted, scale) add_str_digit(data[i] >> 4, digits_reverted, scale) @@ -372,6 +379,12 @@ def decode(data, _): digits_reverted.append(sign) - str_repr = ''.join(digits_reverted[::-1]) + digits = digits_reverted[::-1] + + # Add trailing zeroes in case of a negative scale + for i in range(0, -1 * scale): + add_str_digit(0, digits, scale) + + str_repr = ''.join(digits) return Decimal(str_repr) diff --git a/test/suites/test_decimal.py b/test/suites/test_decimal.py index c817ad08..b880eaa3 100644 --- a/test/suites/test_decimal.py +++ b/test/suites/test_decimal.py @@ -226,6 +226,39 @@ def setUp(self): b'\x09\x87\x65\x43\x21\x98\x76\x54\x32\x1d'), 'tarantool': "decimal.new('-1234567891234567890.0987654321987654321')", }, + 'decimal_exponent_1': { + 'python': decimal.Decimal('1e33'), + 'msgpack': (b'\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0c'), + 'tarantool': "decimal.new('1e33')", + }, + 'decimal_exponent_2': { + 'python': decimal.Decimal('1.2345e33'), + 'msgpack': (b'\x00\x01\x23\x45\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0c'), + 'tarantool': "decimal.new('1.2345e33')", + }, + 'decimal_exponent_3': { + 'python': decimal.Decimal('1.2345e2'), + 'msgpack': (b'\x02\x12\x34\x5c'), + 'tarantool': "decimal.new('1.2345e2')", + }, + 'decimal_exponent_4': { + 'python': decimal.Decimal('1.2345e4'), + 'msgpack': (b'\x00\x12\x34\x5c'), + 'tarantool': "decimal.new('1.2345e4')", + }, + 'decimal_exponent_5': { + 'python': decimal.Decimal('-1e33'), + 'msgpack': (b'\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00' + b'\x00\x00\x00\x00\x00\x00\x00\x0d'), + 'tarantool': "decimal.new('-1e33')", + }, + 'decimal_exponent_6': { + 'python': decimal.Decimal('1e-33'), + 'msgpack': (b'\x21\x1c'), + 'tarantool': "decimal.new('1e-33')", + }, } def test_msgpack_decode(self):