diff --git a/pyiceberg/conversions.py b/pyiceberg/conversions.py index 268cbb93ec..5b7cab560d 100644 --- a/pyiceberg/conversions.py +++ b/pyiceberg/conversions.py @@ -310,9 +310,11 @@ def _(primitive_type: DecimalType, value: Decimal) -> bytes: bytes: The byte representation of `value`. """ _, digits, exponent = value.as_tuple() - exponent = abs(int(exponent)) - if exponent != primitive_type.scale: - raise ValueError(f"Cannot serialize value, scale of value does not match type {primitive_type}: {exponent}") + # A Decimal carries the negated scale as its exponent, so a value with a negative + # scale (1E+2) must not be read as if it had the matching positive one + value_scale = -int(exponent) + if value_scale != primitive_type.scale: + raise ValueError(f"Cannot serialize value, scale of value does not match type {primitive_type}: {value_scale}") elif len(digits) > primitive_type.precision: raise ValueError( f"Cannot serialize value, precision of value is greater than precision of type {primitive_type}: {len(digits)}" diff --git a/tests/test_conversions.py b/tests/test_conversions.py index 9b73b2db8c..57e7f9f618 100644 --- a/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -510,6 +510,13 @@ def __repr__(self) -> str: "primitive_type, value, expected_error_message", [ (DecimalType(7, 3), Decimal("123.4567"), "Cannot serialize value, scale of value does not match type decimal(7, 3): 4"), + # A Decimal with a negative scale must not pass as its positive counterpart + (DecimalType(10, 2), Decimal("1E+2"), "Cannot serialize value, scale of value does not match type decimal(10, 2): -2"), + ( + DecimalType(10, 2), + Decimal("100").normalize(), + "Cannot serialize value, scale of value does not match type decimal(10, 2): -2", + ), ( DecimalType(18, 8), Decimal("123456789.123456789"),