Repository: googleapis/python-bigquery
Pull request #1847 (2024-03-07 22:44:10)

fix: supplementary fix to env-based universe resolution
This PR propagates the fixes to universe resolution up into client instantiation, and allows environt variable based resolution to occur even if client options are entirely unspecified.

Linchin: Thank you @shollyman, I left two comments about corner cases handling.

Patch:
diff --git a/google/cloud/bigquery/client.py b/google/cloud/bigquery/client.py
index cb4daa89..408e7e49 100644
--- a/google/cloud/bigquery/client.py
+++ b/google/cloud/bigquery/client.py
@@ -249,20 +249,19 @@ class Client(ClientWithProject):
         bq_host = _get_bigquery_host()
         kw_args["api_endpoint"] = bq_host if bq_host != _DEFAULT_HOST else None
         client_universe = None
-        if client_options:
-            if isinstance(client_options, dict):
-                client_options = google.api_core.client_options.from_dict(
-                    client_options
+        if client_options is None:
+            client_options = {}
+        if isinstance(client_options, dict):
+            client_options = google.api_core.client_options.from_dict(client_options)
+        if client_options.api_endpoint:
+            api_endpoint = client_options.api_endpoint
+            kw_args["api_endpoint"] = api_endpoint
+        else:
+            client_universe = _get_client_universe(client_options)
+            if client_universe != _DEFAULT_UNIVERSE:
+                kw_args["api_endpoint"] = _DEFAULT_HOST_TEMPLATE.replace(
+                    "{UNIVERSE_DOMAIN}", client_universe
                 )
-            if client_options.api_endpoint:
-                api_endpoint = client_options.api_endpoint
-                kw_args["api_endpoint"] = api_endpoint
-            else:
-                client_universe = _get_client_universe(client_options)
-                if client_universe != _DEFAULT_UNIVERSE:
-                    kw_args["api_endpoint"] = _DEFAULT_HOST_TEMPLATE.replace(
-                        "{UNIVERSE_DOMAIN}", client_universe
-                    )
         # Ensure credentials and universe are not in conflict.
         if hasattr(self, "_credentials") and client_universe is not None:
             _validate_universe(client_universe, self._credentials)


Test patch:
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index be8bef03..d20712a8 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -23,6 +23,7 @@ import io
 import itertools
 import json
 import operator
+import os
 import unittest
 from unittest import mock
 import warnings
@@ -171,6 +172,17 @@ class TestClient(unittest.TestCase):
             client._connection.API_BASE_URL, client._connection.DEFAULT_API_ENDPOINT
         )
 
+    @mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"})
+    def test_ctor_w_only_env_universe(self):
+        creds = _make_credentials()
+        http = object()
+        client = self._make_one(
+            project=self.PROJECT,
+            credentials=creds,
+            _http=http,
+        )
+        self.assertEqual(client._connection.API_BASE_URL, "https://bigquery.foo.com")
+
     def test_ctor_w_client_options_dict(self):
         creds = _make_credentials()
         http = object()