diff --git a/sdk/python/feast/utils.py b/sdk/python/feast/utils.py index 4f8d18ad080..44d0cae7122 100644 --- a/sdk/python/feast/utils.py +++ b/sdk/python/feast/utils.py @@ -431,6 +431,8 @@ def _convert_arrow_fv_to_proto( ) -> List[Tuple[EntityKeyProto, Dict[str, ValueProto], datetime, Optional[datetime]]]: # Avoid ChunkedArrays which guarantees `zero_copy_only` available. if isinstance(table, pyarrow.Table): + if table.num_rows == 0: + return [] table = table.to_batches()[0] if feature_view.batch_source is None: @@ -489,6 +491,8 @@ def _convert_arrow_odfv_to_proto( ) -> List[Tuple[EntityKeyProto, Dict[str, ValueProto], datetime, Optional[datetime]]]: # Avoid ChunkedArrays which guarantees `zero_copy_only` available. if isinstance(table, pyarrow.Table): + if table.num_rows == 0: + return [] table = table.to_batches()[0] columns = [ diff --git a/sdk/python/tests/unit/test_utils.py b/sdk/python/tests/unit/test_utils.py index 7c83eb6ec8a..2c9a1d4e7d7 100644 --- a/sdk/python/tests/unit/test_utils.py +++ b/sdk/python/tests/unit/test_utils.py @@ -9,12 +9,18 @@ from datetime import datetime, timezone from unittest.mock import MagicMock +import pyarrow as pa + from feast.protos.feast.serving.ServingService_pb2 import ( FieldStatus, GetOnlineFeaturesResponse, ) from feast.protos.feast.types.Value_pb2 import Value as ValueProto -from feast.utils import _populate_response_from_feature_data +from feast.utils import ( + _convert_arrow_fv_to_proto, + _convert_arrow_odfv_to_proto, + _populate_response_from_feature_data, +) def _make_table(name="test_fv"): @@ -26,6 +32,14 @@ def _make_table(name="test_fv"): return table +def test_convert_empty_arrow_table_to_proto_returns_no_rows(): + """A zero-row Arrow Table has no record batches and is a valid empty write.""" + table = pa.table({"unused": pa.array([], type=pa.string())}) + + assert _convert_arrow_fv_to_proto(table, MagicMock(), {}) == [] + assert _convert_arrow_odfv_to_proto(table, MagicMock(), {}) == [] + + class TestPopulateResponseFromFeatureData: """Tests for _populate_response_from_feature_data function."""