Skip to content

Commit

Permalink
SNOW-1331032 Add function python_value_str_to_object (#1954)
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-aalam authored Jul 26, 2024
1 parent dbb5ded commit c3d30cd
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/snowflake/snowpark/_internal/type_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
Variant,
VariantType,
VectorType,
_FractionalType,
_IntegralType,
_NumericType,
)

Expand Down Expand Up @@ -525,6 +527,52 @@ def merge_type(a: DataType, b: DataType, name: Optional[str] = None) -> DataType
return a


def python_value_str_to_object(value, tp: DataType) -> Any:
if isinstance(tp, StringType):
return value

if isinstance(
tp,
(
_IntegralType,
_FractionalType,
BooleanType,
BinaryType,
TimeType,
DateType,
TimestampType,
),
):
return eval(value)

if isinstance(tp, ArrayType):
curr_list = eval(value)
if curr_list is None:
return None
element_tp = tp.element_type or StringType()
return [python_value_str_to_object(val, element_tp) for val in curr_list]

if isinstance(tp, MapType):
curr_dict: dict = eval(value)
if curr_dict is None:
return None
key_tp = tp.key_type or StringType()
val_tp = tp.value_type or StringType()
return {
python_value_str_to_object(k, key_tp): python_value_str_to_object(v, val_tp)
for k, v in curr_dict.items()
}

if isinstance(tp, (GeometryType, GeographyType, VariantType)):
if value.strip() == "None":
return None
return value

raise TypeError(
f"Unsupported data type: {tp}, value {value} by python_value_str_to_object()"
)


def python_type_str_to_object(
tp_str: str, is_return_type_for_sproc: bool = False
) -> Type:
Expand Down
81 changes: 81 additions & 0 deletions tests/unit/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved.
#

import decimal
import os
import sys
import typing
Expand Down Expand Up @@ -38,6 +39,7 @@
infer_type,
merge_type,
python_type_to_snow_type,
python_value_str_to_object,
retrieve_func_type_hints_from_source,
snow_type_to_dtype_str,
)
Expand Down Expand Up @@ -584,6 +586,85 @@ def test_decimal_regular_expression(decimal_word):
assert get_number_precision_scale(f" {decimal_word} ( 2 , 1 ) ") == (2, 1)


@pytest.mark.parametrize(
"value_str,datatype,expected_value",
[
("1", IntegerType(), 1),
("True", BooleanType(), True),
("1.0", FloatType(), 1.0),
("decimal.Decimal('3.14')", DecimalType(), decimal.Decimal("3.14")),
("decimal.Decimal(1.0)", DecimalType(), decimal.Decimal(1.0)),
("one", StringType(), "one"),
(None, StringType(), None),
("None", StringType(), "None"),
("POINT(-122.35 37.55)", GeographyType(), "POINT(-122.35 37.55)"),
("POINT(-122.35 37.55)", GeometryType(), "POINT(-122.35 37.55)"),
('{"key": "val"}', VariantType(), '{"key": "val"}'),
("b'one'", BinaryType(), b"one"),
("bytearray('one', 'utf-8')", BinaryType(), bytearray("one", "utf-8")),
("datetime.date(2024, 4, 1)", DateType(), date(2024, 4, 1)),
(
"datetime.time(12, 0, second=20, tzinfo=datetime.timezone.utc)",
TimeType(),
time(12, 0, second=20, tzinfo=timezone.utc),
),
(
"datetime.datetime(2024, 4, 1, 12, 0, 20)",
TimestampType(),
datetime(2024, 4, 1, 12, 0, 20),
),
("['1', '2', '3']", ArrayType(IntegerType()), [1, 2, 3]),
("['a', 'b', 'c']", ArrayType(StringType()), ["a", "b", "c"]),
("['a', 'b', 'c']", ArrayType(), ["a", "b", "c"]),
(
"[\"['1', '2', '3']\", \"['4', '5', '6']\"]",
ArrayType(ArrayType(IntegerType())),
[[1, 2, 3], [4, 5, 6]],
),
("{'1': 'a'}", MapType(), {"1": "a"}),
("{'1': 'a'}", MapType(IntegerType(), StringType()), {1: "a"}),
(
"{'1': \"['a', 'b']\"}",
MapType(IntegerType(), ArrayType(StringType())),
{1: ["a", "b"]},
),
],
)
def test_python_value_str_to_object(value_str, datatype, expected_value):
assert python_value_str_to_object(value_str, datatype) == expected_value


@pytest.mark.parametrize(
"datatype",
[
IntegerType(),
BooleanType(),
FloatType(),
DecimalType(),
BinaryType(),
DateType(),
TimeType(),
TimestampType(),
ArrayType(),
MapType(),
VariantType(),
GeographyType(),
GeometryType(),
],
)
def test_python_value_str_to_object_for_none(datatype):
"StringType() is excluded here and tested in test_python_value_str_to_object"
assert python_value_str_to_object("None", datatype) is None


def test_python_value_str_to_object_negative():
with pytest.raises(
TypeError,
match="Unsupported data type: invalid type, value thanksgiving by python_value_str_to_object()",
):
python_value_str_to_object("thanksgiving", "invalid type")


def test_retrieve_func_type_hints_from_source():
func_name = "foo"

Expand Down

0 comments on commit c3d30cd

Please sign in to comment.