Skip to content

Commit 451fd97

Browse files
feat: expose universe_domain for tpc (#1150)
1 parent a547826 commit 451fd97

File tree

7 files changed

+226
-3
lines changed

7 files changed

+226
-3
lines changed

google/cloud/bigtable/data/_async/client.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,20 @@ def __init__(
211211
*args, **kwargs, channel=custom_channel
212212
),
213213
)
214+
if (
215+
credentials
216+
and credentials.universe_domain != self.universe_domain
217+
and self._emulator_host is None
218+
):
219+
# validate that the universe domain of the credentials matches the
220+
# universe domain configured in client_options
221+
raise ValueError(
222+
f"The configured universe domain ({self.universe_domain}) does "
223+
"not match the universe domain found in the credentials "
224+
f"({self._credentials.universe_domain}). If you haven't "
225+
"configured the universe domain explicitly, `googleapis.com` "
226+
"is the default."
227+
)
214228
self._is_closed = CrossSync.Event()
215229
self.transport = cast(TransportType, self._gapic_client.transport)
216230
# keep track of active instances to for warmup on channel refresh
@@ -235,6 +249,24 @@ def __init__(
235249
stacklevel=2,
236250
)
237251

252+
@property
253+
def universe_domain(self) -> str:
254+
"""Return the universe domain used by the client instance.
255+
256+
Returns:
257+
str: The universe domain used by the client instance.
258+
"""
259+
return self._gapic_client.universe_domain
260+
261+
@property
262+
def api_endpoint(self) -> str:
263+
"""Return the API endpoint used by the client instance.
264+
265+
Returns:
266+
str: The API endpoint used by the client instance.
267+
"""
268+
return self._gapic_client.api_endpoint
269+
238270
@staticmethod
239271
def _client_version() -> str:
240272
"""

google/cloud/bigtable/data/_sync_autogen/client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ def __init__(
158158
*args, **kwargs, channel=custom_channel
159159
),
160160
)
161+
if (
162+
credentials
163+
and credentials.universe_domain != self.universe_domain
164+
and (self._emulator_host is None)
165+
):
166+
raise ValueError(
167+
f"The configured universe domain ({self.universe_domain}) does not match the universe domain found in the credentials ({self._credentials.universe_domain}). If you haven't configured the universe domain explicitly, `googleapis.com` is the default."
168+
)
161169
self._is_closed = CrossSync._Sync_Impl.Event()
162170
self.transport = cast(TransportType, self._gapic_client.transport)
163171
self._active_instances: Set[_WarmedInstanceKey] = set()
@@ -179,6 +187,22 @@ def __init__(
179187
stacklevel=2,
180188
)
181189

190+
@property
191+
def universe_domain(self) -> str:
192+
"""Return the universe domain used by the client instance.
193+
194+
Returns:
195+
str: The universe domain used by the client instance."""
196+
return self._gapic_client.universe_domain
197+
198+
@property
199+
def api_endpoint(self) -> str:
200+
"""Return the API endpoint used by the client instance.
201+
202+
Returns:
203+
str: The API endpoint used by the client instance."""
204+
return self._gapic_client.api_endpoint
205+
182206
@staticmethod
183207
def _client_version() -> str:
184208
"""Helper function to return the client version string for this client"""

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
dependencies = [
4040
"google-api-core[grpc] >= 2.17.0, <3.0.0",
4141
"google-cloud-core >= 1.4.4, <3.0.0",
42-
"google-auth >= 2.14.1, <3.0.0,!=2.24.0,!=2.25.0",
42+
"google-auth >= 2.23.0, <3.0.0,!=2.24.0,!=2.25.0",
4343
"grpc-google-iam-v1 >= 0.12.4, <1.0.0",
4444
"proto-plus >= 1.22.3, <2.0.0",
4545
"proto-plus >= 1.25.0, <2.0.0; python_version>='3.13'",

testing/constraints-3.7.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev",
77
# Then this file should have foo==1.14.0
88
google-api-core==2.17.0
9-
google-auth==2.14.1
9+
google-auth==2.23.0
1010
google-cloud-core==2.0.0
1111
grpc-google-iam-v1==0.12.4
1212
proto-plus==1.22.3

testing/constraints-3.8.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev",
77
# Then this file should have foo==1.14.0
88
google-api-core==2.17.0
9-
google-auth==2.14.1
9+
google-auth==2.23.0
1010
google-cloud-core==2.0.0
1111
grpc-google-iam-v1==0.12.4
1212
proto-plus==1.22.3

tests/unit/data/_async/test_client.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from google.cloud.bigtable_v2.types import ReadRowsResponse
2727
from google.cloud.bigtable.data.read_rows_query import ReadRowsQuery
2828
from google.api_core import exceptions as core_exceptions
29+
from google.api_core import client_options
2930
from google.cloud.bigtable.data.exceptions import InvalidChunk
3031
from google.cloud.bigtable.data.exceptions import _MutateRowsIncomplete
3132
from google.cloud.bigtable.data.mutations import DeleteAllFromRow
@@ -1038,6 +1039,97 @@ def test_client_ctor_sync(self):
10381039
assert client.project == "project-id"
10391040
assert client._channel_refresh_task is None
10401041

1042+
@CrossSync.pytest
1043+
async def test_default_universe_domain(self):
1044+
"""
1045+
When not passed, universe_domain should default to googleapis.com
1046+
"""
1047+
async with self._make_client(project="project-id", credentials=None) as client:
1048+
assert client.universe_domain == "googleapis.com"
1049+
assert client.api_endpoint == "bigtable.googleapis.com"
1050+
1051+
@CrossSync.pytest
1052+
async def test_custom_universe_domain(self):
1053+
"""test with a customized universe domain value and emulator enabled"""
1054+
universe_domain = "test-universe.test"
1055+
options = client_options.ClientOptions(universe_domain=universe_domain)
1056+
async with self._make_client(
1057+
project="project_id",
1058+
client_options=options,
1059+
use_emulator=True,
1060+
credentials=None,
1061+
) as client:
1062+
assert client.universe_domain == universe_domain
1063+
assert client.api_endpoint == f"bigtable.{universe_domain}"
1064+
1065+
@CrossSync.pytest
1066+
async def test_configured_universe_domain_matches_GDU(self):
1067+
"""that configured universe domain succeeds with matched GDU credentials."""
1068+
universe_domain = "googleapis.com"
1069+
options = client_options.ClientOptions(universe_domain=universe_domain)
1070+
async with self._make_client(
1071+
project="project_id", client_options=options, credentials=None
1072+
) as client:
1073+
assert client.universe_domain == "googleapis.com"
1074+
assert client.api_endpoint == "bigtable.googleapis.com"
1075+
1076+
@CrossSync.pytest
1077+
async def test_credential_universe_domain_matches_GDU(self):
1078+
"""Test with credentials"""
1079+
creds = AnonymousCredentials()
1080+
creds._universe_domain = "googleapis.com"
1081+
async with self._make_client(project="project_id", credentials=creds) as client:
1082+
assert client.universe_domain == "googleapis.com"
1083+
assert client.api_endpoint == "bigtable.googleapis.com"
1084+
1085+
@CrossSync.pytest
1086+
async def test_anomynous_credential_universe_domain(self):
1087+
"""Anomynopus credentials should use default universe domain"""
1088+
creds = AnonymousCredentials()
1089+
async with self._make_client(project="project_id", credentials=creds) as client:
1090+
assert client.universe_domain == "googleapis.com"
1091+
assert client.api_endpoint == "bigtable.googleapis.com"
1092+
1093+
@CrossSync.pytest
1094+
async def test_configured_universe_domain_mismatched_credentials(self):
1095+
"""Test that configured universe domain errors with mismatched universe
1096+
domain credentials.
1097+
"""
1098+
universe_domain = "test-universe.test"
1099+
options = client_options.ClientOptions(universe_domain=universe_domain)
1100+
creds = AnonymousCredentials()
1101+
creds._universe_domain = "different-universe"
1102+
with pytest.raises(ValueError) as exc:
1103+
self._make_client(
1104+
project="project_id",
1105+
client_options=options,
1106+
use_emulator=False,
1107+
credentials=creds,
1108+
)
1109+
err_msg = (
1110+
f"The configured universe domain ({universe_domain}) does "
1111+
"not match the universe domain found in the credentials "
1112+
f"({creds.universe_domain}). If you haven't "
1113+
"configured the universe domain explicitly, `googleapis.com` "
1114+
"is the default."
1115+
)
1116+
assert exc.value.args[0] == err_msg
1117+
1118+
@CrossSync.pytest
1119+
async def test_configured_universe_domain_matches_credentials(self):
1120+
"""Test that configured universe domain succeeds with matching universe
1121+
domain credentials.
1122+
"""
1123+
universe_domain = "test-universe.test"
1124+
options = client_options.ClientOptions(universe_domain=universe_domain)
1125+
creds = AnonymousCredentials()
1126+
creds._universe_domain = universe_domain
1127+
async with self._make_client(
1128+
project="project_id", credentials=creds, client_options=options
1129+
) as client:
1130+
assert client.universe_domain == universe_domain
1131+
assert client.api_endpoint == f"bigtable.{universe_domain}"
1132+
10411133

10421134
@CrossSync.convert_class("TestTable", add_mapping_for_name="TestTable")
10431135
class TestTableAsync:

tests/unit/data/_sync_autogen/test_client.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from google.cloud.bigtable_v2.types import ReadRowsResponse
2626
from google.cloud.bigtable.data.read_rows_query import ReadRowsQuery
2727
from google.api_core import exceptions as core_exceptions
28+
from google.api_core import client_options
2829
from google.cloud.bigtable.data.exceptions import InvalidChunk
2930
from google.cloud.bigtable.data.exceptions import _MutateRowsIncomplete
3031
from google.cloud.bigtable.data.mutations import DeleteAllFromRow
@@ -836,6 +837,80 @@ def test_context_manager(self):
836837
close_mock.assert_called_once()
837838
true_close()
838839

840+
def test_default_universe_domain(self):
841+
"""When not passed, universe_domain should default to googleapis.com"""
842+
with self._make_client(project="project-id", credentials=None) as client:
843+
assert client.universe_domain == "googleapis.com"
844+
assert client.api_endpoint == "bigtable.googleapis.com"
845+
846+
def test_custom_universe_domain(self):
847+
"""test with a customized universe domain value and emulator enabled"""
848+
universe_domain = "test-universe.test"
849+
options = client_options.ClientOptions(universe_domain=universe_domain)
850+
with self._make_client(
851+
project="project_id",
852+
client_options=options,
853+
use_emulator=True,
854+
credentials=None,
855+
) as client:
856+
assert client.universe_domain == universe_domain
857+
assert client.api_endpoint == f"bigtable.{universe_domain}"
858+
859+
def test_configured_universe_domain_matches_GDU(self):
860+
"""that configured universe domain succeeds with matched GDU credentials."""
861+
universe_domain = "googleapis.com"
862+
options = client_options.ClientOptions(universe_domain=universe_domain)
863+
with self._make_client(
864+
project="project_id", client_options=options, credentials=None
865+
) as client:
866+
assert client.universe_domain == "googleapis.com"
867+
assert client.api_endpoint == "bigtable.googleapis.com"
868+
869+
def test_credential_universe_domain_matches_GDU(self):
870+
"""Test with credentials"""
871+
creds = AnonymousCredentials()
872+
creds._universe_domain = "googleapis.com"
873+
with self._make_client(project="project_id", credentials=creds) as client:
874+
assert client.universe_domain == "googleapis.com"
875+
assert client.api_endpoint == "bigtable.googleapis.com"
876+
877+
def test_anomynous_credential_universe_domain(self):
878+
"""Anomynopus credentials should use default universe domain"""
879+
creds = AnonymousCredentials()
880+
with self._make_client(project="project_id", credentials=creds) as client:
881+
assert client.universe_domain == "googleapis.com"
882+
assert client.api_endpoint == "bigtable.googleapis.com"
883+
884+
def test_configured_universe_domain_mismatched_credentials(self):
885+
"""Test that configured universe domain errors with mismatched universe
886+
domain credentials."""
887+
universe_domain = "test-universe.test"
888+
options = client_options.ClientOptions(universe_domain=universe_domain)
889+
creds = AnonymousCredentials()
890+
creds._universe_domain = "different-universe"
891+
with pytest.raises(ValueError) as exc:
892+
self._make_client(
893+
project="project_id",
894+
client_options=options,
895+
use_emulator=False,
896+
credentials=creds,
897+
)
898+
err_msg = f"The configured universe domain ({universe_domain}) does not match the universe domain found in the credentials ({creds.universe_domain}). If you haven't configured the universe domain explicitly, `googleapis.com` is the default."
899+
assert exc.value.args[0] == err_msg
900+
901+
def test_configured_universe_domain_matches_credentials(self):
902+
"""Test that configured universe domain succeeds with matching universe
903+
domain credentials."""
904+
universe_domain = "test-universe.test"
905+
options = client_options.ClientOptions(universe_domain=universe_domain)
906+
creds = AnonymousCredentials()
907+
creds._universe_domain = universe_domain
908+
with self._make_client(
909+
project="project_id", credentials=creds, client_options=options
910+
) as client:
911+
assert client.universe_domain == universe_domain
912+
assert client.api_endpoint == f"bigtable.{universe_domain}"
913+
839914

840915
@CrossSync._Sync_Impl.add_mapping_decorator("TestTable")
841916
class TestTable:

0 commit comments

Comments
 (0)