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