Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.

Commit e96f852

Browse files
authored
refactor: add / use 'Client._patch_resource' method (#436)
Add retry support to 'ACL.save', 'ACL.save_predefined', and 'ACL.clear'. Add 'timeout' and 'retry' support to 'Blob.make_private'. Toward #38.
1 parent e0f1b71 commit e96f852

File tree

10 files changed

+936
-497
lines changed

10 files changed

+936
-497
lines changed

google/cloud/storage/_helpers.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,9 @@ def patch(
331331
update_properties = {key: self._properties[key] for key in self._changes}
332332

333333
# Make the API call.
334-
api_response = client._connection.api_request(
335-
method="PATCH",
336-
path=self.path,
337-
data=update_properties,
334+
api_response = client._patch_resource(
335+
self.path,
336+
update_properties,
338337
query_params=query_params,
339338
_target_object=self,
340339
timeout=timeout,

google/cloud/storage/acl.py

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,9 @@ def reload(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY):
474474
for entry in found.get("items", ()):
475475
self.add_entity(self.entity_from_dict(entry))
476476

477-
def _save(self, acl, predefined, client, timeout=_DEFAULT_TIMEOUT):
477+
def _save(
478+
self, acl, predefined, client, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY,
479+
):
478480
"""Helper for :meth:`save` and :meth:`save_predefined`.
479481
480482
:type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list.
@@ -495,8 +497,19 @@ def _save(self, acl, predefined, client, timeout=_DEFAULT_TIMEOUT):
495497
496498
Can also be passed as a tuple (connect_timeout, read_timeout).
497499
See :meth:`requests.Session.request` documentation for details.
500+
501+
:type retry: :class:`~google.api_core.retry.Retry`
502+
:param retry: (Optional) How to retry the RPC.
503+
504+
A None value will disable retries.
505+
506+
A google.api_core.retry.Retry value will enable retries,
507+
and the object will define retriable response codes and errors
508+
and configure backoff and timeout options.
498509
"""
510+
client = self._require_client(client)
499511
query_params = {"projection": "full"}
512+
500513
if predefined is not None:
501514
acl = []
502515
query_params[self._PREDEFINED_QUERY_PARAM] = predefined
@@ -505,21 +518,25 @@ def _save(self, acl, predefined, client, timeout=_DEFAULT_TIMEOUT):
505518
query_params["userProject"] = self.user_project
506519

507520
path = self.save_path
508-
client = self._require_client(client)
509521

510-
result = client._connection.api_request(
511-
method="PATCH",
512-
path=path,
513-
data={self._URL_PATH_ELEM: list(acl)},
522+
result = client._patch_resource(
523+
path,
524+
{self._URL_PATH_ELEM: list(acl)},
514525
query_params=query_params,
515526
timeout=timeout,
527+
retry=retry,
516528
)
529+
517530
self.entities.clear()
531+
518532
for entry in result.get(self._URL_PATH_ELEM, ()):
519533
self.add_entity(self.entity_from_dict(entry))
534+
520535
self.loaded = True
521536

522-
def save(self, acl=None, client=None, timeout=_DEFAULT_TIMEOUT):
537+
def save(
538+
self, acl=None, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY
539+
):
523540
"""Save this ACL for the current bucket.
524541
525542
If :attr:`user_project` is set, bills the API request to that project.
@@ -538,6 +555,15 @@ def save(self, acl=None, client=None, timeout=_DEFAULT_TIMEOUT):
538555
539556
Can also be passed as a tuple (connect_timeout, read_timeout).
540557
See :meth:`requests.Session.request` documentation for details.
558+
559+
:type retry: :class:`~google.api_core.retry.Retry`
560+
:param retry: (Optional) How to retry the RPC.
561+
562+
A None value will disable retries.
563+
564+
A google.api_core.retry.Retry value will enable retries,
565+
and the object will define retriable response codes and errors
566+
and configure backoff and timeout options.
541567
"""
542568
if acl is None:
543569
acl = self
@@ -546,9 +572,11 @@ def save(self, acl=None, client=None, timeout=_DEFAULT_TIMEOUT):
546572
save_to_backend = True
547573

548574
if save_to_backend:
549-
self._save(acl, None, client, timeout=timeout)
575+
self._save(acl, None, client, timeout=timeout, retry=retry)
550576

551-
def save_predefined(self, predefined, client=None, timeout=_DEFAULT_TIMEOUT):
577+
def save_predefined(
578+
self, predefined, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY,
579+
):
552580
"""Save this ACL for the current bucket using a predefined ACL.
553581
554582
If :attr:`user_project` is set, bills the API request to that project.
@@ -570,11 +598,20 @@ def save_predefined(self, predefined, client=None, timeout=_DEFAULT_TIMEOUT):
570598
571599
Can also be passed as a tuple (connect_timeout, read_timeout).
572600
See :meth:`requests.Session.request` documentation for details.
601+
602+
:type retry: :class:`~google.api_core.retry.Retry`
603+
:param retry: (Optional) How to retry the RPC.
604+
605+
A None value will disable retries.
606+
607+
A google.api_core.retry.Retry value will enable retries,
608+
and the object will define retriable response codes and errors
609+
and configure backoff and timeout options.
573610
"""
574611
predefined = self.validate_predefined(predefined)
575-
self._save(None, predefined, client, timeout=timeout)
612+
self._save(None, predefined, client, timeout=timeout, retry=retry)
576613

577-
def clear(self, client=None, timeout=_DEFAULT_TIMEOUT):
614+
def clear(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY):
578615
"""Remove all ACL entries.
579616
580617
If :attr:`user_project` is set, bills the API request to that project.
@@ -594,8 +631,17 @@ def clear(self, client=None, timeout=_DEFAULT_TIMEOUT):
594631
595632
Can also be passed as a tuple (connect_timeout, read_timeout).
596633
See :meth:`requests.Session.request` documentation for details.
634+
635+
:type retry: :class:`~google.api_core.retry.Retry`
636+
:param retry: (Optional) How to retry the RPC.
637+
638+
A None value will disable retries.
639+
640+
A google.api_core.retry.Retry value will enable retries,
641+
and the object will define retriable response codes and errors
642+
and configure backoff and timeout options.
597643
"""
598-
self.save([], client=client, timeout=timeout)
644+
self.save([], client=client, timeout=timeout, retry=retry)
599645

600646

601647
class BucketACL(ACL):

google/cloud/storage/blob.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2978,27 +2978,75 @@ def test_iam_permissions(
29782978

29792979
return resp.get("permissions", [])
29802980

2981-
def make_public(self, client=None):
2981+
def make_public(
2982+
self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY,
2983+
):
29822984
"""Update blob's ACL, granting read access to anonymous users.
29832985
29842986
:type client: :class:`~google.cloud.storage.client.Client` or
29852987
``NoneType``
29862988
:param client: (Optional) The client to use. If not passed, falls back
29872989
to the ``client`` stored on the blob's bucket.
2990+
2991+
:type timeout: float or tuple
2992+
:param timeout: (Optional) The amount of time, in seconds, to wait
2993+
for the server response. The timeout applies to each underlying
2994+
request.
2995+
2996+
Can also be passed as a tuple (connect_timeout, read_timeout).
2997+
See :meth:`requests.Session.request` documentation for details.
2998+
2999+
:type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
3000+
:param retry: (Optional) How to retry the RPC. A None value will disable retries.
3001+
A google.api_core.retry.Retry value will enable retries, and the object will
3002+
define retriable response codes and errors and configure backoff and timeout options.
3003+
3004+
A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and
3005+
activates it only if certain conditions are met. This class exists to provide safe defaults
3006+
for RPC calls that are not technically safe to retry normally (due to potential data
3007+
duplication or other side-effects) but become safe to retry if a condition such as
3008+
if_metageneration_match is set.
3009+
3010+
See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for
3011+
information on retry types and how to configure them.
29883012
"""
29893013
self.acl.all().grant_read()
2990-
self.acl.save(client=client)
3014+
self.acl.save(client=client, timeout=timeout, retry=retry)
29913015

2992-
def make_private(self, client=None):
3016+
def make_private(
3017+
self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY,
3018+
):
29933019
"""Update blob's ACL, revoking read access for anonymous users.
29943020
29953021
:type client: :class:`~google.cloud.storage.client.Client` or
29963022
``NoneType``
29973023
:param client: (Optional) The client to use. If not passed, falls back
29983024
to the ``client`` stored on the blob's bucket.
3025+
3026+
:type timeout: float or tuple
3027+
:param timeout: (Optional) The amount of time, in seconds, to wait
3028+
for the server response. The timeout applies to each underlying
3029+
request.
3030+
3031+
Can also be passed as a tuple (connect_timeout, read_timeout).
3032+
See :meth:`requests.Session.request` documentation for details.
3033+
3034+
:type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
3035+
:param retry: (Optional) How to retry the RPC. A None value will disable retries.
3036+
A google.api_core.retry.Retry value will enable retries, and the object will
3037+
define retriable response codes and errors and configure backoff and timeout options.
3038+
3039+
A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and
3040+
activates it only if certain conditions are met. This class exists to provide safe defaults
3041+
for RPC calls that are not technically safe to retry normally (due to potential data
3042+
duplication or other side-effects) but become safe to retry if a condition such as
3043+
if_metageneration_match is set.
3044+
3045+
See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for
3046+
information on retry types and how to configure them.
29993047
"""
30003048
self.acl.all().revoke_read()
3001-
self.acl.save(client=client)
3049+
self.acl.save(client=client, timeout=timeout, retry=retry)
30023050

30033051
def compose(
30043052
self,

google/cloud/storage/bucket.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,9 +1065,9 @@ def patch(
10651065
# Call the superclass method.
10661066
super(Bucket, self).patch(
10671067
client=client,
1068-
timeout=timeout,
10691068
if_metageneration_match=if_metageneration_match,
10701069
if_metageneration_not_match=if_metageneration_not_match,
1070+
timeout=timeout,
10711071
retry=retry,
10721072
)
10731073

@@ -1993,7 +1993,7 @@ def copy_blob(
19931993
)
19941994

19951995
if not preserve_acl:
1996-
new_blob.acl.save(acl={}, client=client, timeout=timeout)
1996+
new_blob.acl.save(acl={}, client=client, timeout=timeout, retry=retry)
19971997

19981998
new_blob._set_properties(copy_result)
19991999
return new_blob
@@ -3068,7 +3068,7 @@ def make_public(
30683068
for each blob.
30693069
"""
30703070
self.acl.all().grant_read()
3071-
self.acl.save(client=client, timeout=timeout)
3071+
self.acl.save(client=client, timeout=timeout, retry=retry)
30723072

30733073
if future:
30743074
doa = self.default_object_acl
@@ -3099,7 +3099,7 @@ def make_public(
30993099

31003100
for blob in blobs:
31013101
blob.acl.all().grant_read()
3102-
blob.acl.save(client=client, timeout=timeout)
3102+
blob.acl.save(client=client, timeout=timeout, retry=retry)
31033103

31043104
def make_private(
31053105
self,
@@ -3155,7 +3155,7 @@ def make_private(
31553155
for each blob.
31563156
"""
31573157
self.acl.all().revoke_read()
3158-
self.acl.save(client=client, timeout=timeout)
3158+
self.acl.save(client=client, timeout=timeout, retry=retry)
31593159

31603160
if future:
31613161
doa = self.default_object_acl
@@ -3186,7 +3186,7 @@ def make_private(
31863186

31873187
for blob in blobs:
31883188
blob.acl.all().revoke_read()
3189-
blob.acl.save(client=client, timeout=timeout)
3189+
blob.acl.save(client=client, timeout=timeout, retry=retry)
31903190

31913191
def generate_upload_policy(self, conditions, expiration=None, client=None):
31923192
"""Create a signed upload policy for uploading objects.

google/cloud/storage/client.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,77 @@ def _get_resource(
386386
_target_object=_target_object,
387387
)
388388

389+
def _patch_resource(
390+
self,
391+
path,
392+
data,
393+
query_params=None,
394+
headers=None,
395+
timeout=_DEFAULT_TIMEOUT,
396+
retry=DEFAULT_RETRY,
397+
_target_object=None,
398+
):
399+
"""Helper for bucket / blob methods making API 'PATCH' calls.
400+
401+
Args:
402+
path str:
403+
The path of the resource to fetch.
404+
405+
data dict:
406+
The data to be patched.
407+
408+
query_params Optional[dict]:
409+
HTTP query parameters to be passed
410+
411+
headers Optional[dict]:
412+
HTTP headers to be passed
413+
414+
timeout (Optional[Union[float, Tuple[float, float]]]):
415+
The amount of time, in seconds, to wait for the server response.
416+
417+
Can also be passed as a tuple (connect_timeout, read_timeout).
418+
See :meth:`requests.Session.request` documentation for details.
419+
420+
retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]):
421+
How to retry the RPC. A None value will disable retries.
422+
A google.api_core.retry.Retry value will enable retries, and the object will
423+
define retriable response codes and errors and configure backoff and timeout options.
424+
425+
A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and
426+
activates it only if certain conditions are met. This class exists to provide safe defaults
427+
for RPC calls that are not technically safe to retry normally (due to potential data
428+
duplication or other side-effects) but become safe to retry if a condition such as
429+
if_metageneration_match is set.
430+
431+
See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for
432+
information on retry types and how to configure them.
433+
434+
_target_object (Union[ \
435+
:class:`~google.cloud.storage.bucket.Bucket`, \
436+
:class:`~google.cloud.storage.bucket.blob`, \
437+
]):
438+
Object to which future data is to be applied -- only relevant
439+
in the context of a batch.
440+
441+
Returns:
442+
dict
443+
The JSON resource fetched
444+
445+
Raises:
446+
google.cloud.exceptions.NotFound
447+
If the bucket is not found.
448+
"""
449+
return self._connection.api_request(
450+
method="PATCH",
451+
path=path,
452+
data=data,
453+
query_params=query_params,
454+
headers=headers,
455+
timeout=timeout,
456+
retry=retry,
457+
_target_object=_target_object,
458+
)
459+
389460
def get_bucket(
390461
self,
391462
bucket_or_name,

0 commit comments

Comments
 (0)