30
30
# Standard library imports
31
31
import copy
32
32
from collections import OrderedDict
33
+
33
34
try :
34
35
from email .generator import BytesGenerator
35
36
except ImportError :
@@ -260,14 +261,17 @@ def build(
260
261
else :
261
262
discovery_http = http
262
263
263
- for discovery_url in \
264
- _discovery_service_uri_options (discoveryServiceUrl , version ):
264
+ for discovery_url in _discovery_service_uri_options (discoveryServiceUrl , version ):
265
265
requested_url = uritemplate .expand (discovery_url , params )
266
266
267
267
try :
268
268
content = _retrieve_discovery_doc (
269
- requested_url , discovery_http , cache_discovery , cache ,
270
- developerKey , num_retries = num_retries
269
+ requested_url ,
270
+ discovery_http ,
271
+ cache_discovery ,
272
+ cache ,
273
+ developerKey ,
274
+ num_retries = num_retries ,
271
275
)
272
276
return build_from_document (
273
277
content ,
@@ -308,13 +312,15 @@ def _discovery_service_uri_options(discoveryServiceUrl, version):
308
312
# V1 Discovery won't work if the requested version is None
309
313
if discoveryServiceUrl == V1_DISCOVERY_URI and version is None :
310
314
logger .warning (
311
- "Discovery V1 does not support empty versions. Defaulting to V2..." )
315
+ "Discovery V1 does not support empty versions. Defaulting to V2..."
316
+ )
312
317
urls .pop (0 )
313
318
return list (OrderedDict .fromkeys (urls ))
314
319
315
320
316
- def _retrieve_discovery_doc (url , http , cache_discovery ,
317
- cache = None , developerKey = None , num_retries = 1 ):
321
+ def _retrieve_discovery_doc (
322
+ url , http , cache_discovery , cache = None , developerKey = None , num_retries = 1
323
+ ):
318
324
"""Retrieves the discovery_doc from cache or the internet.
319
325
320
326
Args:
@@ -444,8 +450,20 @@ def build_from_document(
444
450
setting up mutual TLS channel.
445
451
"""
446
452
447
- if http is not None and credentials is not None :
448
- raise ValueError ("Arguments http and credentials are mutually exclusive." )
453
+ if client_options is None :
454
+ client_options = google .api_core .client_options .ClientOptions ()
455
+ if isinstance (client_options , six .moves .collections_abc .Mapping ):
456
+ client_options = google .api_core .client_options .from_dict (client_options )
457
+
458
+ if http is not None :
459
+ # if http is passed, the user cannot provide credentials
460
+ banned_options = [
461
+ (credentials , "credentials" ),
462
+ (client_options .credentials_file , "client_options.credentials_file" ),
463
+ ]
464
+ for option , name in banned_options :
465
+ if option is not None :
466
+ raise ValueError ("Arguments http and {} are mutually exclusive" .format (name ))
449
467
450
468
if isinstance (service , six .string_types ):
451
469
service = json .loads (service )
@@ -463,11 +481,8 @@ def build_from_document(
463
481
464
482
# If an API Endpoint is provided on client options, use that as the base URL
465
483
base = urljoin (service ["rootUrl" ], service ["servicePath" ])
466
- if client_options :
467
- if isinstance (client_options , six .moves .collections_abc .Mapping ):
468
- client_options = google .api_core .client_options .from_dict (client_options )
469
- if client_options .api_endpoint :
470
- base = client_options .api_endpoint
484
+ if client_options .api_endpoint :
485
+ base = client_options .api_endpoint
471
486
472
487
schema = Schemas (service )
473
488
@@ -483,13 +498,30 @@ def build_from_document(
483
498
# If so, then the we need to setup authentication if no developerKey is
484
499
# specified.
485
500
if scopes and not developerKey :
501
+ # Make sure the user didn't pass multiple credentials
502
+ if client_options .credentials_file and credentials :
503
+ raise google .api_core .exceptions .DuplicateCredentialArgs (
504
+ "client_options.credentials_file and credentials are mutually exclusive."
505
+ )
506
+ # Check for credentials file via client options
507
+ if client_options .credentials_file :
508
+ credentials = _auth .credentials_from_file (
509
+ client_options .credentials_file ,
510
+ scopes = client_options .scopes ,
511
+ quota_project_id = client_options .quota_project_id ,
512
+ )
486
513
# If the user didn't pass in credentials, attempt to acquire application
487
514
# default credentials.
488
515
if credentials is None :
489
- credentials = _auth .default_credentials ()
516
+ credentials = _auth .default_credentials (
517
+ scopes = client_options .scopes ,
518
+ quota_project_id = client_options .quota_project_id ,
519
+ )
490
520
491
521
# The credentials need to be scoped.
492
- credentials = _auth .with_scopes (credentials , scopes )
522
+ # If the user provided scopes via client_options don't override them
523
+ if not client_options .scopes :
524
+ credentials = _auth .with_scopes (credentials , scopes )
493
525
494
526
# If credentials are provided, create an authorized http instance;
495
527
# otherwise, skip authentication.
@@ -519,7 +551,9 @@ def build_from_document(
519
551
and client_options .client_encrypted_cert_source
520
552
):
521
553
client_cert_to_use = client_options .client_encrypted_cert_source
522
- elif adc_cert_path and adc_key_path and mtls .has_default_client_cert_source ():
554
+ elif (
555
+ adc_cert_path and adc_key_path and mtls .has_default_client_cert_source ()
556
+ ):
523
557
client_cert_to_use = mtls .default_client_encrypted_cert_source (
524
558
adc_cert_path , adc_key_path
525
559
)
0 commit comments