Skip to content

Commit 73fc241

Browse files
committed
test: parametrize to_arrow empty stream tests and update docstrings
1 parent 0a873a3 commit 73fc241

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

packages/google-cloud-bigquery-storage/google/cloud/bigquery_storage_v1/reader.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,13 @@ def __iter__(self):
349349
def to_arrow(self):
350350
"""Create a :class:`pyarrow.Table` of all rows in the stream.
351351
352+
Note: This is the :class:`ReadRowsIterable` version of ``to_arrow``. It is
353+
typically invoked by calling :meth:`ReadRowsStream.to_arrow`, which
354+
delegates here after handling optional session context. The key difference
355+
is that :meth:`ReadRowsStream.to_arrow` accepts a ``read_session`` argument
356+
to provide schema hints for empty streams, whereas this method relies on
357+
the parser initialized during :class:`ReadRowsIterable` construction.
358+
352359
This method requires the pyarrow library and a stream using the Arrow
353360
format.
354361
@@ -365,6 +372,9 @@ def to_arrow(self):
365372

366373
# No data, return an empty Table.
367374
if self._stream_parser is None:
375+
# Note: This returns a table with an empty schema (no columns).
376+
# Downstream consumers (like Vertex Ray) might fail if they expect specific columns.
377+
# To guarantee the correct schema, provide 'read_session' to `ReadRowsStream.to_arrow()`.
368378
return pyarrow.Table.from_batches([], schema=pyarrow.schema([]))
369379

370380
self._stream_parser._parse_arrow_schema()

packages/google-cloud-bigquery-storage/tests/unit/test_reader_v1_arrow.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import importlib_metadata as metadata
2828

2929
import google.api_core.exceptions
30-
3130
from google.cloud.bigquery_storage import types
3231

3332
from .helpers import SCALAR_BLOCKS, SCALAR_COLUMN_NAMES, SCALAR_COLUMNS
@@ -208,6 +207,27 @@ def test_rows_w_empty_stream_arrow(class_under_test, mock_gapic_client):
208207
assert tuple(got) == ()
209208

210209

210+
@pytest.mark.parametrize(
211+
"use_session",
212+
[False, True],
213+
ids=["no_session", "with_session"],
214+
)
215+
def test_to_arrow_empty_stream(class_under_test, mock_gapic_client, use_session):
216+
"""Verify that to_arrow() handles empty streams safely."""
217+
arrow_schema = _bq_to_arrow_schema(SCALAR_COLUMNS)
218+
mock_gapic_client.read_rows.return_value = iter([])
219+
220+
reader = class_under_test(mock_gapic_client, "name", 0, {})
221+
222+
read_session = _generate_arrow_read_session(arrow_schema) if use_session else None
223+
expected_schema = arrow_schema if use_session else pyarrow.schema([])
224+
225+
table = reader.to_arrow(read_session)
226+
227+
assert len(table) == 0
228+
assert table.schema == expected_schema
229+
230+
211231
def test_rows_w_scalars_arrow(class_under_test, mock_gapic_client):
212232
arrow_schema = _bq_to_arrow_schema(SCALAR_COLUMNS)
213233
arrow_batches = _bq_to_arrow_batches(SCALAR_BLOCKS, arrow_schema)

0 commit comments

Comments
 (0)