Skip to content

Commit 7e0b46a

Browse files
feat: add support of float32 type (#1113)
* feat: add support of float32 type * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * incorporate changes * incorporate changes * handle case for infinity * fix build * fix tests --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent a92c6d3 commit 7e0b46a

File tree

7 files changed

+82
-11
lines changed

7 files changed

+82
-11
lines changed

google/cloud/spanner_v1/_helpers.py

+5
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ def _parse_value_pb(value_pb, field_type):
228228
return float(value_pb.string_value)
229229
else:
230230
return value_pb.number_value
231+
elif type_code == TypeCode.FLOAT32:
232+
if value_pb.HasField("string_value"):
233+
return float(value_pb.string_value)
234+
else:
235+
return value_pb.number_value
231236
elif type_code == TypeCode.DATE:
232237
return _date_from_iso8601_date(value_pb.string_value)
233238
elif type_code == TypeCode.TIMESTAMP:

google/cloud/spanner_v1/param_types.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
BOOL = Type(code=TypeCode.BOOL)
2727
INT64 = Type(code=TypeCode.INT64)
2828
FLOAT64 = Type(code=TypeCode.FLOAT64)
29+
FLOAT32 = Type(code=TypeCode.FLOAT32)
2930
DATE = Type(code=TypeCode.DATE)
3031
TIMESTAMP = Type(code=TypeCode.TIMESTAMP)
3132
NUMERIC = Type(code=TypeCode.NUMERIC)

google/cloud/spanner_v1/streamed.py

+1
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ def _merge_struct(lhs, rhs, type_):
332332
TypeCode.BYTES: _merge_string,
333333
TypeCode.DATE: _merge_string,
334334
TypeCode.FLOAT64: _merge_float64,
335+
TypeCode.FLOAT32: _merge_float64,
335336
TypeCode.INT64: _merge_string,
336337
TypeCode.STRING: _merge_string,
337338
TypeCode.STRUCT: _merge_struct,

tests/system/_sample_data.py

+3
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,8 @@ def _check_cell_data(found_cell, expected_cell, recurse_into_lists=True):
9090
for found_item, expected_item in zip(found_cell, expected_cell):
9191
_check_cell_data(found_item, expected_item)
9292

93+
elif isinstance(found_cell, float) and not math.isinf(found_cell):
94+
assert abs(found_cell - expected_cell) < 0.00001
95+
9396
else:
9497
assert found_cell == expected_cell

tests/system/test_session_api.py

+41
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,47 @@ def test_execute_sql_w_float_bindings_transfinite(sessions_database, database_di
22162216
)
22172217

22182218

2219+
def test_execute_sql_w_float32_bindings(sessions_database, database_dialect):
2220+
pytest.skip("float32 is not yet supported in production.")
2221+
_bind_test_helper(
2222+
sessions_database,
2223+
database_dialect,
2224+
spanner_v1.param_types.FLOAT32,
2225+
42.3,
2226+
[12.3, 456.0, 7.89],
2227+
)
2228+
2229+
2230+
def test_execute_sql_w_float32_bindings_transfinite(
2231+
sessions_database, database_dialect
2232+
):
2233+
pytest.skip("float32 is not yet supported in production.")
2234+
key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "neg_inf"
2235+
placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}"
2236+
2237+
# Find -inf
2238+
_check_sql_results(
2239+
sessions_database,
2240+
sql=f"SELECT {placeholder}",
2241+
params={key: NEG_INF},
2242+
param_types={key: spanner_v1.param_types.FLOAT32},
2243+
expected=[(NEG_INF,)],
2244+
order=False,
2245+
)
2246+
2247+
key = "p1" if database_dialect == DatabaseDialect.POSTGRESQL else "pos_inf"
2248+
placeholder = "$1" if database_dialect == DatabaseDialect.POSTGRESQL else f"@{key}"
2249+
# Find +inf
2250+
_check_sql_results(
2251+
sessions_database,
2252+
sql=f"SELECT {placeholder}",
2253+
params={key: POS_INF},
2254+
param_types={key: spanner_v1.param_types.FLOAT32},
2255+
expected=[(POS_INF,)],
2256+
order=False,
2257+
)
2258+
2259+
22192260
def test_execute_sql_w_bytes_bindings(sessions_database, database_dialect):
22202261
_bind_test_helper(
22212262
sessions_database,

tests/unit/test__helpers.py

+21
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,27 @@ def test_w_float_str(self):
466466

467467
self.assertEqual(self._callFUT(value_pb, field_type), expected_value)
468468

469+
def test_w_float32(self):
470+
from google.cloud.spanner_v1 import Type, TypeCode
471+
from google.protobuf.struct_pb2 import Value
472+
473+
VALUE = 3.14159
474+
field_type = Type(code=TypeCode.FLOAT32)
475+
value_pb = Value(number_value=VALUE)
476+
477+
self.assertEqual(self._callFUT(value_pb, field_type), VALUE)
478+
479+
def test_w_float32_str(self):
480+
from google.cloud.spanner_v1 import Type, TypeCode
481+
from google.protobuf.struct_pb2 import Value
482+
483+
VALUE = "3.14159"
484+
field_type = Type(code=TypeCode.FLOAT32)
485+
value_pb = Value(string_value=VALUE)
486+
expected_value = 3.14159
487+
488+
self.assertEqual(self._callFUT(value_pb, field_type), expected_value)
489+
469490
def test_w_date(self):
470491
import datetime
471492
from google.protobuf.struct_pb2 import Value

tests/unit/test_param_types.py

+10-11
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818

1919
class Test_ArrayParamType(unittest.TestCase):
2020
def test_it(self):
21-
from google.cloud.spanner_v1 import Type
22-
from google.cloud.spanner_v1 import TypeCode
23-
from google.cloud.spanner_v1 import param_types
21+
from google.cloud.spanner_v1 import Type, TypeCode, param_types
2422

2523
expected = Type(
2624
code=TypeCode.ARRAY, array_element_type=Type(code=TypeCode.INT64)
@@ -33,15 +31,13 @@ def test_it(self):
3331

3432
class Test_Struct(unittest.TestCase):
3533
def test_it(self):
36-
from google.cloud.spanner_v1 import Type
37-
from google.cloud.spanner_v1 import TypeCode
38-
from google.cloud.spanner_v1 import StructType
39-
from google.cloud.spanner_v1 import param_types
34+
from google.cloud.spanner_v1 import StructType, Type, TypeCode, param_types
4035

4136
struct_type = StructType(
4237
fields=[
4338
StructType.Field(name="name", type_=Type(code=TypeCode.STRING)),
4439
StructType.Field(name="count", type_=Type(code=TypeCode.INT64)),
40+
StructType.Field(name="float32", type_=Type(code=TypeCode.FLOAT32)),
4541
]
4642
)
4743
expected = Type(code=TypeCode.STRUCT, struct_type=struct_type)
@@ -50,6 +46,7 @@ def test_it(self):
5046
[
5147
param_types.StructField("name", param_types.STRING),
5248
param_types.StructField("count", param_types.INT64),
49+
param_types.StructField("float32", param_types.FLOAT32),
5350
]
5451
)
5552

@@ -58,10 +55,12 @@ def test_it(self):
5855

5956
class Test_JsonbParamType(unittest.TestCase):
6057
def test_it(self):
61-
from google.cloud.spanner_v1 import Type
62-
from google.cloud.spanner_v1 import TypeCode
63-
from google.cloud.spanner_v1 import TypeAnnotationCode
64-
from google.cloud.spanner_v1 import param_types
58+
from google.cloud.spanner_v1 import (
59+
Type,
60+
TypeAnnotationCode,
61+
TypeCode,
62+
param_types,
63+
)
6564

6665
expected = Type(
6766
code=TypeCode.JSON,

0 commit comments

Comments
 (0)