@@ -236,6 +236,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
236236 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
237237 return m .groupdict () if m else {}
238238
239+ @classmethod
240+ def get_mtls_endpoint_and_cert_source (
241+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
242+ ):
243+ """Return the API endpoint and client cert source for mutual TLS.
244+
245+ The client cert source is determined in the following order:
246+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
247+ client cert source is None.
248+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
249+ default client cert source exists, use the default one; otherwise the client cert
250+ source is None.
251+
252+ The API endpoint is determined in the following order:
253+ (1) if `client_options.api_endpoint` if provided, use the provided one.
254+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
255+ default mTLS endpoint; if the environment variabel is "never", use the default API
256+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
257+ use the default API endpoint.
258+
259+ More details can be found at https://google.aip.dev/auth/4114.
260+
261+ Args:
262+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
263+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
264+ in this method.
265+
266+ Returns:
267+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
268+ client cert source to use.
269+
270+ Raises:
271+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
272+ """
273+ if client_options is None :
274+ client_options = client_options_lib .ClientOptions ()
275+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
276+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
277+ if use_client_cert not in ("true" , "false" ):
278+ raise ValueError (
279+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
280+ )
281+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
282+ raise MutualTLSChannelError (
283+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
284+ )
285+
286+ # Figure out the client cert source to use.
287+ client_cert_source = None
288+ if use_client_cert == "true" :
289+ if client_options .client_cert_source :
290+ client_cert_source = client_options .client_cert_source
291+ elif mtls .has_default_client_cert_source ():
292+ client_cert_source = mtls .default_client_cert_source ()
293+
294+ # Figure out which api endpoint to use.
295+ if client_options .api_endpoint is not None :
296+ api_endpoint = client_options .api_endpoint
297+ elif use_mtls_endpoint == "always" or (
298+ use_mtls_endpoint == "auto" and client_cert_source
299+ ):
300+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
301+ else :
302+ api_endpoint = cls .DEFAULT_ENDPOINT
303+
304+ return api_endpoint , client_cert_source
305+
239306 def __init__ (
240307 self ,
241308 * ,
@@ -286,57 +353,22 @@ def __init__(
286353 if client_options is None :
287354 client_options = client_options_lib .ClientOptions ()
288355
289- # Create SSL credentials for mutual TLS if needed.
290- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
291- "true" ,
292- "false" ,
293- ):
294- raise ValueError (
295- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
296- )
297- use_client_cert = (
298- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
356+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
357+ client_options
299358 )
300359
301- client_cert_source_func = None
302- is_mtls = False
303- if use_client_cert :
304- if client_options .client_cert_source :
305- is_mtls = True
306- client_cert_source_func = client_options .client_cert_source
307- else :
308- is_mtls = mtls .has_default_client_cert_source ()
309- if is_mtls :
310- client_cert_source_func = mtls .default_client_cert_source ()
311- else :
312- client_cert_source_func = None
313-
314- # Figure out which api endpoint to use.
315- if client_options .api_endpoint is not None :
316- api_endpoint = client_options .api_endpoint
317- else :
318- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
319- if use_mtls_env == "never" :
320- api_endpoint = self .DEFAULT_ENDPOINT
321- elif use_mtls_env == "always" :
322- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
323- elif use_mtls_env == "auto" :
324- if is_mtls :
325- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
326- else :
327- api_endpoint = self .DEFAULT_ENDPOINT
328- else :
329- raise MutualTLSChannelError (
330- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
331- "values: never, auto, always"
332- )
360+ api_key_value = getattr (client_options , "api_key" , None )
361+ if api_key_value and credentials :
362+ raise ValueError (
363+ "client_options.api_key and credentials are mutually exclusive"
364+ )
333365
334366 # Save or instantiate the transport.
335367 # Ordinarily, we provide the transport, but allowing a custom transport
336368 # instance provides an extensibility point for unusual situations.
337369 if isinstance (transport , BudgetServiceTransport ):
338370 # transport is a BudgetServiceTransport instance.
339- if credentials or client_options .credentials_file :
371+ if credentials or client_options .credentials_file or api_key_value :
340372 raise ValueError (
341373 "When providing a transport instance, "
342374 "provide its credentials directly."
@@ -348,6 +380,15 @@ def __init__(
348380 )
349381 self ._transport = transport
350382 else :
383+ import google .auth ._default # type: ignore
384+
385+ if api_key_value and hasattr (
386+ google .auth ._default , "get_api_key_credentials"
387+ ):
388+ credentials = google .auth ._default .get_api_key_credentials (
389+ api_key_value
390+ )
391+
351392 Transport = type (self ).get_transport_class (transport )
352393 self ._transport = Transport (
353394 credentials = credentials ,
0 commit comments