@@ -325,6 +325,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
325325 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
326326 return m .groupdict () if m else {}
327327
328+ @classmethod
329+ def get_mtls_endpoint_and_cert_source (
330+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
331+ ):
332+ """Return the API endpoint and client cert source for mutual TLS.
333+
334+ The client cert source is determined in the following order:
335+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
336+ client cert source is None.
337+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
338+ default client cert source exists, use the default one; otherwise the client cert
339+ source is None.
340+
341+ The API endpoint is determined in the following order:
342+ (1) if `client_options.api_endpoint` if provided, use the provided one.
343+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
344+ default mTLS endpoint; if the environment variabel is "never", use the default API
345+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
346+ use the default API endpoint.
347+
348+ More details can be found at https://google.aip.dev/auth/4114.
349+
350+ Args:
351+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
352+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
353+ in this method.
354+
355+ Returns:
356+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
357+ client cert source to use.
358+
359+ Raises:
360+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
361+ """
362+ if client_options is None :
363+ client_options = client_options_lib .ClientOptions ()
364+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
365+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
366+ if use_client_cert not in ("true" , "false" ):
367+ raise ValueError (
368+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
369+ )
370+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
371+ raise MutualTLSChannelError (
372+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
373+ )
374+
375+ # Figure out the client cert source to use.
376+ client_cert_source = None
377+ if use_client_cert == "true" :
378+ if client_options .client_cert_source :
379+ client_cert_source = client_options .client_cert_source
380+ elif mtls .has_default_client_cert_source ():
381+ client_cert_source = mtls .default_client_cert_source ()
382+
383+ # Figure out which api endpoint to use.
384+ if client_options .api_endpoint is not None :
385+ api_endpoint = client_options .api_endpoint
386+ elif use_mtls_endpoint == "always" or (
387+ use_mtls_endpoint == "auto" and client_cert_source
388+ ):
389+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
390+ else :
391+ api_endpoint = cls .DEFAULT_ENDPOINT
392+
393+ return api_endpoint , client_cert_source
394+
328395 def __init__ (
329396 self ,
330397 * ,
@@ -375,57 +442,22 @@ def __init__(
375442 if client_options is None :
376443 client_options = client_options_lib .ClientOptions ()
377444
378- # Create SSL credentials for mutual TLS if needed.
379- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
380- "true" ,
381- "false" ,
382- ):
383- raise ValueError (
384- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
385- )
386- use_client_cert = (
387- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
445+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
446+ client_options
388447 )
389448
390- client_cert_source_func = None
391- is_mtls = False
392- if use_client_cert :
393- if client_options .client_cert_source :
394- is_mtls = True
395- client_cert_source_func = client_options .client_cert_source
396- else :
397- is_mtls = mtls .has_default_client_cert_source ()
398- if is_mtls :
399- client_cert_source_func = mtls .default_client_cert_source ()
400- else :
401- client_cert_source_func = None
402-
403- # Figure out which api endpoint to use.
404- if client_options .api_endpoint is not None :
405- api_endpoint = client_options .api_endpoint
406- else :
407- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
408- if use_mtls_env == "never" :
409- api_endpoint = self .DEFAULT_ENDPOINT
410- elif use_mtls_env == "always" :
411- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
412- elif use_mtls_env == "auto" :
413- if is_mtls :
414- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
415- else :
416- api_endpoint = self .DEFAULT_ENDPOINT
417- else :
418- raise MutualTLSChannelError (
419- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
420- "values: never, auto, always"
421- )
449+ api_key_value = getattr (client_options , "api_key" , None )
450+ if api_key_value and credentials :
451+ raise ValueError (
452+ "client_options.api_key and credentials are mutually exclusive"
453+ )
422454
423455 # Save or instantiate the transport.
424456 # Ordinarily, we provide the transport, but allowing a custom transport
425457 # instance provides an extensibility point for unusual situations.
426458 if isinstance (transport , AutoMlTransport ):
427459 # transport is a AutoMlTransport instance.
428- if credentials or client_options .credentials_file :
460+ if credentials or client_options .credentials_file or api_key_value :
429461 raise ValueError (
430462 "When providing a transport instance, "
431463 "provide its credentials directly."
@@ -437,6 +469,15 @@ def __init__(
437469 )
438470 self ._transport = transport
439471 else :
472+ import google .auth ._default # type: ignore
473+
474+ if api_key_value and hasattr (
475+ google .auth ._default , "get_api_key_credentials"
476+ ):
477+ credentials = google .auth ._default .get_api_key_credentials (
478+ api_key_value
479+ )
480+
440481 Transport = type (self ).get_transport_class (transport )
441482 self ._transport = Transport (
442483 credentials = credentials ,
0 commit comments