From 2b49143a4c7cc2515c26c6992de3e76613c5bd39 Mon Sep 17 00:00:00 2001 From: Rio Yu <52408936+rioyu123@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:38:29 +0800 Subject: [PATCH] fix: preserve binary decimals outside the current context range --- src-python/amazon/ion/reader_binary.py | 16 +++------------- tests/test_simpleion.py | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src-python/amazon/ion/reader_binary.py b/src-python/amazon/ion/reader_binary.py index 6b5d8d5d3..b4fe8e6e3 100644 --- a/src-python/amazon/ion/reader_binary.py +++ b/src-python/amazon/ion/reader_binary.py @@ -13,7 +13,7 @@ # License. from collections import deque from datetime import timedelta -from decimal import Decimal, localcontext +from decimal import Decimal from enum import IntEnum from functools import partial from io import BytesIO @@ -185,18 +185,8 @@ def _parse_decimal(buf): exponent = _parse_var_int(buf, signed=True) sign_bit, coefficient = _parse_signed_int_components(buf) - if coefficient == 0: - # Handle the zero cases--especially negative zero - value = Decimal((sign_bit, (0,), exponent)) - else: - coefficient *= sign_bit and -1 or 1 - with localcontext() as context: - # Adjusting precision for taking into account arbitrarily - # large/small numbers - context.prec = len(str(coefficient)) - value = Decimal(coefficient).scaleb(exponent) - - return value + # Construct the value without applying the caller's arithmetic context. + return Decimal((sign_bit, Decimal(coefficient).as_tuple().digits, exponent)) def _parse_sid_iter(data): diff --git a/tests/test_simpleion.py b/tests/test_simpleion.py index 3cf264143..da75d4eba 100644 --- a/tests/test_simpleion.py +++ b/tests/test_simpleion.py @@ -15,7 +15,7 @@ from functools import partial from io import BytesIO, StringIO -from decimal import Decimal +from decimal import Decimal, localcontext from itertools import chain from math import isnan @@ -948,6 +948,19 @@ def wrap_annot(content, annot_bytes): return ivm + content +@mark.parametrize('text', ['1e3', '-1e3', '1e-3', '-1e-3', '1.2300', '0.00', '-0.00']) +@mark.parametrize('parse_eagerly', [True, False]) +def test_binary_decimal_preserves_value_outside_context(text, parse_eagerly): + expected = Decimal(text) + data = dumps(expected, imports=[]) + with localcontext() as context: + context.prec = 2 + context.Emax = 2 + context.Emin = -2 + actual = loads(data, catalog=SymbolTableCatalog(), parse_eagerly=parse_eagerly) + assert actual.as_tuple() == expected.as_tuple() + + def test_load_deeply_nested_annotations_binary_raises_ion_exception(): data = _build_nested_annotation_binary(3000) buf = BytesIO(data)