From 903996367ac4b063f978780d1e3e080189cf9816 Mon Sep 17 00:00:00 2001 From: rahul yadav Date: Fri, 8 Mar 2024 20:39:32 +0530 Subject: [PATCH 1/7] feat: add support of float32 type --- google/cloud/spanner_v1/_helpers.py | 5 +++++ google/cloud/spanner_v1/param_types.py | 1 + tests/unit/test__helpers.py | 21 +++++++++++++++++++++ tests/unit/test_param_types.py | 18 +++++++----------- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/google/cloud/spanner_v1/_helpers.py b/google/cloud/spanner_v1/_helpers.py index e0e2bfdbd0..d6b10dba18 100644 --- a/google/cloud/spanner_v1/_helpers.py +++ b/google/cloud/spanner_v1/_helpers.py @@ -228,6 +228,11 @@ def _parse_value_pb(value_pb, field_type): return float(value_pb.string_value) else: return value_pb.number_value + elif type_code == TypeCode.FLOAT32: + if value_pb.HasField("string_value"): + return float(value_pb.string_value) + else: + return value_pb.number_value elif type_code == TypeCode.DATE: return _date_from_iso8601_date(value_pb.string_value) elif type_code == TypeCode.TIMESTAMP: diff --git a/google/cloud/spanner_v1/param_types.py b/google/cloud/spanner_v1/param_types.py index 0c03f7ecc6..6bceac1ab5 100644 --- a/google/cloud/spanner_v1/param_types.py +++ b/google/cloud/spanner_v1/param_types.py @@ -26,6 +26,7 @@ BOOL = Type(code=TypeCode.BOOL) INT64 = Type(code=TypeCode.INT64) FLOAT64 = Type(code=TypeCode.FLOAT64) +Float32 = Type(code=TypeCode.FLOAT32) DATE = Type(code=TypeCode.DATE) TIMESTAMP = Type(code=TypeCode.TIMESTAMP) NUMERIC = Type(code=TypeCode.NUMERIC) diff --git a/tests/unit/test__helpers.py b/tests/unit/test__helpers.py index 0e0ec903a2..cb2372406f 100644 --- a/tests/unit/test__helpers.py +++ b/tests/unit/test__helpers.py @@ -466,6 +466,27 @@ def test_w_float_str(self): self.assertEqual(self._callFUT(value_pb, field_type), expected_value) + def test_w_float32(self): + from google.cloud.spanner_v1 import Type, TypeCode + from google.protobuf.struct_pb2 import Value + + VALUE = 3.14159 + field_type = Type(code=TypeCode.FLOAT32) + value_pb = Value(number_value=VALUE) + + self.assertEqual(self._callFUT(value_pb, field_type), VALUE) + + def test_w_float32_str(self): + from google.cloud.spanner_v1 import Type, TypeCode + from google.protobuf.struct_pb2 import Value + + VALUE = "3.14159" + field_type = Type(code=TypeCode.FLOAT32) + value_pb = Value(string_value=VALUE) + expected_value = 3.14159 + + self.assertEqual(self._callFUT(value_pb, field_type), expected_value) + def test_w_date(self): import datetime from google.protobuf.struct_pb2 import Value diff --git a/tests/unit/test_param_types.py b/tests/unit/test_param_types.py index 02f41c1f25..b78c9361c4 100644 --- a/tests/unit/test_param_types.py +++ b/tests/unit/test_param_types.py @@ -18,9 +18,7 @@ class Test_ArrayParamType(unittest.TestCase): def test_it(self): - from google.cloud.spanner_v1 import Type - from google.cloud.spanner_v1 import TypeCode - from google.cloud.spanner_v1 import param_types + from google.cloud.spanner_v1 import Type, TypeCode, param_types expected = Type( code=TypeCode.ARRAY, array_element_type=Type(code=TypeCode.INT64) @@ -33,15 +31,14 @@ def test_it(self): class Test_Struct(unittest.TestCase): def test_it(self): - from google.cloud.spanner_v1 import Type - from google.cloud.spanner_v1 import TypeCode - from google.cloud.spanner_v1 import StructType - from google.cloud.spanner_v1 import param_types + from google.cloud.spanner_v1 import (StructType, Type, TypeCode, + param_types) struct_type = StructType( fields=[ StructType.Field(name="name", type_=Type(code=TypeCode.STRING)), StructType.Field(name="count", type_=Type(code=TypeCode.INT64)), + StructType.Field(name="float32", type_=Type(code=TypeCode.FLOAT32)), ] ) expected = Type(code=TypeCode.STRUCT, struct_type=struct_type) @@ -50,6 +47,7 @@ def test_it(self): [ param_types.StructField("name", param_types.STRING), param_types.StructField("count", param_types.INT64), + param_types.StructField("float32", param_types.Float32), ] ) @@ -58,10 +56,8 @@ def test_it(self): class Test_JsonbParamType(unittest.TestCase): def test_it(self): - from google.cloud.spanner_v1 import Type - from google.cloud.spanner_v1 import TypeCode - from google.cloud.spanner_v1 import TypeAnnotationCode - from google.cloud.spanner_v1 import param_types + from google.cloud.spanner_v1 import (Type, TypeAnnotationCode, + TypeCode, param_types) expected = Type( code=TypeCode.JSON, From 7bbb15a47628586ec2a7b769b35872e54e8c3dc7 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Fri, 8 Mar 2024 15:13:10 +0000 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- tests/unit/test_param_types.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_param_types.py b/tests/unit/test_param_types.py index b78c9361c4..009649e27c 100644 --- a/tests/unit/test_param_types.py +++ b/tests/unit/test_param_types.py @@ -31,8 +31,7 @@ def test_it(self): class Test_Struct(unittest.TestCase): def test_it(self): - from google.cloud.spanner_v1 import (StructType, Type, TypeCode, - param_types) + from google.cloud.spanner_v1 import StructType, Type, TypeCode, param_types struct_type = StructType( fields=[ @@ -56,8 +55,12 @@ def test_it(self): class Test_JsonbParamType(unittest.TestCase): def test_it(self): - from google.cloud.spanner_v1 import (Type, TypeAnnotationCode, - TypeCode, param_types) + from google.cloud.spanner_v1 import ( + Type, + TypeAnnotationCode, + TypeCode, + param_types, + ) expected = Type( code=TypeCode.JSON, From 67e2e2cd31f44a0e5364dbf076faa2383d0ddcb5 Mon Sep 17 00:00:00 2001 From: rahul yadav Date: Mon, 11 Mar 2024 09:59:24 +0530 Subject: [PATCH 3/7] incorporate changes --- google/cloud/spanner_v1/param_types.py | 2 +- tests/unit/test_param_types.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google/cloud/spanner_v1/param_types.py b/google/cloud/spanner_v1/param_types.py index 6bceac1ab5..9b1910244d 100644 --- a/google/cloud/spanner_v1/param_types.py +++ b/google/cloud/spanner_v1/param_types.py @@ -26,7 +26,7 @@ BOOL = Type(code=TypeCode.BOOL) INT64 = Type(code=TypeCode.INT64) FLOAT64 = Type(code=TypeCode.FLOAT64) -Float32 = Type(code=TypeCode.FLOAT32) +FLOAT32 = Type(code=TypeCode.FLOAT32) DATE = Type(code=TypeCode.DATE) TIMESTAMP = Type(code=TypeCode.TIMESTAMP) NUMERIC = Type(code=TypeCode.NUMERIC) diff --git a/tests/unit/test_param_types.py b/tests/unit/test_param_types.py index 009649e27c..645774d79b 100644 --- a/tests/unit/test_param_types.py +++ b/tests/unit/test_param_types.py @@ -46,7 +46,7 @@ def test_it(self): [ param_types.StructField("name", param_types.STRING), param_types.StructField("count", param_types.INT64), - param_types.StructField("float32", param_types.Float32), + param_types.StructField("float32", param_types.FLOAT32), ] ) From bff3ec299d26205081bc93ef2d9a69514242a09c Mon Sep 17 00:00:00 2001 From: rahul yadav Date: Tue, 12 Mar 2024 12:56:27 +0530 Subject: [PATCH 4/7] incorporate changes --- google/cloud/spanner_v1/streamed.py | 1 + tests/system/_sample_data.py | 3 +++ tests/system/test_session_api.py | 41 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/google/cloud/spanner_v1/streamed.py b/google/cloud/spanner_v1/streamed.py index ac8fc71ce6..d2c2b6216f 100644 --- a/google/cloud/spanner_v1/streamed.py +++ b/google/cloud/spanner_v1/streamed.py @@ -332,6 +332,7 @@ def _merge_struct(lhs, rhs, type_): TypeCode.BYTES: _merge_string, TypeCode.DATE: _merge_string, TypeCode.FLOAT64: _merge_float64, + TypeCode.FLOAT32: _merge_float64, TypeCode.INT64: _merge_string, TypeCode.STRING: _merge_string, TypeCode.STRUCT: _merge_struct, diff --git a/tests/system/_sample_data.py b/tests/system/_sample_data.py index 9c83f42224..4b8aa8c2a6 100644 --- a/tests/system/_sample_data.py +++ b/tests/system/_sample_data.py @@ -90,5 +90,8 @@ def _check_cell_data(found_cell, expected_cell, recurse_into_lists=True): for found_item, expected_item in zip(found_cell, expected_cell): _check_cell_data(found_item, expected_item) + elif isinstance(found_cell, float): + assert abs(found_cell - expected_cell) < 0.00001 + else: assert found_cell == expected_cell diff --git a/tests/system/test_session_api.py b/tests/system/test_session_api.py index 29d196b011..db0952b612 100644 --- a/tests/system/test_session_api.py +++ b/tests/system/test_session_api.py @@ -2216,6 +2216,47 @@ def test_execute_sql_w_float_bindings_transfinite(sessions_database, database_di ) +def test_execute_sql_w_float32_bindings(sessions_database, database_dialect): + pytest.skip(f"float32 is not yet supported in production.") + _bind_test_helper( + sessions_database, + database_dialect, + spanner_v1.param_types.FLOAT32, + 42.3, + [12.3, 456.0, 7.89], + ) + + +def test_execute_sql_w_float32_bindings_transfinite( + sessions_database, database_dialect +): + pytest.skip(f"float32 is not yet supported in production.") + key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "neg_inf" + placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}" + + # Find -inf + _check_sql_results( + sessions_database, + sql=f"SELECT {placeholder}", + params={key: NEG_INF}, + param_types={key: spanner_v1.param_types.FLOAT64}, + expected=[(NEG_INF,)], + order=False, + ) + + key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "pos_inf" + placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}" + # Find +inf + _check_sql_results( + sessions_database, + sql=f"SELECT {placeholder}", + params={key: POS_INF}, + param_types={key: spanner_v1.param_types.FLOAT64}, + expected=[(POS_INF,)], + order=False, + ) + + def test_execute_sql_w_bytes_bindings(sessions_database, database_dialect): _bind_test_helper( sessions_database, From fa2aab61b92d34501cadc9f111fba89bcc4554b1 Mon Sep 17 00:00:00 2001 From: rahul yadav Date: Tue, 12 Mar 2024 13:01:06 +0530 Subject: [PATCH 5/7] handle case for infinity --- tests/system/_sample_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/_sample_data.py b/tests/system/_sample_data.py index 4b8aa8c2a6..d9c269c27f 100644 --- a/tests/system/_sample_data.py +++ b/tests/system/_sample_data.py @@ -90,7 +90,7 @@ def _check_cell_data(found_cell, expected_cell, recurse_into_lists=True): for found_item, expected_item in zip(found_cell, expected_cell): _check_cell_data(found_item, expected_item) - elif isinstance(found_cell, float): + elif isinstance(found_cell, float) and not math.isinf(found_cell): assert abs(found_cell - expected_cell) < 0.00001 else: From 243742e809857655e386a8b601e5b164fc7c0d5d Mon Sep 17 00:00:00 2001 From: rahul yadav Date: Tue, 12 Mar 2024 14:02:00 +0530 Subject: [PATCH 6/7] fix build --- tests/system/test_session_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/test_session_api.py b/tests/system/test_session_api.py index db0952b612..68bbd4ccfd 100644 --- a/tests/system/test_session_api.py +++ b/tests/system/test_session_api.py @@ -2217,7 +2217,7 @@ def test_execute_sql_w_float_bindings_transfinite(sessions_database, database_di def test_execute_sql_w_float32_bindings(sessions_database, database_dialect): - pytest.skip(f"float32 is not yet supported in production.") + pytest.skip("float32 is not yet supported in production.") _bind_test_helper( sessions_database, database_dialect, @@ -2230,7 +2230,7 @@ def test_execute_sql_w_float32_bindings(sessions_database, database_dialect): def test_execute_sql_w_float32_bindings_transfinite( sessions_database, database_dialect ): - pytest.skip(f"float32 is not yet supported in production.") + pytest.skip("float32 is not yet supported in production.") key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "neg_inf" placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}" From f65f7ff2085612abd2b465afcf70f9de4dfd4be0 Mon Sep 17 00:00:00 2001 From: rahul yadav Date: Tue, 12 Mar 2024 16:23:06 +0530 Subject: [PATCH 7/7] fix tests --- tests/system/test_session_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/test_session_api.py b/tests/system/test_session_api.py index 68bbd4ccfd..6f1844faa9 100644 --- a/tests/system/test_session_api.py +++ b/tests/system/test_session_api.py @@ -2239,7 +2239,7 @@ def test_execute_sql_w_float32_bindings_transfinite( sessions_database, sql=f"SELECT {placeholder}", params={key: NEG_INF}, - param_types={key: spanner_v1.param_types.FLOAT64}, + param_types={key: spanner_v1.param_types.FLOAT32}, expected=[(NEG_INF,)], order=False, ) @@ -2251,7 +2251,7 @@ def test_execute_sql_w_float32_bindings_transfinite( sessions_database, sql=f"SELECT {placeholder}", params={key: POS_INF}, - param_types={key: spanner_v1.param_types.FLOAT64}, + param_types={key: spanner_v1.param_types.FLOAT32}, expected=[(POS_INF,)], order=False, )