Skip to content

Commit 63abf07

Browse files
authored
feat: add timeout parameter to public methods (#44)
* Add a default request timeout constant * Add timeout to ACL public methods * Add timeout to Blob methods * Add default timeout to Batch._do_request() * Add timeout to Bucket methods * Add timeout to Client methods * Add timeout to HMACKeyMetadata methods * Add timeout to BucketNotification methods * Add timeout to _PropertyMixin helpers
1 parent 64abf24 commit 63abf07

18 files changed

+869
-202
lines changed

google/cloud/storage/_helpers.py

+27-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
from hashlib import md5
2222
import os
2323

24+
from google.cloud.storage.constants import _DEFAULT_TIMEOUT
25+
26+
2427
STORAGE_EMULATOR_ENV_VAR = "STORAGE_EMULATOR_HOST"
2528
"""Environment variable defining host for Storage emulator."""
2629

@@ -117,7 +120,7 @@ def _query_params(self):
117120
params["userProject"] = self.user_project
118121
return params
119122

120-
def reload(self, client=None):
123+
def reload(self, client=None, timeout=_DEFAULT_TIMEOUT):
121124
"""Reload properties from Cloud Storage.
122125
123126
If :attr:`user_project` is set, bills the API request to that project.
@@ -126,6 +129,12 @@ def reload(self, client=None):
126129
``NoneType``
127130
:param client: the client to use. If not passed, falls back to the
128131
``client`` stored on the current object.
132+
:type timeout: float or tuple
133+
:param timeout: (optional) The amount of time, in seconds, to wait
134+
for the server response.
135+
136+
Can also be passed as a tuple (connect_timeout, read_timeout).
137+
See :meth:`requests.Session.request` documentation for details.
129138
"""
130139
client = self._require_client(client)
131140
query_params = self._query_params
@@ -138,6 +147,7 @@ def reload(self, client=None):
138147
query_params=query_params,
139148
headers=self._encryption_headers(),
140149
_target_object=self,
150+
timeout=timeout,
141151
)
142152
self._set_properties(api_response)
143153

@@ -169,7 +179,7 @@ def _set_properties(self, value):
169179
# If the values are reset, the changes must as well.
170180
self._changes = set()
171181

172-
def patch(self, client=None):
182+
def patch(self, client=None, timeout=_DEFAULT_TIMEOUT):
173183
"""Sends all changed properties in a PATCH request.
174184
175185
Updates the ``_properties`` with the response from the backend.
@@ -180,6 +190,12 @@ def patch(self, client=None):
180190
``NoneType``
181191
:param client: the client to use. If not passed, falls back to the
182192
``client`` stored on the current object.
193+
:type timeout: float or tuple
194+
:param timeout: (optional) The amount of time, in seconds, to wait
195+
for the server response.
196+
197+
Can also be passed as a tuple (connect_timeout, read_timeout).
198+
See :meth:`requests.Session.request` documentation for details.
183199
"""
184200
client = self._require_client(client)
185201
query_params = self._query_params
@@ -195,10 +211,11 @@ def patch(self, client=None):
195211
data=update_properties,
196212
query_params=query_params,
197213
_target_object=self,
214+
timeout=timeout,
198215
)
199216
self._set_properties(api_response)
200217

201-
def update(self, client=None):
218+
def update(self, client=None, timeout=_DEFAULT_TIMEOUT):
202219
"""Sends all properties in a PUT request.
203220
204221
Updates the ``_properties`` with the response from the backend.
@@ -209,6 +226,12 @@ def update(self, client=None):
209226
``NoneType``
210227
:param client: the client to use. If not passed, falls back to the
211228
``client`` stored on the current object.
229+
:type timeout: float or tuple
230+
:param timeout: (optional) The amount of time, in seconds, to wait
231+
for the server response.
232+
233+
Can also be passed as a tuple (connect_timeout, read_timeout).
234+
See :meth:`requests.Session.request` documentation for details.
212235
"""
213236
client = self._require_client(client)
214237
query_params = self._query_params
@@ -219,6 +242,7 @@ def update(self, client=None):
219242
data=self._properties,
220243
query_params=query_params,
221244
_target_object=self,
245+
timeout=timeout,
222246
)
223247
self._set_properties(api_response)
224248

google/cloud/storage/acl.py

+53-12
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
when sending metadata for ACLs to the API.
8080
"""
8181

82+
from google.cloud.storage.constants import _DEFAULT_TIMEOUT
83+
8284

8385
class _ACLEntity(object):
8486
"""Class representing a set of roles for an entity.
@@ -206,10 +208,18 @@ class ACL(object):
206208
def __init__(self):
207209
self.entities = {}
208210

209-
def _ensure_loaded(self):
210-
"""Load if not already loaded."""
211+
def _ensure_loaded(self, timeout=_DEFAULT_TIMEOUT):
212+
"""Load if not already loaded.
213+
214+
:type timeout: float or tuple
215+
:param timeout: (optional) The amount of time, in seconds, to wait
216+
for the server response.
217+
218+
Can also be passed as a tuple (connect_timeout, read_timeout).
219+
See :meth:`requests.Session.request` documentation for details.
220+
"""
211221
if not self.loaded:
212-
self.reload()
222+
self.reload(timeout=timeout)
213223

214224
@classmethod
215225
def validate_predefined(cls, predefined):
@@ -415,7 +425,7 @@ def _require_client(self, client):
415425
client = self.client
416426
return client
417427

418-
def reload(self, client=None):
428+
def reload(self, client=None, timeout=_DEFAULT_TIMEOUT):
419429
"""Reload the ACL data from Cloud Storage.
420430
421431
If :attr:`user_project` is set, bills the API request to that project.
@@ -424,6 +434,12 @@ def reload(self, client=None):
424434
``NoneType``
425435
:param client: Optional. The client to use. If not passed, falls back
426436
to the ``client`` stored on the ACL's parent.
437+
:type timeout: float or tuple
438+
:param timeout: (optional) The amount of time, in seconds, to wait
439+
for the server response.
440+
441+
Can also be passed as a tuple (connect_timeout, read_timeout).
442+
See :meth:`requests.Session.request` documentation for details.
427443
"""
428444
path = self.reload_path
429445
client = self._require_client(client)
@@ -435,13 +451,13 @@ def reload(self, client=None):
435451
self.entities.clear()
436452

437453
found = client._connection.api_request(
438-
method="GET", path=path, query_params=query_params
454+
method="GET", path=path, query_params=query_params, timeout=timeout
439455
)
440456
self.loaded = True
441457
for entry in found.get("items", ()):
442458
self.add_entity(self.entity_from_dict(entry))
443459

444-
def _save(self, acl, predefined, client):
460+
def _save(self, acl, predefined, client, timeout=_DEFAULT_TIMEOUT):
445461
"""Helper for :meth:`save` and :meth:`save_predefined`.
446462
447463
:type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list.
@@ -457,6 +473,12 @@ def _save(self, acl, predefined, client):
457473
``NoneType``
458474
:param client: Optional. The client to use. If not passed, falls back
459475
to the ``client`` stored on the ACL's parent.
476+
:type timeout: float or tuple
477+
:param timeout: (optional) The amount of time, in seconds, to wait
478+
for the server response.
479+
480+
Can also be passed as a tuple (connect_timeout, read_timeout).
481+
See :meth:`requests.Session.request` documentation for details.
460482
"""
461483
query_params = {"projection": "full"}
462484
if predefined is not None:
@@ -474,13 +496,14 @@ def _save(self, acl, predefined, client):
474496
path=path,
475497
data={self._URL_PATH_ELEM: list(acl)},
476498
query_params=query_params,
499+
timeout=timeout,
477500
)
478501
self.entities.clear()
479502
for entry in result.get(self._URL_PATH_ELEM, ()):
480503
self.add_entity(self.entity_from_dict(entry))
481504
self.loaded = True
482505

483-
def save(self, acl=None, client=None):
506+
def save(self, acl=None, client=None, timeout=_DEFAULT_TIMEOUT):
484507
"""Save this ACL for the current bucket.
485508
486509
If :attr:`user_project` is set, bills the API request to that project.
@@ -493,6 +516,12 @@ def save(self, acl=None, client=None):
493516
``NoneType``
494517
:param client: Optional. The client to use. If not passed, falls back
495518
to the ``client`` stored on the ACL's parent.
519+
:type timeout: float or tuple
520+
:param timeout: (optional) The amount of time, in seconds, to wait
521+
for the server response.
522+
523+
Can also be passed as a tuple (connect_timeout, read_timeout).
524+
See :meth:`requests.Session.request` documentation for details.
496525
"""
497526
if acl is None:
498527
acl = self
@@ -501,9 +530,9 @@ def save(self, acl=None, client=None):
501530
save_to_backend = True
502531

503532
if save_to_backend:
504-
self._save(acl, None, client)
533+
self._save(acl, None, client, timeout=timeout)
505534

506-
def save_predefined(self, predefined, client=None):
535+
def save_predefined(self, predefined, client=None, timeout=_DEFAULT_TIMEOUT):
507536
"""Save this ACL for the current bucket using a predefined ACL.
508537
509538
If :attr:`user_project` is set, bills the API request to that project.
@@ -519,11 +548,17 @@ def save_predefined(self, predefined, client=None):
519548
``NoneType``
520549
:param client: Optional. The client to use. If not passed, falls back
521550
to the ``client`` stored on the ACL's parent.
551+
:type timeout: float or tuple
552+
:param timeout: (optional) The amount of time, in seconds, to wait
553+
for the server response.
554+
555+
Can also be passed as a tuple (connect_timeout, read_timeout).
556+
See :meth:`requests.Session.request` documentation for details.
522557
"""
523558
predefined = self.validate_predefined(predefined)
524-
self._save(None, predefined, client)
559+
self._save(None, predefined, client, timeout=timeout)
525560

526-
def clear(self, client=None):
561+
def clear(self, client=None, timeout=_DEFAULT_TIMEOUT):
527562
"""Remove all ACL entries.
528563
529564
If :attr:`user_project` is set, bills the API request to that project.
@@ -537,8 +572,14 @@ def clear(self, client=None):
537572
``NoneType``
538573
:param client: Optional. The client to use. If not passed, falls back
539574
to the ``client`` stored on the ACL's parent.
575+
:type timeout: float or tuple
576+
:param timeout: (optional) The amount of time, in seconds, to wait
577+
for the server response.
578+
579+
Can also be passed as a tuple (connect_timeout, read_timeout).
580+
See :meth:`requests.Session.request` documentation for details.
540581
"""
541-
self.save([], client=client)
582+
self.save([], client=client, timeout=timeout)
542583

543584

544585
class BucketACL(ACL):

google/cloud/storage/batch.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from google.cloud import _helpers
3030
from google.cloud import exceptions
3131
from google.cloud.storage._http import Connection
32+
from google.cloud.storage.constants import _DEFAULT_TIMEOUT
3233

3334

3435
class MIMEApplicationHTTP(MIMEApplication):
@@ -150,7 +151,9 @@ def __init__(self, client):
150151
self._requests = []
151152
self._target_objects = []
152153

153-
def _do_request(self, method, url, headers, data, target_object, timeout=None):
154+
def _do_request(
155+
self, method, url, headers, data, target_object, timeout=_DEFAULT_TIMEOUT
156+
):
154157
"""Override Connection: defer actual HTTP request.
155158
156159
Only allow up to ``_MAX_BATCH_SIZE`` requests to be deferred.
@@ -175,7 +178,8 @@ def _do_request(self, method, url, headers, data, target_object, timeout=None):
175178
176179
:type timeout: float or tuple
177180
:param timeout: (optional) The amount of time, in seconds, to wait
178-
for the server response. By default, the method waits indefinitely.
181+
for the server response.
182+
179183
Can also be passed as a tuple (connect_timeout, read_timeout).
180184
See :meth:`requests.Session.request` documentation for details.
181185
@@ -206,8 +210,8 @@ def _prepare_batch_request(self):
206210

207211
multi = MIMEMultipart()
208212

209-
# Use timeout of last request, default to None (indefinite)
210-
timeout = None
213+
# Use timeout of last request, default to _DEFAULT_TIMEOUT
214+
timeout = _DEFAULT_TIMEOUT
211215
for method, uri, headers, body, _timeout in self._requests:
212216
subrequest = MIMEApplicationHTTP(method, uri, headers, body)
213217
multi.attach(subrequest)

0 commit comments

Comments
 (0)