Skip to content

Commit 130a961

Browse files
committed
feat: Add support for static discovery documents
1 parent af918e8 commit 130a961

File tree

2 files changed

+75
-19
lines changed

2 files changed

+75
-19
lines changed

googleapiclient/discovery.py

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ def build(
193193
adc_cert_path=None,
194194
adc_key_path=None,
195195
num_retries=1,
196+
static_discovery=True,
196197
):
197198
"""Construct a Resource for interacting with an API.
198199
@@ -246,6 +247,9 @@ def build(
246247
https://google.aip.dev/auth/4114
247248
num_retries: Integer, number of times to retry discovery with
248249
randomized exponential backoff in case of intermittent/connection issues.
250+
static_discovery: Boolean, whether or not to use the static discovery docs
251+
included in the package when the discovery doc is not available in the
252+
cache.
249253
250254
Returns:
251255
A Resource object with methods for interacting with the service.
@@ -274,6 +278,7 @@ def build(
274278
cache,
275279
developerKey,
276280
num_retries=num_retries,
281+
static_discovery=static_discovery,
277282
)
278283
service = build_from_document(
279284
content,
@@ -330,7 +335,13 @@ def _discovery_service_uri_options(discoveryServiceUrl, version):
330335

331336

332337
def _retrieve_discovery_doc(
333-
url, http, cache_discovery, cache=None, developerKey=None, num_retries=1
338+
url,
339+
http,
340+
cache_discovery,
341+
cache=None,
342+
developerKey=None,
343+
num_retries=1,
344+
static_discovery=True
334345
):
335346
"""Retrieves the discovery_doc from cache or the internet.
336347
@@ -345,35 +356,48 @@ def _retrieve_discovery_doc(
345356
from the API Console.
346357
num_retries: Integer, number of times to retry discovery with
347358
randomized exponential backoff in case of intermittent/connection issues.
359+
static_discovery: Boolean, whether or not to use the static discovery docs
360+
included in the package when the discovery doc is not available in the
361+
cache.
348362
349363
Returns:
350364
A unicode string representation of the discovery document.
351365
"""
352-
if cache_discovery:
353-
from . import discovery_cache
366+
from . import discovery_cache
367+
368+
content = None
354369

370+
if cache_discovery:
355371
if cache is None:
356372
cache = discovery_cache.autodetect()
357373
if cache:
358374
content = cache.get(url)
359375
if content:
360376
return content
361377

362-
actual_url = url
363-
# REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
364-
# variable that contains the network address of the client sending the
365-
# request. If it exists then add that to the request for the discovery
366-
# document to avoid exceeding the quota on discovery requests.
367-
if "REMOTE_ADDR" in os.environ:
368-
actual_url = _add_query_parameter(url, "userIp", os.environ["REMOTE_ADDR"])
369-
if developerKey:
370-
actual_url = _add_query_parameter(url, "key", developerKey)
371-
logger.debug("URL being requested: GET %s", actual_url)
372-
373-
# Execute this request with retries build into HttpRequest
374-
# Note that it will already raise an error if we don't get a 2xx response
375-
req = HttpRequest(http, HttpRequest.null_postproc, actual_url)
376-
resp, content = req.execute(num_retries=num_retries)
378+
# At this point, the discovery document was not found in the cache so
379+
# we can attempt to retreive the static discovery document from the library.
380+
if static_discovery:
381+
content = discovery_cache.get_static_doc(url)
382+
383+
# If the content is None, retrieve the discovery doc from the internet
384+
# because it is not in the cache or the static doc directory.
385+
if content is None:
386+
actual_url = url
387+
# REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
388+
# variable that contains the network address of the client sending the
389+
# request. If it exists then add that to the request for the discovery
390+
# document to avoid exceeding the quota on discovery requests.
391+
if "REMOTE_ADDR" in os.environ:
392+
actual_url = _add_query_parameter(url, "userIp", os.environ["REMOTE_ADDR"])
393+
if developerKey:
394+
actual_url = _add_query_parameter(url, "key", developerKey)
395+
logger.debug("URL being requested: GET %s", actual_url)
396+
397+
# Execute this request with retries build into HttpRequest
398+
# Note that it will already raise an error if we don't get a 2xx response
399+
req = HttpRequest(http, HttpRequest.null_postproc, actual_url)
400+
resp, content = req.execute(num_retries=num_retries)
377401

378402
try:
379403
content = content.decode("utf-8")

googleapiclient/discovery_cache/__init__.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
LOGGER = logging.getLogger(__name__)
2424

2525
DISCOVERY_DOC_MAX_AGE = 60 * 60 * 24 # 1 day
26-
26+
DISCOVERY_DOC_DIR = os.path.join(os.path.dirname(
27+
os.path.realpath(__file__)), 'documents')
2728

2829
def autodetect():
2930
"""Detects an appropriate cache module and returns it.
@@ -47,3 +48,34 @@ def autodetect():
4748
except Exception as e:
4849
LOGGER.warning(e, exc_info=True)
4950
return None
51+
52+
def get_static_doc(uri):
53+
"""Retrieves the discovery document from the directory defined in
54+
DISCOVERY_DOC_STATIC_DIR corresponding to the uri provided.
55+
56+
Args:
57+
uri: string, The URI of the discovery document in the format
58+
https://{domain}/discovery/{discoveryVer}/apis/{api}/{apiVersion}/rest
59+
60+
Returns:
61+
A string containing the contents of the JSON discovery document,
62+
otherwise None if the JSON discovery document was not found.
63+
"""
64+
65+
doc_name = None
66+
67+
# Extract the {apiVersion} and {api} from the uri which are the 2nd and 3rd
68+
# last parts of the uri respectively.
69+
# https://www.googleapis.com/discovery/v1/apis/{api}/{apiVersion}/rest
70+
uri_parts = uri.split('/')
71+
if len(uri_parts) > 3:
72+
doc_name = "{}.{}.json".format(uri_parts[-3], uri_parts[-2])
73+
74+
try:
75+
with open(os.path.join(DISCOVERY_DOC_DIR, doc_name), 'r') as f:
76+
content = f.read()
77+
except FileNotFoundError:
78+
content = None
79+
80+
return content
81+

0 commit comments

Comments
 (0)