From d5c45117402961a80cc01414b1633fbf2f7b8670 Mon Sep 17 00:00:00 2001 From: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> Date: Sun, 15 Nov 2026 06:21:29 +0200 Subject: [PATCH 1/6] fix(expressions): reject fractional strings converting to int/long Signed-off-by: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> --- pyiceberg/expressions/literals.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyiceberg/expressions/literals.py b/pyiceberg/expressions/literals.py index b502b43539..65569fc6f0 100644 --- a/pyiceberg/expressions/literals.py +++ b/pyiceberg/expressions/literals.py @@ -595,7 +595,7 @@ def _(self, type_var: IntegerType) -> Literal[int]: return IntAboveMax() elif IntegerType.min > number: return IntBelowMin() - return LongLiteral(int(number)) + return LongLiteral(_to_integral(number, type_var)) except (ArithmeticError, OverflowError, ValueError) as e: raise ValueError(f"Could not convert {self.value} into a {type_var}") from e @@ -608,7 +608,7 @@ def _(self, type_var: LongType) -> Literal[int]: elif LongType.min > long_value: return LongBelowMin() else: - return LongLiteral(int(long_value)) + return LongLiteral(_to_integral(long_value, type_var)) except (ArithmeticError, OverflowError, TypeError, ValueError) as e: raise ValueError(f"Could not convert {self.value} into a {type_var}") from e From 9d9398206c66c7be8f1db4e6b628f521c4956696 Mon Sep 17 00:00:00 2001 From: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> Date: Sun, 15 Nov 2026 06:34:54 +0200 Subject: [PATCH 2/6] test(expressions): expect ValueError for fractional strings to int/long Signed-off-by: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> --- tests/expressions/test_literals.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/expressions/test_literals.py b/tests/expressions/test_literals.py index 9c4252e57d..e7fe754adc 100644 --- a/tests/expressions/test_literals.py +++ b/tests/expressions/test_literals.py @@ -325,9 +325,7 @@ def test_string_literal() -> None: pi_string_lit = StringLiteral("3.141") pi_double_lit = literal(3.141).to(DoubleType()) - assert literal("3.141").to(IntegerType()) == literal(3) - assert literal("3.141").to(LongType()) == literal(3) - + assert sqrt2 != pi assert pi != pi_double_lit assert pi == pi_string_lit @@ -946,7 +944,15 @@ def test_fractional_decimal_to_integral_type_raises() -> None: _ = DecimalLiteral(Decimal(value)).to(target_type) -def test_integral_decimal_to_integral_type() -> None: +def test_fractional_string_to_integral_type_raises() -> None: + # Rounding would change the predicate, e.g. x < "2.6" would become x < 2 and drop x = 2 + for target_type in [IntegerType(), LongType()]: + for value in ["2.5", "2.6", "-2.5", "0.1"]: + with pytest.raises(ValueError, match=f"Could not convert {value} into a {target_type}"): + _ = literal(value).to(target_type) + + + def test_integral_decimal_to_integral_type() -> None: # A decimal literal without a fractional part, such as 2.0, still converts exactly for target_type in [IntegerType(), LongType()]: for value in ["2", "2.0", "2.00", "-2.0"]: From 316f3b63a082b0593c7c935ce8de94623d3357e9 Mon Sep 17 00:00:00 2001 From: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> Date: Sun, 15 Nov 2026 06:40:47 +0200 Subject: [PATCH 3/6] style: remove stray blank line in test_string_literal Signed-off-by: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> --- tests/expressions/test_literals.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/expressions/test_literals.py b/tests/expressions/test_literals.py index e7fe754adc..dfd6b6fd3e 100644 --- a/tests/expressions/test_literals.py +++ b/tests/expressions/test_literals.py @@ -323,10 +323,9 @@ def test_string_literal() -> None: sqrt2 = literal("1.414").to(StringType()) pi = literal("3.141").to(StringType()) pi_string_lit = StringLiteral("3.141") - pi_double_lit = literal(3.141).to(DoubleType()) + pi_double_lit = literal(3.141).to(DoubleType( - - assert sqrt2 != pi + assert sqrt2 != pi assert pi != pi_double_lit assert pi == pi_string_lit assert pi == pi From d3c23304897a8de0debc240383a0574b8f4021e1 Mon Sep 17 00:00:00 2001 From: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> Date: Sun, 15 Nov 2026 06:43:59 +0200 Subject: [PATCH 4/6] fix: restore closing parentheses on pi_double_lit Signed-off-by: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> --- tests/expressions/test_literals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/expressions/test_literals.py b/tests/expressions/test_literals.py index dfd6b6fd3e..6fbe6bf5f5 100644 --- a/tests/expressions/test_literals.py +++ b/tests/expressions/test_literals.py @@ -323,7 +323,7 @@ def test_string_literal() -> None: sqrt2 = literal("1.414").to(StringType()) pi = literal("3.141").to(StringType()) pi_string_lit = StringLiteral("3.141") - pi_double_lit = literal(3.141).to(DoubleType( + pi_double_lit = literal(3.141).to(DoubleType()) assert sqrt2 != pi assert pi != pi_double_lit From f1a439fce42b0e9864687c54aafc81205cb59c72 Mon Sep 17 00:00:00 2001 From: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> Date: Sun, 15 Nov 2026 06:49:30 +0200 Subject: [PATCH 5/6] fix: correct indentation of sqrt2 assert in test_string_literal Signed-off-by: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> --- tests/expressions/test_literals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/expressions/test_literals.py b/tests/expressions/test_literals.py index 6fbe6bf5f5..3de0e1b63a 100644 --- a/tests/expressions/test_literals.py +++ b/tests/expressions/test_literals.py @@ -325,7 +325,7 @@ def test_string_literal() -> None: pi_string_lit = StringLiteral("3.141") pi_double_lit = literal(3.141).to(DoubleType()) - assert sqrt2 != pi + assert sqrt2 != pi assert pi != pi_double_lit assert pi == pi_string_lit assert pi == pi From 66057bd3dfd56ec4a7d88aa06c447b5d7a89f012 Mon Sep 17 00:00:00 2001 From: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> Date: Sun, 15 Nov 2026 06:54:23 +0200 Subject: [PATCH 6/6] fix: dedent test_integral_decimal_to_integral_type to top level Signed-off-by: Shahzeb Ali <126076773+Shahzeb-DataEngineer@users.noreply.github.com> --- tests/expressions/test_literals.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/expressions/test_literals.py b/tests/expressions/test_literals.py index 3de0e1b63a..506dc69d89 100644 --- a/tests/expressions/test_literals.py +++ b/tests/expressions/test_literals.py @@ -949,9 +949,9 @@ def test_fractional_string_to_integral_type_raises() -> None: for value in ["2.5", "2.6", "-2.5", "0.1"]: with pytest.raises(ValueError, match=f"Could not convert {value} into a {target_type}"): _ = literal(value).to(target_type) - - - def test_integral_decimal_to_integral_type() -> None: + + +def test_integral_decimal_to_integral_type() -> None: # A decimal literal without a fractional part, such as 2.0, still converts exactly for target_type in [IntegerType(), LongType()]: for value in ["2", "2.0", "2.00", "-2.0"]: