Skip to content

Commit 02eecb6

Browse files
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`
1 parent 831170d commit 02eecb6

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

pyiceberg/expressions/literals.py

+20
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,26 @@ def _(self, type_var: BooleanType) -> Literal[bool]:
603603
else:
604604
raise ValueError(f"Could not convert {self.value} into a {type_var}")
605605

606+
@to.register(FloatType)
607+
def _(self, type_var: FloatType) -> Literal[float]:
608+
try:
609+
number = float(self.value)
610+
if FloatType.max < number:
611+
return FloatAboveMax()
612+
elif FloatType.min > number:
613+
return FloatBelowMin()
614+
return FloatLiteral(number)
615+
except ValueError as e:
616+
raise ValueError(f"Could not convert {self.value} into a {type_var}") from e
617+
618+
@to.register(DoubleType)
619+
def _(self, type_var: DoubleType) -> Literal[float]:
620+
try:
621+
number = float(self.value)
622+
return DoubleLiteral(number)
623+
except ValueError as e:
624+
raise ValueError(f"Could not convert {self.value} into a {type_var}") from e
625+
606626
def __repr__(self) -> str:
607627
"""Return the string representation of the StringLiteral class."""
608628
return f"literal({repr(self.value)})"

tests/expressions/test_literals.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,22 @@ def test_string_to_boolean_literal() -> None:
393393
assert literal("FALSE").to(BooleanType()) == literal(False)
394394

395395

396+
def test_string_to_float_literal() -> None:
397+
assert literal("3.141").to(FloatType()) == literal(3.141).to(FloatType())
398+
399+
400+
def test_string_to_float_outside_bound() -> None:
401+
big_lit_str = literal(str(FloatType.max + 1.0e37))
402+
assert big_lit_str.to(FloatType()) == FloatAboveMax()
403+
404+
small_lit_str = literal(str(FloatType.min - 1.0e37))
405+
assert small_lit_str.to(FloatType()) == FloatBelowMin()
406+
407+
408+
def test_string_to_double_literal() -> None:
409+
assert literal("3.141").to(DoubleType()) == literal(3.141)
410+
411+
396412
@pytest.mark.parametrize(
397413
"val",
398414
["unknown", "off", "on", "0", "1", "y", "yes", "n", "no", "t", "f"],
@@ -744,7 +760,7 @@ def test_invalid_decimal_conversions() -> None:
744760
def test_invalid_string_conversions() -> None:
745761
assert_invalid_conversions(
746762
literal("abc"),
747-
[FloatType(), DoubleType(), FixedType(1), BinaryType()],
763+
[FixedType(1), BinaryType()],
748764
)
749765

750766

0 commit comments

Comments
 (0)