Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions packages/google-cloud-bigquery/google/cloud/bigquery/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
_versions_helpers,
enums,
job,
version,

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.

medium

Importing the version module as version can easily lead to shadowing issues or confusion because version is a very common variable and parameter name throughout this codebase. Consider aliasing it to bq_version to prevent potential naming conflicts.

Suggested change
version,
version as bq_version,

)
from google.cloud.bigquery import exceptions as bq_exceptions
from google.cloud.bigquery._helpers import (
Expand Down Expand Up @@ -128,9 +129,7 @@
)

pyarrow = _versions_helpers.PYARROW_VERSIONS.try_import()
pandas = (
_versions_helpers.PANDAS_VERSIONS.try_import()
) # mypy check fails because pandas import is outside module, there are type: ignore comments related to this
pandas = _versions_helpers.PANDAS_VERSIONS.try_import() # mypy check fails because pandas import is outside module, there are type: ignore comments related to this


ResumableTimeoutType = Union[
Expand All @@ -148,7 +147,7 @@
_RESUMABLE_URL_TEMPLATE = _BASE_UPLOAD_TEMPLATE + "resumable"
_GENERIC_CONTENT_TYPE = "*/*"
_READ_LESS_THAN_SIZE = (
"Size {:d} was specified but the file-like object only had " "{:d} bytes remaining."
"Size {:d} was specified but the file-like object only had {:d} bytes remaining."
)
_NEED_TABLE_ARGUMENT = (
"The table argument should be a table ID string, Table, or TableReference"
Expand Down Expand Up @@ -641,9 +640,16 @@ def _ensure_bqstorage_client(
pandas_gbq = None # type: ignore

if pandas_gbq is None:
user_agent = "pandas-gbq/0.0.0"
# Even if pandas-gbq isn't installed, attribute all
# to_dataframe/to_arrow usage the same as we do the recommended
# (pandas-gbq) code paths.
pandas_user_agent = "pandas-gbq/0.0.0"
else:
user_agent = f"pandas-gbq/{pandas_gbq.__version__}"
pandas_user_agent = f"pandas-gbq/{pandas_gbq.__version__}"

# Track the google-cloud-bigquery version as "legacy" because this code
# path is intended to be migrated to pandas-gbq itself.
user_agent = f"legacy-gcb/{version.__version__} {pandas_user_agent}"

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.

medium

Use the aliased bq_version to avoid potential shadowing issues with the common name version.

Suggested change
user_agent = f"legacy-gcb/{version.__version__} {pandas_user_agent}"
user_agent = f"legacy-gcb/{bq_version.__version__} {pandas_user_agent}"


if client_info is None:
amended_client_info = google.api_core.gapic_v1.client_info.ClientInfo(
Expand Down
70 changes: 46 additions & 24 deletions packages/google-cloud-bigquery/tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
import google.cloud.bigquery.table
from google.api_core import client_info
from google.cloud import bigquery
from google.cloud.bigquery import ParquetOptions, exceptions
from google.cloud.bigquery import ParquetOptions, exceptions, version
from google.cloud.bigquery.dataset import Dataset, DatasetReference
from google.cloud.bigquery.enums import DatasetView, TimestampPrecision, UpdateMode
from google.cloud.bigquery.retry import DEFAULT_TIMEOUT
Expand Down Expand Up @@ -840,6 +840,9 @@ def test_ensure_bqstorage_client_creating_new_instance(self):
self.assertIs(kwargs["client_options"], mock.sentinel.client_options)
self.assertIn("test-agent", kwargs["client_info"].user_agent)
self.assertIn("pandas-gbq", kwargs["client_info"].user_agent)
self.assertIn(
f"legacy-gcb/{version.__version__}", kwargs["client_info"].user_agent
)

def test_ensure_bqstorage_client_pandas_gbq_installed(self):
bigquery_storage = pytest.importorskip("google.cloud.bigquery_storage")
Expand All @@ -857,15 +860,17 @@ def test_ensure_bqstorage_client_pandas_gbq_installed(self):
mock_pandas = mock.Mock()
mock_pandas.__version__ = "0.13.0"

with mock.patch(
"google.cloud.bigquery_storage.BigQueryReadClient", mock_client
), mock.patch.dict(sys.modules, {"pandas_gbq": mock_pandas}):
with (
mock.patch("google.cloud.bigquery_storage.BigQueryReadClient", mock_client),
mock.patch.dict(sys.modules, {"pandas_gbq": mock_pandas}),
):
client._ensure_bqstorage_client(client_info=client_info)

mock_client.assert_called_once()
_, kwargs = mock_client.call_args
self.assertEqual(
kwargs["client_info"].user_agent, "app-agent pandas-gbq/0.13.0"
kwargs["client_info"].user_agent,
f"app-agent legacy-gcb/{version.__version__} pandas-gbq/0.13.0",
)

def test_ensure_bqstorage_client_pandas_gbq_not_installed(self):
Expand All @@ -881,14 +886,18 @@ def test_ensure_bqstorage_client_pandas_gbq_not_installed(self):
user_agent="app-agent"
)

with mock.patch(
"google.cloud.bigquery_storage.BigQueryReadClient", mock_client
), mock.patch.dict(sys.modules, {"pandas_gbq": None}):
with (
mock.patch("google.cloud.bigquery_storage.BigQueryReadClient", mock_client),
mock.patch.dict(sys.modules, {"pandas_gbq": None}),
):
client._ensure_bqstorage_client(client_info=client_info)

mock_client.assert_called_once()
_, kwargs = mock_client.call_args
self.assertEqual(kwargs["client_info"].user_agent, "app-agent pandas-gbq/0.0.0")
self.assertEqual(
kwargs["client_info"].user_agent,
f"app-agent legacy-gcb/{version.__version__} pandas-gbq/0.0.0",
)

def test_ensure_bqstorage_client_client_info_none(self):
bigquery_storage = pytest.importorskip("google.cloud.bigquery_storage")
Expand All @@ -898,14 +907,18 @@ def test_ensure_bqstorage_client_client_info_none(self):
creds = _make_credentials()
client = self._make_one(project=self.PROJECT, credentials=creds)

with mock.patch(
"google.cloud.bigquery_storage.BigQueryReadClient", mock_client
), mock.patch.dict(sys.modules, {"pandas_gbq": None}):
with (
mock.patch("google.cloud.bigquery_storage.BigQueryReadClient", mock_client),
mock.patch.dict(sys.modules, {"pandas_gbq": None}),
):
client._ensure_bqstorage_client(client_info=None)

mock_client.assert_called_once()
_, kwargs = mock_client.call_args
self.assertEqual(kwargs["client_info"].user_agent, "pandas-gbq/0.0.0")
self.assertEqual(
kwargs["client_info"].user_agent,
f"legacy-gcb/{version.__version__} pandas-gbq/0.0.0",
)

def test_ensure_bqstorage_client_client_info_user_agent_none(self):
bigquery_storage = pytest.importorskip("google.cloud.bigquery_storage")
Expand All @@ -919,14 +932,18 @@ def test_ensure_bqstorage_client_client_info_user_agent_none(self):

client_info = google.api_core.gapic_v1.client_info.ClientInfo(user_agent=None)

with mock.patch(
"google.cloud.bigquery_storage.BigQueryReadClient", mock_client
), mock.patch.dict(sys.modules, {"pandas_gbq": None}):
with (
mock.patch("google.cloud.bigquery_storage.BigQueryReadClient", mock_client),
mock.patch.dict(sys.modules, {"pandas_gbq": None}),
):
client._ensure_bqstorage_client(client_info=client_info)

mock_client.assert_called_once()
_, kwargs = mock_client.call_args
self.assertEqual(kwargs["client_info"].user_agent, "pandas-gbq/0.0.0")
self.assertEqual(
kwargs["client_info"].user_agent,
f"legacy-gcb/{version.__version__} pandas-gbq/0.0.0",
)

def test_ensure_bqstorage_client_missing_dependency(self):
creds = _make_credentials()
Expand Down Expand Up @@ -9157,9 +9174,10 @@ def test_load_table_from_dataframe_w_partial_schema_extra_types(self):
SchemaField("unknown_col", "BYTES"),
)
job_config = job.LoadJobConfig(schema=schema)
with load_patch as load_table_from_file, pytest.raises(
ValueError
) as exc_context:
with (
load_patch as load_table_from_file,
pytest.raises(ValueError) as exc_context,
):
client.load_table_from_dataframe(
dataframe, self.TABLE_REF, job_config=job_config, location=self.LOCATION
)
Expand Down Expand Up @@ -9429,9 +9447,13 @@ def test_load_table_from_dataframe_emits_pending_deprecation_warning(self):
get_table_patch = mock.patch(
"google.cloud.bigquery.client.Client.get_table", autospec=True
)
with load_patch, get_table_patch, pytest.warns(
PendingDeprecationWarning,
match="Loading DataFrames via google-cloud-bigquery is deprecated",
with (
load_patch,
get_table_patch,
pytest.warns(
PendingDeprecationWarning,
match="Loading DataFrames via google-cloud-bigquery is deprecated",
),
):
client.load_table_from_dataframe(dataframe, self.TABLE_REF)

Expand Down Expand Up @@ -9853,7 +9875,7 @@ def test_load_table_from_json_unicode_emoji_data_case(self):

client = self._make_client()

emoji = "\U0001F3E6"
emoji = "\U0001f3e6"
json_row = {"emoji": emoji}
json_rows = [json_row]

Expand Down
Loading
Loading