Skip to content

Commit b5f4869

Browse files
authored
fix: update runtime check for min google-cloud-bigquery to 3.3.5 (#721)
The minimum version of google-cloud-bigquery was updated to 3.3.5 in pandas-gbq version 0.18.0 (released November 2022). This change updates the runtime check in features.py to reflect that minimum version and removes some dead code for feature checks that are no longer relevant.
1 parent 78c58cc commit b5f4869

File tree

8 files changed

+32
-177
lines changed

8 files changed

+32
-177
lines changed

pandas_gbq/features.py

+9-37
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@
55
"""Module for checking dependency versions and supported features."""
66

77
# https://github.com/googleapis/python-bigquery/blob/master/CHANGELOG.md
8-
BIGQUERY_MINIMUM_VERSION = "1.27.2"
9-
BIGQUERY_ACCURATE_TIMESTAMP_VERSION = "2.6.0"
10-
BIGQUERY_FROM_DATAFRAME_CSV_VERSION = "2.6.0"
11-
BIGQUERY_SUPPORTS_BIGNUMERIC_VERSION = "2.10.0"
12-
BIGQUERY_NO_DATE_AS_OBJECT_VERSION = "3.0.0dev"
8+
BIGQUERY_MINIMUM_VERSION = "3.3.5"
139
PANDAS_VERBOSITY_DEPRECATION_VERSION = "0.23.0"
1410
PANDAS_BOOLEAN_DTYPE_VERSION = "1.0.0"
1511
PANDAS_PARQUET_LOSSLESS_TIMESTAMP_VERSION = "1.1.0"
@@ -31,47 +27,23 @@ def bigquery_installed_version(self):
3127
self._bigquery_installed_version = packaging.version.parse(
3228
google.cloud.bigquery.__version__
3329
)
30+
return self._bigquery_installed_version
31+
32+
def bigquery_try_import(self):
33+
import google.cloud.bigquery
34+
import packaging.version
35+
3436
bigquery_minimum_version = packaging.version.parse(BIGQUERY_MINIMUM_VERSION)
3537

36-
if self._bigquery_installed_version < bigquery_minimum_version:
38+
if self.bigquery_installed_version < bigquery_minimum_version:
3739
raise ImportError(
3840
"pandas-gbq requires google-cloud-bigquery >= {0}, "
3941
"current version {1}".format(
4042
bigquery_minimum_version, self._bigquery_installed_version
4143
)
4244
)
4345

44-
return self._bigquery_installed_version
45-
46-
@property
47-
def bigquery_has_accurate_timestamp(self):
48-
import packaging.version
49-
50-
min_version = packaging.version.parse(BIGQUERY_ACCURATE_TIMESTAMP_VERSION)
51-
return self.bigquery_installed_version >= min_version
52-
53-
@property
54-
def bigquery_has_bignumeric(self):
55-
import packaging.version
56-
57-
min_version = packaging.version.parse(BIGQUERY_SUPPORTS_BIGNUMERIC_VERSION)
58-
return self.bigquery_installed_version >= min_version
59-
60-
@property
61-
def bigquery_has_from_dataframe_with_csv(self):
62-
import packaging.version
63-
64-
bigquery_from_dataframe_version = packaging.version.parse(
65-
BIGQUERY_FROM_DATAFRAME_CSV_VERSION
66-
)
67-
return self.bigquery_installed_version >= bigquery_from_dataframe_version
68-
69-
@property
70-
def bigquery_needs_date_as_object(self):
71-
import packaging.version
72-
73-
max_version = packaging.version.parse(BIGQUERY_NO_DATE_AS_OBJECT_VERSION)
74-
return self.bigquery_installed_version < max_version
46+
return google.cloud.bigquery
7547

7648
@property
7749
def pandas_installed_version(self):

pandas_gbq/gbq.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,9 @@ def sizeof_fmt(num, suffix="B"):
367367

368368
def get_client(self):
369369
import google.api_core.client_info
370-
from google.cloud import bigquery
371370
import pandas
372371

372+
bigquery = FEATURES.bigquery_try_import()
373373
client_info = google.api_core.client_info.ClientInfo(
374374
user_agent="pandas-{}".format(pandas.__version__)
375375
)
@@ -563,10 +563,6 @@ def _download_results(
563563
if max_results is not None:
564564
create_bqstorage_client = False
565565

566-
to_dataframe_kwargs = {}
567-
if FEATURES.bigquery_needs_date_as_object:
568-
to_dataframe_kwargs["date_as_object"] = True
569-
570566
try:
571567
schema_fields = [field.to_api_repr() for field in rows_iter.schema]
572568
conversion_dtypes = _bqschema_to_nullsafe_dtypes(schema_fields)
@@ -575,7 +571,6 @@ def _download_results(
575571
dtypes=conversion_dtypes,
576572
progress_bar_type=progress_bar_type,
577573
create_bqstorage_client=create_bqstorage_client,
578-
**to_dataframe_kwargs,
579574
)
580575
except self.http_error as ex:
581576
self.process_http_error(ex)

pandas_gbq/load.py

+10-23
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from google.cloud import bigquery
1515

1616
from pandas_gbq import exceptions
17-
from pandas_gbq.features import FEATURES
1817
import pandas_gbq.schema
1918

2019

@@ -252,28 +251,16 @@ def load_chunks(
252251
# TODO: yield progress depending on result() with timeout
253252
return [0]
254253
elif api_method == "load_csv":
255-
if FEATURES.bigquery_has_from_dataframe_with_csv:
256-
return load_csv_from_dataframe(
257-
client,
258-
dataframe,
259-
destination_table_ref,
260-
write_disposition,
261-
location,
262-
chunksize,
263-
schema,
264-
billing_project=billing_project,
265-
)
266-
else:
267-
return load_csv_from_file(
268-
client,
269-
dataframe,
270-
destination_table_ref,
271-
write_disposition,
272-
location,
273-
chunksize,
274-
schema,
275-
billing_project=billing_project,
276-
)
254+
return load_csv_from_dataframe(
255+
client,
256+
dataframe,
257+
destination_table_ref,
258+
write_disposition,
259+
location,
260+
chunksize,
261+
schema,
262+
billing_project=billing_project,
263+
)
277264
else:
278265
raise ValueError(
279266
f"Got unexpected api_method: {api_method!r}, expected one of 'load_parquet', 'load_csv'."

setup.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,9 @@
3434
"google-api-core >= 2.10.2, <3.0.0dev",
3535
"google-auth >=2.13.0",
3636
"google-auth-oauthlib >=0.7.0",
37-
# Require 1.27.* because it has a fix for out-of-bounds timestamps. See:
38-
# https://github.com/googleapis/python-bigquery/pull/209 and
39-
# https://github.com/googleapis/python-bigquery-pandas/issues/365
40-
# Exclude 2.4.* because it has a bug where waiting for the query can hang
41-
# indefinitely. https://github.com/pydata/pandas-gbq/issues/343
42-
"google-cloud-bigquery >=3.3.5,<4.0.0dev,!=2.4.*",
37+
# Please also update the minimum version in pandas_gbq/features.py to
38+
# allow pandas-gbq to detect invalid package versions at runtime.
39+
"google-cloud-bigquery >=3.3.5,<4.0.0dev",
4340
"google-cloud-bigquery-storage >=2.16.2,<3.0.0dev",
4441
"packaging >=20.0.0",
4542
]

tests/system/test_read_gbq.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,6 @@ def writable_table(
454454
),
455455
),
456456
id="bignumeric-normal-range",
457-
marks=pytest.mark.skipif(
458-
not FEATURES.bigquery_has_bignumeric,
459-
reason="BIGNUMERIC not supported in this version of google-cloud-bigquery",
460-
),
461457
),
462458
pytest.param(
463459
*QueryTestCase(
@@ -538,9 +534,7 @@ def writable_table(
538534
),
539535
}
540536
),
541-
use_bqstorage_apis={True, False}
542-
if FEATURES.bigquery_has_accurate_timestamp
543-
else {True},
537+
use_bqstorage_apis={True, False},
544538
),
545539
id="issue365-extreme-datetimes",
546540
),

tests/unit/test_features.py

-71
Original file line numberDiff line numberDiff line change
@@ -13,77 +13,6 @@ def fresh_bigquery_version(monkeypatch):
1313
monkeypatch.setattr(FEATURES, "_pandas_installed_version", None)
1414

1515

16-
@pytest.mark.parametrize(
17-
["bigquery_version", "expected"],
18-
[
19-
("1.27.2", False),
20-
("1.99.100", False),
21-
("2.5.4", False),
22-
("2.6.0", True),
23-
("2.6.1", True),
24-
("2.12.0", True),
25-
],
26-
)
27-
def test_bigquery_has_accurate_timestamp(monkeypatch, bigquery_version, expected):
28-
import google.cloud.bigquery
29-
30-
monkeypatch.setattr(google.cloud.bigquery, "__version__", bigquery_version)
31-
assert FEATURES.bigquery_has_accurate_timestamp == expected
32-
33-
34-
@pytest.mark.parametrize(
35-
["bigquery_version", "expected"],
36-
[
37-
("1.27.2", False),
38-
("1.99.100", False),
39-
("2.9.999", False),
40-
("2.10.0", True),
41-
("2.12.0", True),
42-
("3.0.0", True),
43-
],
44-
)
45-
def test_bigquery_has_bignumeric(monkeypatch, bigquery_version, expected):
46-
import google.cloud.bigquery
47-
48-
monkeypatch.setattr(google.cloud.bigquery, "__version__", bigquery_version)
49-
assert FEATURES.bigquery_has_bignumeric == expected
50-
51-
52-
@pytest.mark.parametrize(
53-
["bigquery_version", "expected"],
54-
[
55-
("1.27.2", False),
56-
("1.99.100", False),
57-
("2.5.4", False),
58-
("2.6.0", True),
59-
("2.6.1", True),
60-
("2.12.0", True),
61-
],
62-
)
63-
def test_bigquery_has_from_dataframe_with_csv(monkeypatch, bigquery_version, expected):
64-
import google.cloud.bigquery
65-
66-
monkeypatch.setattr(google.cloud.bigquery, "__version__", bigquery_version)
67-
assert FEATURES.bigquery_has_from_dataframe_with_csv == expected
68-
69-
70-
@pytest.mark.parametrize(
71-
["bigquery_version", "expected"],
72-
[
73-
("1.27.2", True),
74-
("1.99.100", True),
75-
("2.12.0", True),
76-
("3.0.0", False),
77-
("3.1.0", False),
78-
],
79-
)
80-
def test_bigquery_needs_date_as_object(monkeypatch, bigquery_version, expected):
81-
import google.cloud.bigquery
82-
83-
monkeypatch.setattr(google.cloud.bigquery, "__version__", bigquery_version)
84-
assert FEATURES.bigquery_needs_date_as_object == expected
85-
86-
8716
@pytest.mark.parametrize(
8817
["pandas_version", "expected"],
8918
[

tests/unit/test_gbq.py

+5-13
Original file line numberDiff line numberDiff line change
@@ -732,19 +732,11 @@ def test_read_gbq_use_bqstorage_api(
732732
assert df is not None
733733

734734
mock_list_rows = mock_bigquery_client.list_rows("dest", max_results=100)
735-
if FEATURES.bigquery_needs_date_as_object:
736-
mock_list_rows.to_dataframe.assert_called_once_with(
737-
create_bqstorage_client=True,
738-
dtypes=mock.ANY,
739-
progress_bar_type=mock.ANY,
740-
date_as_object=True,
741-
)
742-
else:
743-
mock_list_rows.to_dataframe.assert_called_once_with(
744-
create_bqstorage_client=True,
745-
dtypes=mock.ANY,
746-
progress_bar_type=mock.ANY,
747-
)
735+
mock_list_rows.to_dataframe.assert_called_once_with(
736+
create_bqstorage_client=True,
737+
dtypes=mock.ANY,
738+
progress_bar_type=mock.ANY,
739+
)
748740

749741

750742
def test_read_gbq_calls_tqdm(mock_bigquery_client, mock_service_account_credentials):

tests/unit/test_load.py

+3-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import decimal
99
from io import StringIO
1010
import textwrap
11-
from unittest import mock
1211

1312
import db_dtypes
1413
import numpy
@@ -17,13 +16,10 @@
1716
import pytest
1817

1918
from pandas_gbq import exceptions
20-
from pandas_gbq.features import FEATURES
2119
from pandas_gbq import load
2220

2321

2422
def load_method(bqclient, api_method):
25-
if not FEATURES.bigquery_has_from_dataframe_with_csv and api_method == "load_csv":
26-
return bqclient.load_table_from_file
2723
return bqclient.load_table_from_dataframe
2824

2925

@@ -180,24 +176,17 @@ def test_load_csv_from_file_generates_schema(mock_bigquery_client):
180176

181177

182178
@pytest.mark.parametrize(
183-
["bigquery_has_from_dataframe_with_csv", "api_method"],
184-
[(True, "load_parquet"), (True, "load_csv"), (False, "load_csv")],
179+
["api_method"],
180+
[("load_parquet",), ("load_csv",)],
185181
)
186-
def test_load_chunks_omits_policy_tags(
187-
monkeypatch, mock_bigquery_client, bigquery_has_from_dataframe_with_csv, api_method
188-
):
182+
def test_load_chunks_omits_policy_tags(monkeypatch, mock_bigquery_client, api_method):
189183
"""Ensure that policyTags are omitted.
190184
191185
We don't want to change the policyTags via a load job, as this can cause
192186
403 error. See: https://github.com/googleapis/python-bigquery/pull/557
193187
"""
194188
import google.cloud.bigquery
195189

196-
monkeypatch.setattr(
197-
type(FEATURES),
198-
"bigquery_has_from_dataframe_with_csv",
199-
mock.PropertyMock(return_value=bigquery_has_from_dataframe_with_csv),
200-
)
201190
df = pandas.DataFrame({"col1": [1, 2, 3]})
202191
destination = google.cloud.bigquery.TableReference.from_string(
203192
"my-project.my_dataset.my_table"

0 commit comments

Comments
 (0)