You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by fo...@apache.org on 2025/04/18 10:17:46 UTC

(iceberg-python) branch main updated: Add cast from string to float and double (#1933)

This is an automated email from the ASF dual-hosted git repository.

fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git


The following commit(s) were added to refs/heads/main by this push:
     new 02eecb6c Add cast from string to float and double (#1933)
02eecb6c is described below

commit 02eecb6cc9b9bf14b64c13f651ec7cd8631440c0
Author: Akashdeep Gupta <gu...@users.noreply.github.com>
AuthorDate: Fri Apr 18 15:47:41 2025 +0530

    Add cast from string to float and double (#1933)
    
    Closes #1919
    
    # Rationale for this change
    This is an additional good to have feature where users can convert valid
    Float and Double strings to Iceberg FloatType and Double Literal.
    
    # Are these changes tested?
    Yes. I have also added tests for the same.
    
    # Are there any user-facing changes?
    Yes. Users can cast valid float and double strings to `FloatType` and
    `DecimalType`
---
 pyiceberg/expressions/literals.py  | 20 ++++++++++++++++++++
 tests/expressions/test_literals.py | 18 +++++++++++++++++-
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/pyiceberg/expressions/literals.py b/pyiceberg/expressions/literals.py
index b29d0d9e..e52ed5e0 100644
--- a/pyiceberg/expressions/literals.py
+++ b/pyiceberg/expressions/literals.py
@@ -603,6 +603,26 @@ class StringLiteral(Literal[str]):
         else:
             raise ValueError(f"Could not convert {self.value} into a {type_var}")
 
+    @to.register(FloatType)
+    def _(self, type_var: FloatType) -> Literal[float]:
+        try:
+            number = float(self.value)
+            if FloatType.max < number:
+                return FloatAboveMax()
+            elif FloatType.min > number:
+                return FloatBelowMin()
+            return FloatLiteral(number)
+        except ValueError as e:
+            raise ValueError(f"Could not convert {self.value} into a {type_var}") from e
+
+    @to.register(DoubleType)
+    def _(self, type_var: DoubleType) -> Literal[float]:
+        try:
+            number = float(self.value)
+            return DoubleLiteral(number)
+        except ValueError as e:
+            raise ValueError(f"Could not convert {self.value} into a {type_var}") from e
+
     def __repr__(self) -> str:
         """Return the string representation of the StringLiteral class."""
         return f"literal({repr(self.value)})"
diff --git a/tests/expressions/test_literals.py b/tests/expressions/test_literals.py
index 6144e327..4d8f5557 100644
--- a/tests/expressions/test_literals.py
+++ b/tests/expressions/test_literals.py
@@ -393,6 +393,22 @@ def test_string_to_boolean_literal() -> None:
     assert literal("FALSE").to(BooleanType()) == literal(False)
 
 
+def test_string_to_float_literal() -> None:
+    assert literal("3.141").to(FloatType()) == literal(3.141).to(FloatType())
+
+
+def test_string_to_float_outside_bound() -> None:
+    big_lit_str = literal(str(FloatType.max + 1.0e37))
+    assert big_lit_str.to(FloatType()) == FloatAboveMax()
+
+    small_lit_str = literal(str(FloatType.min - 1.0e37))
+    assert small_lit_str.to(FloatType()) == FloatBelowMin()
+
+
+def test_string_to_double_literal() -> None:
+    assert literal("3.141").to(DoubleType()) == literal(3.141)
+
+
 @pytest.mark.parametrize(
     "val",
     ["unknown", "off", "on", "0", "1", "y", "yes", "n", "no", "t", "f"],
@@ -744,7 +760,7 @@ def test_invalid_decimal_conversions() -> None:
 def test_invalid_string_conversions() -> None:
     assert_invalid_conversions(
         literal("abc"),
-        [FloatType(), DoubleType(), FixedType(1), BinaryType()],
+        [FixedType(1), BinaryType()],
     )