@@ -219,6 +219,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
219219 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
220220 return m .groupdict () if m else {}
221221
222+ @classmethod
223+ def get_mtls_endpoint_and_cert_source (
224+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
225+ ):
226+ """Return the API endpoint and client cert source for mutual TLS.
227+
228+ The client cert source is determined in the following order:
229+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
230+ client cert source is None.
231+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
232+ default client cert source exists, use the default one; otherwise the client cert
233+ source is None.
234+
235+ The API endpoint is determined in the following order:
236+ (1) if `client_options.api_endpoint` if provided, use the provided one.
237+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
238+ default mTLS endpoint; if the environment variabel is "never", use the default API
239+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
240+ use the default API endpoint.
241+
242+ More details can be found at https://google.aip.dev/auth/4114.
243+
244+ Args:
245+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
246+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
247+ in this method.
248+
249+ Returns:
250+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
251+ client cert source to use.
252+
253+ Raises:
254+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
255+ """
256+ if client_options is None :
257+ client_options = client_options_lib .ClientOptions ()
258+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
259+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
260+ if use_client_cert not in ("true" , "false" ):
261+ raise ValueError (
262+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
263+ )
264+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
265+ raise MutualTLSChannelError (
266+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
267+ )
268+
269+ # Figure out the client cert source to use.
270+ client_cert_source = None
271+ if use_client_cert == "true" :
272+ if client_options .client_cert_source :
273+ client_cert_source = client_options .client_cert_source
274+ elif mtls .has_default_client_cert_source ():
275+ client_cert_source = mtls .default_client_cert_source ()
276+
277+ # Figure out which api endpoint to use.
278+ if client_options .api_endpoint is not None :
279+ api_endpoint = client_options .api_endpoint
280+ elif use_mtls_endpoint == "always" or (
281+ use_mtls_endpoint == "auto" and client_cert_source
282+ ):
283+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
284+ else :
285+ api_endpoint = cls .DEFAULT_ENDPOINT
286+
287+ return api_endpoint , client_cert_source
288+
222289 def __init__ (
223290 self ,
224291 * ,
@@ -269,57 +336,22 @@ def __init__(
269336 if client_options is None :
270337 client_options = client_options_lib .ClientOptions ()
271338
272- # Create SSL credentials for mutual TLS if needed.
273- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
274- "true" ,
275- "false" ,
276- ):
277- raise ValueError (
278- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
279- )
280- use_client_cert = (
281- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
339+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
340+ client_options
282341 )
283342
284- client_cert_source_func = None
285- is_mtls = False
286- if use_client_cert :
287- if client_options .client_cert_source :
288- is_mtls = True
289- client_cert_source_func = client_options .client_cert_source
290- else :
291- is_mtls = mtls .has_default_client_cert_source ()
292- if is_mtls :
293- client_cert_source_func = mtls .default_client_cert_source ()
294- else :
295- client_cert_source_func = None
296-
297- # Figure out which api endpoint to use.
298- if client_options .api_endpoint is not None :
299- api_endpoint = client_options .api_endpoint
300- else :
301- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
302- if use_mtls_env == "never" :
303- api_endpoint = self .DEFAULT_ENDPOINT
304- elif use_mtls_env == "always" :
305- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
306- elif use_mtls_env == "auto" :
307- if is_mtls :
308- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
309- else :
310- api_endpoint = self .DEFAULT_ENDPOINT
311- else :
312- raise MutualTLSChannelError (
313- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
314- "values: never, auto, always"
315- )
343+ api_key_value = getattr (client_options , "api_key" , None )
344+ if api_key_value and credentials :
345+ raise ValueError (
346+ "client_options.api_key and credentials are mutually exclusive"
347+ )
316348
317349 # Save or instantiate the transport.
318350 # Ordinarily, we provide the transport, but allowing a custom transport
319351 # instance provides an extensibility point for unusual situations.
320352 if isinstance (transport , LanguageServiceTransport ):
321353 # transport is a LanguageServiceTransport instance.
322- if credentials or client_options .credentials_file :
354+ if credentials or client_options .credentials_file or api_key_value :
323355 raise ValueError (
324356 "When providing a transport instance, "
325357 "provide its credentials directly."
@@ -331,6 +363,15 @@ def __init__(
331363 )
332364 self ._transport = transport
333365 else :
366+ import google .auth ._default # type: ignore
367+
368+ if api_key_value and hasattr (
369+ google .auth ._default , "get_api_key_credentials"
370+ ):
371+ credentials = google .auth ._default .get_api_key_credentials (
372+ api_key_value
373+ )
374+
334375 Transport = type (self ).get_transport_class (transport )
335376 self ._transport = Transport (
336377 credentials = credentials ,
0 commit comments