30
30
from google .cloud .client import ClientWithProject
31
31
from google .cloud .exceptions import NotFound
32
32
33
+ from google .cloud .storage ._helpers import _add_generation_match_parameters
33
34
from google .cloud .storage ._helpers import _bucket_bound_hostname_url
34
35
from google .cloud .storage ._helpers import _get_api_endpoint_override
35
36
from google .cloud .storage ._helpers import _get_environ_project
@@ -367,7 +368,7 @@ def get_service_account_email(
367
368
api_response = self ._get_resource (path , timeout = timeout , retry = retry )
368
369
return api_response ["email_address" ]
369
370
370
- def bucket (self , bucket_name , user_project = None ):
371
+ def bucket (self , bucket_name , user_project = None , generation = None ):
371
372
"""Factory constructor for bucket object.
372
373
373
374
.. note::
@@ -381,10 +382,19 @@ def bucket(self, bucket_name, user_project=None):
381
382
:param user_project: (Optional) The project ID to be billed for API
382
383
requests made via the bucket.
383
384
385
+ :type generation: int
386
+ :param generation: (Optional) If present, selects a specific revision of
387
+ this bucket.
388
+
384
389
:rtype: :class:`google.cloud.storage.bucket.Bucket`
385
390
:returns: The bucket object created.
386
391
"""
387
- return Bucket (client = self , name = bucket_name , user_project = user_project )
392
+ return Bucket (
393
+ client = self ,
394
+ name = bucket_name ,
395
+ user_project = user_project ,
396
+ generation = generation ,
397
+ )
388
398
389
399
def batch (self , raise_exception = True ):
390
400
"""Factory constructor for batch object.
@@ -789,7 +799,7 @@ def _delete_resource(
789
799
_target_object = _target_object ,
790
800
)
791
801
792
- def _bucket_arg_to_bucket (self , bucket_or_name ):
802
+ def _bucket_arg_to_bucket (self , bucket_or_name , generation = None ):
793
803
"""Helper to return given bucket or create new by name.
794
804
795
805
Args:
@@ -798,17 +808,27 @@ def _bucket_arg_to_bucket(self, bucket_or_name):
798
808
str, \
799
809
]):
800
810
The bucket resource to pass or name to create.
811
+ generation (Optional[int]):
812
+ The bucket generation. If generation is specified,
813
+ bucket_or_name must be a name (str).
801
814
802
815
Returns:
803
816
google.cloud.storage.bucket.Bucket
804
817
The newly created bucket or the given one.
805
818
"""
806
819
if isinstance (bucket_or_name , Bucket ):
820
+ if generation :
821
+ raise ValueError (
822
+ "The generation can only be specified if a "
823
+ "name is used to specify a bucket, not a Bucket object. "
824
+ "Create a new Bucket object with the correct generation "
825
+ "instead."
826
+ )
807
827
bucket = bucket_or_name
808
828
if bucket .client is None :
809
829
bucket ._client = self
810
830
else :
811
- bucket = Bucket (self , name = bucket_or_name )
831
+ bucket = Bucket (self , name = bucket_or_name , generation = generation )
812
832
return bucket
813
833
814
834
@create_trace_span (name = "Storage.Client.getBucket" )
@@ -819,6 +839,9 @@ def get_bucket(
819
839
if_metageneration_match = None ,
820
840
if_metageneration_not_match = None ,
821
841
retry = DEFAULT_RETRY ,
842
+ * ,
843
+ generation = None ,
844
+ soft_deleted = None ,
822
845
):
823
846
"""Retrieve a bucket via a GET request.
824
847
@@ -837,12 +860,12 @@ def get_bucket(
837
860
Can also be passed as a tuple (connect_timeout, read_timeout).
838
861
See :meth:`requests.Session.request` documentation for details.
839
862
840
- if_metageneration_match (Optional[long ]):
863
+ if_metageneration_match (Optional[int ]):
841
864
Make the operation conditional on whether the
842
- blob 's current metageneration matches the given value.
865
+ bucket 's current metageneration matches the given value.
843
866
844
- if_metageneration_not_match (Optional[long ]):
845
- Make the operation conditional on whether the blob 's
867
+ if_metageneration_not_match (Optional[int ]):
868
+ Make the operation conditional on whether the bucket 's
846
869
current metageneration does not match the given value.
847
870
848
871
retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]):
@@ -859,6 +882,19 @@ def get_bucket(
859
882
See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for
860
883
information on retry types and how to configure them.
861
884
885
+ generation (Optional[int]):
886
+ The generation of the bucket. The generation can be used to
887
+ specify a specific soft-deleted version of the bucket, in
888
+ conjunction with the ``soft_deleted`` argument below. If
889
+ ``soft_deleted`` is not True, the generation is unused.
890
+
891
+ soft_deleted (Optional[bool]):
892
+ If True, looks for a soft-deleted bucket. Will only return
893
+ the bucket metadata if the bucket exists and is in a
894
+ soft-deleted state. The bucket ``generation`` is required if
895
+ ``soft_deleted`` is set to True.
896
+ See: https://cloud.google.com/storage/docs/soft-delete
897
+
862
898
Returns:
863
899
google.cloud.storage.bucket.Bucket
864
900
The bucket matching the name provided.
@@ -867,13 +903,14 @@ def get_bucket(
867
903
google.cloud.exceptions.NotFound
868
904
If the bucket is not found.
869
905
"""
870
- bucket = self ._bucket_arg_to_bucket (bucket_or_name )
906
+ bucket = self ._bucket_arg_to_bucket (bucket_or_name , generation = generation )
871
907
bucket .reload (
872
908
client = self ,
873
909
timeout = timeout ,
874
910
if_metageneration_match = if_metageneration_match ,
875
911
if_metageneration_not_match = if_metageneration_not_match ,
876
912
retry = retry ,
913
+ soft_deleted = soft_deleted ,
877
914
)
878
915
return bucket
879
916
@@ -1386,6 +1423,8 @@ def list_buckets(
1386
1423
page_size = None ,
1387
1424
timeout = _DEFAULT_TIMEOUT ,
1388
1425
retry = DEFAULT_RETRY ,
1426
+ * ,
1427
+ soft_deleted = None ,
1389
1428
):
1390
1429
"""Get all buckets in the project associated to the client.
1391
1430
@@ -1438,6 +1477,12 @@ def list_buckets(
1438
1477
:param retry:
1439
1478
(Optional) How to retry the RPC. See: :ref:`configuring_retries`
1440
1479
1480
+ :type soft_deleted: bool
1481
+ :param soft_deleted:
1482
+ (Optional) If true, only soft-deleted buckets will be listed as distinct results in order of increasing
1483
+ generation number. This parameter can only be used successfully if the bucket has a soft delete policy.
1484
+ See: https://cloud.google.com/storage/docs/soft-delete
1485
+
1441
1486
:rtype: :class:`~google.api_core.page_iterator.Iterator`
1442
1487
:raises ValueError: if both ``project`` is ``None`` and the client's
1443
1488
project is also ``None``.
@@ -1469,6 +1514,9 @@ def list_buckets(
1469
1514
if fields is not None :
1470
1515
extra_params ["fields" ] = fields
1471
1516
1517
+ if soft_deleted is not None :
1518
+ extra_params ["softDeleted" ] = soft_deleted
1519
+
1472
1520
return self ._list_resource (
1473
1521
"/b" ,
1474
1522
_item_to_bucket ,
@@ -1480,6 +1528,71 @@ def list_buckets(
1480
1528
retry = retry ,
1481
1529
)
1482
1530
1531
+ def restore_bucket (
1532
+ self ,
1533
+ bucket_name ,
1534
+ generation ,
1535
+ projection = "noAcl" ,
1536
+ if_metageneration_match = None ,
1537
+ if_metageneration_not_match = None ,
1538
+ timeout = _DEFAULT_TIMEOUT ,
1539
+ retry = DEFAULT_RETRY ,
1540
+ ):
1541
+ """Restores a soft-deleted bucket.
1542
+
1543
+ :type bucket_name: str
1544
+ :param bucket_name: The name of the bucket to be restored.
1545
+
1546
+ :type generation: int
1547
+ :param generation: Selects the specific revision of the bucket.
1548
+
1549
+ :type projection: str
1550
+ :param projection:
1551
+ (Optional) Specifies the set of properties to return. If used, must
1552
+ be 'full' or 'noAcl'. Defaults to 'noAcl'.
1553
+
1554
+ if_metageneration_match (Optional[int]):
1555
+ Make the operation conditional on whether the
1556
+ blob's current metageneration matches the given value.
1557
+
1558
+ if_metageneration_not_match (Optional[int]):
1559
+ Make the operation conditional on whether the blob's
1560
+ current metageneration does not match the given value.
1561
+
1562
+ :type timeout: float or tuple
1563
+ :param timeout:
1564
+ (Optional) The amount of time, in seconds, to wait
1565
+ for the server response. See: :ref:`configuring_timeouts`
1566
+
1567
+ :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
1568
+ :param retry:
1569
+ (Optional) How to retry the RPC.
1570
+
1571
+ Users can configure non-default retry behavior. A ``None`` value will
1572
+ disable retries. See [Configuring Retries](https://cloud.google.com/python/docs/reference/storage/latest/retry_timeout).
1573
+
1574
+ :rtype: :class:`google.cloud.storage.bucket.Bucket`
1575
+ :returns: The restored Bucket.
1576
+ """
1577
+ query_params = {"generation" : generation , "projection" : projection }
1578
+
1579
+ _add_generation_match_parameters (
1580
+ query_params ,
1581
+ if_metageneration_match = if_metageneration_match ,
1582
+ if_metageneration_not_match = if_metageneration_not_match ,
1583
+ )
1584
+
1585
+ bucket = self .bucket (bucket_name )
1586
+ api_response = self ._post_resource (
1587
+ f"{ bucket .path } /restore" ,
1588
+ None ,
1589
+ query_params = query_params ,
1590
+ timeout = timeout ,
1591
+ retry = retry ,
1592
+ )
1593
+ bucket ._set_properties (api_response )
1594
+ return bucket
1595
+
1483
1596
@create_trace_span (name = "Storage.Client.createHmacKey" )
1484
1597
def create_hmac_key (
1485
1598
self ,
0 commit comments