@@ -344,6 +344,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
344344 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
345345 return m .groupdict () if m else {}
346346
347+ @classmethod
348+ def get_mtls_endpoint_and_cert_source (
349+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
350+ ):
351+ """Return the API endpoint and client cert source for mutual TLS.
352+
353+ The client cert source is determined in the following order:
354+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
355+ client cert source is None.
356+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
357+ default client cert source exists, use the default one; otherwise the client cert
358+ source is None.
359+
360+ The API endpoint is determined in the following order:
361+ (1) if `client_options.api_endpoint` if provided, use the provided one.
362+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
363+ default mTLS endpoint; if the environment variabel is "never", use the default API
364+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
365+ use the default API endpoint.
366+
367+ More details can be found at https://google.aip.dev/auth/4114.
368+
369+ Args:
370+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
371+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
372+ in this method.
373+
374+ Returns:
375+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
376+ client cert source to use.
377+
378+ Raises:
379+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
380+ """
381+ if client_options is None :
382+ client_options = client_options_lib .ClientOptions ()
383+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
384+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
385+ if use_client_cert not in ("true" , "false" ):
386+ raise ValueError (
387+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
388+ )
389+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
390+ raise MutualTLSChannelError (
391+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
392+ )
393+
394+ # Figure out the client cert source to use.
395+ client_cert_source = None
396+ if use_client_cert == "true" :
397+ if client_options .client_cert_source :
398+ client_cert_source = client_options .client_cert_source
399+ elif mtls .has_default_client_cert_source ():
400+ client_cert_source = mtls .default_client_cert_source ()
401+
402+ # Figure out which api endpoint to use.
403+ if client_options .api_endpoint is not None :
404+ api_endpoint = client_options .api_endpoint
405+ elif use_mtls_endpoint == "always" or (
406+ use_mtls_endpoint == "auto" and client_cert_source
407+ ):
408+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
409+ else :
410+ api_endpoint = cls .DEFAULT_ENDPOINT
411+
412+ return api_endpoint , client_cert_source
413+
347414 def __init__ (
348415 self ,
349416 * ,
@@ -394,57 +461,22 @@ def __init__(
394461 if client_options is None :
395462 client_options = client_options_lib .ClientOptions ()
396463
397- # Create SSL credentials for mutual TLS if needed.
398- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
399- "true" ,
400- "false" ,
401- ):
402- raise ValueError (
403- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
404- )
405- use_client_cert = (
406- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
464+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
465+ client_options
407466 )
408467
409- client_cert_source_func = None
410- is_mtls = False
411- if use_client_cert :
412- if client_options .client_cert_source :
413- is_mtls = True
414- client_cert_source_func = client_options .client_cert_source
415- else :
416- is_mtls = mtls .has_default_client_cert_source ()
417- if is_mtls :
418- client_cert_source_func = mtls .default_client_cert_source ()
419- else :
420- client_cert_source_func = None
421-
422- # Figure out which api endpoint to use.
423- if client_options .api_endpoint is not None :
424- api_endpoint = client_options .api_endpoint
425- else :
426- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
427- if use_mtls_env == "never" :
428- api_endpoint = self .DEFAULT_ENDPOINT
429- elif use_mtls_env == "always" :
430- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
431- elif use_mtls_env == "auto" :
432- if is_mtls :
433- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
434- else :
435- api_endpoint = self .DEFAULT_ENDPOINT
436- else :
437- raise MutualTLSChannelError (
438- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
439- "values: never, auto, always"
440- )
468+ api_key_value = getattr (client_options , "api_key" , None )
469+ if api_key_value and credentials :
470+ raise ValueError (
471+ "client_options.api_key and credentials are mutually exclusive"
472+ )
441473
442474 # Save or instantiate the transport.
443475 # Ordinarily, we provide the transport, but allowing a custom transport
444476 # instance provides an extensibility point for unusual situations.
445477 if isinstance (transport , DataCatalogTransport ):
446478 # transport is a DataCatalogTransport instance.
447- if credentials or client_options .credentials_file :
479+ if credentials or client_options .credentials_file or api_key_value :
448480 raise ValueError (
449481 "When providing a transport instance, "
450482 "provide its credentials directly."
@@ -456,6 +488,15 @@ def __init__(
456488 )
457489 self ._transport = transport
458490 else :
491+ import google .auth ._default # type: ignore
492+
493+ if api_key_value and hasattr (
494+ google .auth ._default , "get_api_key_credentials"
495+ ):
496+ credentials = google .auth ._default .get_api_key_credentials (
497+ api_key_value
498+ )
499+
459500 Transport = type (self ).get_transport_class (transport )
460501 self ._transport = Transport (
461502 credentials = credentials ,
0 commit comments