@@ -248,6 +248,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
248248 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
249249 return m .groupdict () if m else {}
250250
251+ @classmethod
252+ def get_mtls_endpoint_and_cert_source (
253+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
254+ ):
255+ """Return the API endpoint and client cert source for mutual TLS.
256+
257+ The client cert source is determined in the following order:
258+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
259+ client cert source is None.
260+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
261+ default client cert source exists, use the default one; otherwise the client cert
262+ source is None.
263+
264+ The API endpoint is determined in the following order:
265+ (1) if `client_options.api_endpoint` if provided, use the provided one.
266+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
267+ default mTLS endpoint; if the environment variabel is "never", use the default API
268+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
269+ use the default API endpoint.
270+
271+ More details can be found at https://google.aip.dev/auth/4114.
272+
273+ Args:
274+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
275+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
276+ in this method.
277+
278+ Returns:
279+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
280+ client cert source to use.
281+
282+ Raises:
283+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
284+ """
285+ if client_options is None :
286+ client_options = client_options_lib .ClientOptions ()
287+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
288+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
289+ if use_client_cert not in ("true" , "false" ):
290+ raise ValueError (
291+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
292+ )
293+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
294+ raise MutualTLSChannelError (
295+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
296+ )
297+
298+ # Figure out the client cert source to use.
299+ client_cert_source = None
300+ if use_client_cert == "true" :
301+ if client_options .client_cert_source :
302+ client_cert_source = client_options .client_cert_source
303+ elif mtls .has_default_client_cert_source ():
304+ client_cert_source = mtls .default_client_cert_source ()
305+
306+ # Figure out which api endpoint to use.
307+ if client_options .api_endpoint is not None :
308+ api_endpoint = client_options .api_endpoint
309+ elif use_mtls_endpoint == "always" or (
310+ use_mtls_endpoint == "auto" and client_cert_source
311+ ):
312+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
313+ else :
314+ api_endpoint = cls .DEFAULT_ENDPOINT
315+
316+ return api_endpoint , client_cert_source
317+
251318 def __init__ (
252319 self ,
253320 * ,
@@ -298,57 +365,22 @@ def __init__(
298365 if client_options is None :
299366 client_options = client_options_lib .ClientOptions ()
300367
301- # Create SSL credentials for mutual TLS if needed.
302- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
303- "true" ,
304- "false" ,
305- ):
306- raise ValueError (
307- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
308- )
309- use_client_cert = (
310- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
368+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
369+ client_options
311370 )
312371
313- client_cert_source_func = None
314- is_mtls = False
315- if use_client_cert :
316- if client_options .client_cert_source :
317- is_mtls = True
318- client_cert_source_func = client_options .client_cert_source
319- else :
320- is_mtls = mtls .has_default_client_cert_source ()
321- if is_mtls :
322- client_cert_source_func = mtls .default_client_cert_source ()
323- else :
324- client_cert_source_func = None
325-
326- # Figure out which api endpoint to use.
327- if client_options .api_endpoint is not None :
328- api_endpoint = client_options .api_endpoint
329- else :
330- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
331- if use_mtls_env == "never" :
332- api_endpoint = self .DEFAULT_ENDPOINT
333- elif use_mtls_env == "always" :
334- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
335- elif use_mtls_env == "auto" :
336- if is_mtls :
337- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
338- else :
339- api_endpoint = self .DEFAULT_ENDPOINT
340- else :
341- raise MutualTLSChannelError (
342- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
343- "values: never, auto, always"
344- )
372+ api_key_value = getattr (client_options , "api_key" , None )
373+ if api_key_value and credentials :
374+ raise ValueError (
375+ "client_options.api_key and credentials are mutually exclusive"
376+ )
345377
346378 # Save or instantiate the transport.
347379 # Ordinarily, we provide the transport, but allowing a custom transport
348380 # instance provides an extensibility point for unusual situations.
349381 if isinstance (transport , ServiceManagerTransport ):
350382 # transport is a ServiceManagerTransport instance.
351- if credentials or client_options .credentials_file :
383+ if credentials or client_options .credentials_file or api_key_value :
352384 raise ValueError (
353385 "When providing a transport instance, "
354386 "provide its credentials directly."
@@ -360,6 +392,15 @@ def __init__(
360392 )
361393 self ._transport = transport
362394 else :
395+ import google .auth ._default # type: ignore
396+
397+ if api_key_value and hasattr (
398+ google .auth ._default , "get_api_key_credentials"
399+ ):
400+ credentials = google .auth ._default .get_api_key_credentials (
401+ api_key_value
402+ )
403+
363404 Transport = type (self ).get_transport_class (transport )
364405 self ._transport = Transport (
365406 credentials = credentials ,
0 commit comments