Skip to content

Commit 3edc313

Browse files
chore: prevent location warning when _read_gbq_colab can determine the location (#1802)
* chore: prevent location warning when _read_gbq_colab can determine the location I've made some updates to prevent a location warning when the system can determine the location for `bigframes.pandas.io.api._read_gbq_colab`. I've updated `bigframes.pandas.io.api._read_gbq_colab` so it correctly calls `bigframes.session.Session._read_gbq_colab` and adjusted its arguments. The `_read_gbq_colab` function in the pandas API layer now has a simpler signature, accepting `query_or_table`, `pyformat_args`, and `dry_run`. It will continue to call `_set_default_session_location_if_possible` to prevent location warnings. I've also updated the unit tests to reflect these changes, making sure that the correct session-level function is called and that arguments are passed through as expected. I've also moved the tests to `tests/unit/pandas/io/test_api.py` and converted them to pytest style to follow our repository conventions. * Update tests/unit/pandas/io/test_api.py * remove unused import * format the query first --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 080eb7b commit 3edc313

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

bigframes/pandas/io/api.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,67 @@ def read_gbq(
216216
read_gbq.__doc__ = inspect.getdoc(bigframes.session.Session.read_gbq)
217217

218218

219+
@overload
220+
def _read_gbq_colab( # type: ignore[overload-overlap]
221+
query_or_table: str,
222+
*,
223+
pyformat_args: Optional[Dict[str, Any]] = ...,
224+
dry_run: Literal[False] = ...,
225+
) -> bigframes.dataframe.DataFrame:
226+
...
227+
228+
229+
@overload
230+
def _read_gbq_colab(
231+
query_or_table: str,
232+
*,
233+
pyformat_args: Optional[Dict[str, Any]] = ...,
234+
dry_run: Literal[True] = ...,
235+
) -> pandas.Series:
236+
...
237+
238+
239+
def _read_gbq_colab(
240+
query_or_table: str,
241+
*,
242+
pyformat_args: Optional[Dict[str, Any]] = None,
243+
dry_run: bool = False,
244+
) -> bigframes.dataframe.DataFrame | pandas.Series:
245+
"""A Colab-specific version of read_gbq.
246+
247+
Calls `_set_default_session_location_if_possible` and then delegates
248+
to `bigframes.session.Session._read_gbq_colab`.
249+
250+
Args:
251+
query_or_table (str):
252+
SQL query or table ID (table ID not yet supported).
253+
pyformat_args (Optional[Dict[str, Any]]):
254+
Parameters to format into the query string.
255+
dry_run (bool):
256+
If True, estimates the query results size without returning data.
257+
The return will be a pandas Series with query metadata.
258+
259+
Returns:
260+
Union[bigframes.dataframe.DataFrame, pandas.Series]:
261+
A BigQuery DataFrame if `dry_run` is False, otherwise a pandas Series.
262+
"""
263+
if pyformat_args is None:
264+
pyformat_args = {}
265+
266+
query = bigframes.core.pyformat.pyformat(
267+
query_or_table,
268+
pyformat_args=pyformat_args,
269+
)
270+
_set_default_session_location_if_possible(query)
271+
272+
return global_session.with_default_session(
273+
bigframes.session.Session._read_gbq_colab,
274+
query_or_table,
275+
pyformat_args=pyformat_args,
276+
dry_run=dry_run,
277+
)
278+
279+
219280
def read_gbq_model(model_name: str):
220281
return global_session.with_default_session(
221282
bigframes.session.Session.read_gbq_model,

tests/unit/pandas/io/test_api.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from unittest import mock
16+
17+
import bigframes.dataframe
18+
import bigframes.pandas.io.api as bf_io_api
19+
import bigframes.session
20+
21+
22+
@mock.patch("bigframes.pandas.io.api._set_default_session_location_if_possible")
23+
@mock.patch("bigframes.core.global_session.with_default_session")
24+
def test_read_gbq_colab_calls_set_location(
25+
mock_with_default_session, mock_set_location
26+
):
27+
# Configure the mock for with_default_session to return a DataFrame mock
28+
mock_df = mock.create_autospec(bigframes.dataframe.DataFrame)
29+
mock_with_default_session.return_value = mock_df
30+
31+
query_or_table = "SELECT {param1} AS param1"
32+
sample_pyformat_args = {"param1": "value1"}
33+
result = bf_io_api._read_gbq_colab(
34+
query_or_table, pyformat_args=sample_pyformat_args, dry_run=False
35+
)
36+
37+
# Make sure that we format the SQL first to prevent syntax errors.
38+
formatted_query = "SELECT 'value1' AS param1"
39+
mock_set_location.assert_called_once_with(formatted_query)
40+
mock_with_default_session.assert_called_once()
41+
42+
# Check the actual arguments passed to with_default_session
43+
args, kwargs = mock_with_default_session.call_args
44+
assert args[0] == bigframes.session.Session._read_gbq_colab
45+
assert args[1] == query_or_table
46+
assert kwargs["pyformat_args"] == sample_pyformat_args
47+
assert not kwargs["dry_run"]
48+
assert isinstance(result, bigframes.dataframe.DataFrame)

0 commit comments

Comments
 (0)