@@ -1188,6 +1188,7 @@ def get_blob(
1188
1188
if_metageneration_not_match = None ,
1189
1189
timeout = _DEFAULT_TIMEOUT ,
1190
1190
retry = DEFAULT_RETRY ,
1191
+ soft_deleted = None ,
1191
1192
** kwargs ,
1192
1193
):
1193
1194
"""Get a blob object by name.
@@ -1248,6 +1249,13 @@ def get_blob(
1248
1249
:param retry:
1249
1250
(Optional) How to retry the RPC. See: :ref:`configuring_retries`
1250
1251
1252
+ :type soft_deleted: bool
1253
+ :param soft_deleted:
1254
+ (Optional) If True, looks for a soft-deleted object. Will only return
1255
+ the object metadata if the object exists and is in a soft-deleted state.
1256
+ Object ``generation`` is required if ``soft_deleted`` is set to True.
1257
+ See: https://cloud.google.com/storage/docs/soft-delete
1258
+
1251
1259
:param kwargs: Keyword arguments to pass to the
1252
1260
:class:`~google.cloud.storage.blob.Blob` constructor.
1253
1261
@@ -1275,6 +1283,7 @@ def get_blob(
1275
1283
if_metageneration_match = if_metageneration_match ,
1276
1284
if_metageneration_not_match = if_metageneration_not_match ,
1277
1285
retry = retry ,
1286
+ soft_deleted = soft_deleted ,
1278
1287
)
1279
1288
except NotFound :
1280
1289
return None
@@ -1297,6 +1306,7 @@ def list_blobs(
1297
1306
timeout = _DEFAULT_TIMEOUT ,
1298
1307
retry = DEFAULT_RETRY ,
1299
1308
match_glob = None ,
1309
+ soft_deleted = None ,
1300
1310
):
1301
1311
"""Return an iterator used to find blobs in the bucket.
1302
1312
@@ -1378,6 +1388,13 @@ def list_blobs(
1378
1388
The string value must be UTF-8 encoded. See:
1379
1389
https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
1380
1390
1391
+ :type soft_deleted: bool
1392
+ :param soft_deleted:
1393
+ (Optional) If true, only soft-deleted objects will be listed as distinct results in order of increasing
1394
+ generation number. This parameter can only be used successfully if the bucket has a soft delete policy.
1395
+ Note ``soft_deleted`` and ``versions`` cannot be set to True simultaneously. See:
1396
+ https://cloud.google.com/storage/docs/soft-delete
1397
+
1381
1398
:rtype: :class:`~google.api_core.page_iterator.Iterator`
1382
1399
:returns: Iterator of all :class:`~google.cloud.storage.blob.Blob`
1383
1400
in this bucket matching the arguments.
@@ -1398,6 +1415,7 @@ def list_blobs(
1398
1415
timeout = timeout ,
1399
1416
retry = retry ,
1400
1417
match_glob = match_glob ,
1418
+ soft_deleted = soft_deleted ,
1401
1419
)
1402
1420
1403
1421
def list_notifications (
@@ -2060,6 +2078,110 @@ def rename_blob(
2060
2078
)
2061
2079
return new_blob
2062
2080
2081
+ def restore_blob (
2082
+ self ,
2083
+ blob_name ,
2084
+ client = None ,
2085
+ generation = None ,
2086
+ copy_source_acl = None ,
2087
+ projection = None ,
2088
+ if_generation_match = None ,
2089
+ if_generation_not_match = None ,
2090
+ if_metageneration_match = None ,
2091
+ if_metageneration_not_match = None ,
2092
+ timeout = _DEFAULT_TIMEOUT ,
2093
+ retry = DEFAULT_RETRY_IF_GENERATION_SPECIFIED ,
2094
+ ):
2095
+ """Restores a soft-deleted object.
2096
+
2097
+ If :attr:`user_project` is set on the bucket, bills the API request to that project.
2098
+
2099
+ See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/objects/restore)
2100
+
2101
+ :type blob_name: str
2102
+ :param blob_name: The name of the blob to be restored.
2103
+
2104
+ :type client: :class:`~google.cloud.storage.client.Client`
2105
+ :param client: (Optional) The client to use. If not passed, falls back
2106
+ to the ``client`` stored on the current bucket.
2107
+
2108
+ :type generation: long
2109
+ :param generation: (Optional) If present, selects a specific revision of this object.
2110
+
2111
+ :type copy_source_acl: bool
2112
+ :param copy_source_acl: (Optional) If true, copy the soft-deleted object's access controls.
2113
+
2114
+ :type projection: str
2115
+ :param projection: (Optional) Specifies the set of properties to return.
2116
+ If used, must be 'full' or 'noAcl'.
2117
+
2118
+ :type if_generation_match: long
2119
+ :param if_generation_match:
2120
+ (Optional) See :ref:`using-if-generation-match`
2121
+
2122
+ :type if_generation_not_match: long
2123
+ :param if_generation_not_match:
2124
+ (Optional) See :ref:`using-if-generation-not-match`
2125
+
2126
+ :type if_metageneration_match: long
2127
+ :param if_metageneration_match:
2128
+ (Optional) See :ref:`using-if-metageneration-match`
2129
+
2130
+ :type if_metageneration_not_match: long
2131
+ :param if_metageneration_not_match:
2132
+ (Optional) See :ref:`using-if-metageneration-not-match`
2133
+
2134
+ :type timeout: float or tuple
2135
+ :param timeout:
2136
+ (Optional) The amount of time, in seconds, to wait
2137
+ for the server response. See: :ref:`configuring_timeouts`
2138
+
2139
+ :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
2140
+ :param retry:
2141
+ (Optional) How to retry the RPC.
2142
+ The default value is ``DEFAULT_RETRY_IF_GENERATION_SPECIFIED``, which
2143
+ only restore operations with ``if_generation_match`` or ``generation`` set
2144
+ will be retried.
2145
+
2146
+ Users can configure non-default retry behavior. A ``None`` value will
2147
+ disable retries. A ``DEFAULT_RETRY`` value will enable retries
2148
+ even if restore operations are not guaranteed to be idempotent.
2149
+ See [Configuring Retries](https://cloud.google.com/python/docs/reference/storage/latest/retry_timeout).
2150
+
2151
+ :rtype: :class:`google.cloud.storage.blob.Blob`
2152
+ :returns: The restored Blob.
2153
+ """
2154
+ client = self ._require_client (client )
2155
+ query_params = {}
2156
+
2157
+ if self .user_project is not None :
2158
+ query_params ["userProject" ] = self .user_project
2159
+ if generation is not None :
2160
+ query_params ["generation" ] = generation
2161
+ if copy_source_acl is not None :
2162
+ query_params ["copySourceAcl" ] = copy_source_acl
2163
+ if projection is not None :
2164
+ query_params ["projection" ] = projection
2165
+
2166
+ _add_generation_match_parameters (
2167
+ query_params ,
2168
+ if_generation_match = if_generation_match ,
2169
+ if_generation_not_match = if_generation_not_match ,
2170
+ if_metageneration_match = if_metageneration_match ,
2171
+ if_metageneration_not_match = if_metageneration_not_match ,
2172
+ )
2173
+
2174
+ blob = Blob (bucket = self , name = blob_name )
2175
+ api_response = client ._post_resource (
2176
+ f"{ blob .path } /restore" ,
2177
+ None ,
2178
+ query_params = query_params ,
2179
+ timeout = timeout ,
2180
+ retry = retry ,
2181
+ )
2182
+ blob ._set_properties (api_response )
2183
+ return blob
2184
+
2063
2185
@property
2064
2186
def cors (self ):
2065
2187
"""Retrieve or set CORS policies configured for this bucket.
@@ -2227,6 +2349,18 @@ def iam_configuration(self):
2227
2349
info = self ._properties .get ("iamConfiguration" , {})
2228
2350
return IAMConfiguration .from_api_repr (info , self )
2229
2351
2352
+ @property
2353
+ def soft_delete_policy (self ):
2354
+ """Retrieve the soft delete policy for this bucket.
2355
+
2356
+ See https://cloud.google.com/storage/docs/soft-delete
2357
+
2358
+ :rtype: :class:`SoftDeletePolicy`
2359
+ :returns: an instance for managing the bucket's soft delete policy.
2360
+ """
2361
+ policy = self ._properties .get ("softDeletePolicy" , {})
2362
+ return SoftDeletePolicy .from_api_repr (policy , self )
2363
+
2230
2364
@property
2231
2365
def lifecycle_rules (self ):
2232
2366
"""Retrieve or set lifecycle rules configured for this bucket.
@@ -3432,6 +3566,102 @@ def generate_signed_url(
3432
3566
)
3433
3567
3434
3568
3569
+ class SoftDeletePolicy (dict ):
3570
+ """Map a bucket's soft delete policy.
3571
+
3572
+ See https://cloud.google.com/storage/docs/soft-delete
3573
+
3574
+ :type bucket: :class:`Bucket`
3575
+ :param bucket: Bucket for which this instance is the policy.
3576
+
3577
+ :type retention_duration_seconds: int
3578
+ :param retention_duration_seconds:
3579
+ (Optional) The period of time in seconds that soft-deleted objects in the bucket
3580
+ will be retained and cannot be permanently deleted.
3581
+
3582
+ :type effective_time: :class:`datetime.datetime`
3583
+ :param effective_time:
3584
+ (Optional) When the bucket's soft delete policy is effective.
3585
+ This value should normally only be set by the back-end API.
3586
+ """
3587
+
3588
+ def __init__ (self , bucket , ** kw ):
3589
+ data = {}
3590
+ retention_duration_seconds = kw .get ("retention_duration_seconds" )
3591
+ data ["retentionDurationSeconds" ] = retention_duration_seconds
3592
+
3593
+ effective_time = kw .get ("effective_time" )
3594
+ if effective_time is not None :
3595
+ effective_time = _datetime_to_rfc3339 (effective_time )
3596
+ data ["effectiveTime" ] = effective_time
3597
+
3598
+ super ().__init__ (data )
3599
+ self ._bucket = bucket
3600
+
3601
+ @classmethod
3602
+ def from_api_repr (cls , resource , bucket ):
3603
+ """Factory: construct instance from resource.
3604
+
3605
+ :type resource: dict
3606
+ :param resource: mapping as returned from API call.
3607
+
3608
+ :type bucket: :class:`Bucket`
3609
+ :params bucket: Bucket for which this instance is the policy.
3610
+
3611
+ :rtype: :class:`SoftDeletePolicy`
3612
+ :returns: Instance created from resource.
3613
+ """
3614
+ instance = cls (bucket )
3615
+ instance .update (resource )
3616
+ return instance
3617
+
3618
+ @property
3619
+ def bucket (self ):
3620
+ """Bucket for which this instance is the policy.
3621
+
3622
+ :rtype: :class:`Bucket`
3623
+ :returns: the instance's bucket.
3624
+ """
3625
+ return self ._bucket
3626
+
3627
+ @property
3628
+ def retention_duration_seconds (self ):
3629
+ """Get the retention duration of the bucket's soft delete policy.
3630
+
3631
+ :rtype: int or ``NoneType``
3632
+ :returns: The period of time in seconds that soft-deleted objects in the bucket
3633
+ will be retained and cannot be permanently deleted; Or ``None`` if the
3634
+ property is not set.
3635
+ """
3636
+ duration = self .get ("retentionDurationSeconds" )
3637
+ if duration is not None :
3638
+ return int (duration )
3639
+
3640
+ @retention_duration_seconds .setter
3641
+ def retention_duration_seconds (self , value ):
3642
+ """Set the retention duration of the bucket's soft delete policy.
3643
+
3644
+ :type value: int
3645
+ :param value:
3646
+ The period of time in seconds that soft-deleted objects in the bucket
3647
+ will be retained and cannot be permanently deleted.
3648
+ """
3649
+ self ["retentionDurationSeconds" ] = value
3650
+ self .bucket ._patch_property ("softDeletePolicy" , self )
3651
+
3652
+ @property
3653
+ def effective_time (self ):
3654
+ """Get the effective time of the bucket's soft delete policy.
3655
+
3656
+ :rtype: datetime.datetime or ``NoneType``
3657
+ :returns: point-in time at which the bucket's soft delte policy is
3658
+ effective, or ``None`` if the property is not set.
3659
+ """
3660
+ timestamp = self .get ("effectiveTime" )
3661
+ if timestamp is not None :
3662
+ return _rfc3339_nanos_to_datetime (timestamp )
3663
+
3664
+
3435
3665
def _raise_if_len_differs (expected_len , ** generation_match_args ):
3436
3666
"""
3437
3667
Raise an error if any generation match argument
0 commit comments