Skip to content

feat: delegate ReadRowsPage.to_arrow to pandas_gbq.arrow - #17938

Draft
shuoweil wants to merge 18 commits into
mainfrom
shuowei-gbq-task-8a-readrowspage-arrow
Draft

feat: delegate ReadRowsPage.to_arrow to pandas_gbq.arrow#17938
shuoweil wants to merge 18 commits into
mainfrom
shuowei-gbq-task-8a-readrowspage-arrow

Conversation

@shuoweil

@shuoweil shuoweil commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Working in progress branch

Delegates ReadRowsPage.to_arrow() in google-cloud-bigquery-storage to pandas_gbq.arrow.from_read_rows_response when pandas-gbq is installed, decoupling protobuf record batch parsing into pandas-gbq.

Changes Made

  1. pandas-gbq (packages/pandas-gbq):
    • Added pandas_gbq.arrow.from_read_rows_response(message, arrow_schema=None) to parse ReadRowsResponse protobuf messages into pyarrow.RecordBatch instances via IPC stream reading.
    • Exported arrow submodule in pandas_gbq.__all__.
    • Added unit test suite in packages/pandas-gbq/tests/unit/test_arrow.py.
  2. google-cloud-bigquery-storage (packages/google-cloud-bigquery-storage):
    • Updated ReadRowsPage.to_arrow() in google/cloud/bigquery_storage_v1/reader.py to delegate to pandas_gbq.arrow.from_read_rows_response.
    • Added a PendingDeprecationWarning informing users of direct pandas-gbq usage.
    • Retained inline stream parser fallback when pandas-gbq is not present.
    • Added explicit unit tests in packages/google-cloud-bigquery-storage/tests/unit/test_reader_v1_arrow.py.

Fixes #<526614511> 🦕

@shuoweil shuoweil self-assigned this Jul 29, 2026
@shuoweil
shuoweil requested review from a team as code owners July 29, 2026 21:57
@shuoweil
shuoweil requested review from sycai and removed request for a team and sycai July 29, 2026 21:57
@shuoweil
shuoweil marked this pull request as draft July 29, 2026 21:58

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request deprecates direct retrieval of Arrow record batches via google-cloud-bigquery-storage and delegates this functionality to a new arrow submodule in pandas-gbq. The review feedback highlights several critical issues: 1) pyarrow.RecordBatch does not have a from_batches method, so from_arrays should be used instead; 2) importing pyarrow at the top level of pandas_gbq/arrow.py will break imports for users who do not have this optional dependency installed, requiring a conditional import and string type annotations; and 3) reader.read_next_batch() can raise a StopIteration exception if the stream is empty, which needs to be handled gracefully.

Comment thread packages/pandas-gbq/pandas_gbq/arrow.py Outdated
Comment thread packages/pandas-gbq/pandas_gbq/arrow.py Outdated
"""Arrow integration submodule for pandas-gbq."""
from typing import Any, Optional

import pyarrow as pa

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Since pyarrow is an optional dependency for pandas-gbq, importing it at the top level of this module will cause import pandas_gbq to fail with an ImportError for any user who does not have pyarrow installed. We should wrap the import in a try-except block and raise a descriptive error only when the function is called. Additionally, when assigning None in the except ImportError block, type: ignore[assignment] is necessary to prevent a mypy error.

try:
    import pyarrow as pa
except ImportError:
    pa = None  # type: ignore[assignment]
References
  1. When handling an optional dependency by assigning None in an except ImportError block, type: ignore[assignment] is necessary on the assignment to prevent a mypy error, as using typing.TYPE_CHECKING alone is insufficient.

@shuoweil shuoweil Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Wrapped the optional pyarrow import in a try...except ImportError block with pa = None # type: ignore[assignment] in pandas_gbq/arrow.py, and added a runtime check in from_read_rows_response that raises a descriptive ImportError when pyarrow is missing. Added test coverage in test_arrow.py.

Comment thread packages/pandas-gbq/pandas_gbq/arrow.py Outdated
Comment thread packages/pandas-gbq/pandas_gbq/arrow.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant