Skip to content

Commit

Permalink
Add bucket properties to support retention policy feature. (#447)
Browse files Browse the repository at this point in the history
Toward #445.
  • Loading branch information
tseaver committed Jun 25, 2018
1 parent f6048da commit 6a1866e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
73 changes: 73 additions & 0 deletions storage/google/cloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,21 @@ def cors(self, entries):
"""
self._patch_property('cors', entries)

default_event_based_hold = _scalar_property('defaultEventBasedHold')
"""Are uploaded objects automatically placed under an even-based hold?
If True, uploaded objects will be placed under an event-based hold to
be released at a future time. When released an object will then begin
the retention period determined by the policy retention period for the
object bucket.
See https://cloud.google.com/storage/docs/json_api/v1/buckets
If the property is not set locally, returns ``None``.
:rtype: bool or ``NoneType``
"""

@property
def default_kms_key_name(self):
"""Retrieve / set default KMS encryption key for objects in the bucket.
Expand Down Expand Up @@ -1019,6 +1034,64 @@ def project_number(self):
if project_number is not None:
return int(project_number)

@property
def retention_policy_effective_time(self):
"""Retrieve the effective time of the bucket's retention policy.
:rtype: datetime.datetime or ``NoneType``
:returns: point-in time at which the bucket's retention policy is
effective, or ``None`` if the property is not
set locally.
"""
policy = self._properties.get('retentionPolicy')
if policy is not None:
timestamp = policy.get('effectiveTime')
if timestamp is not None:
return _rfc3339_to_datetime(timestamp)

@property
def retention_policy_locked(self):
"""Retrieve whthere the bucket's retention policy is locked.
:rtype: bool
:returns: True if the bucket's policy is locked, or else False
if the policy is not locked, or the property is not
set locally.
"""
policy = self._properties.get('retentionPolicy')
if policy is not None:
return policy.get('isLocked')

@property
def retention_period(self):
"""Retrieve or set the retention period for items in the bucket.
:rtype: int or ``NoneType``
:returns: number of seconds to retain items after upload or release
from event-based lock, or ``None`` if the property is not
set locally.
"""
policy = self._properties.get('retentionPolicy')
if policy is not None:
period = policy.get('retentionPeriod')
if period is not None:
return int(period)

@retention_period.setter
def retention_period(self, value):
"""Set the retention period for items in the bucket.
:type value: int
:param value:
number of seconds to retain items after upload or release from
event-based lock.
:raises ValueError: if the bucket's retention policy is locked.
"""
policy = self._properties.setdefault('retentionPolicy', {})
policy['retentionPeriod'] = str(value)
self._patch_property('retentionPolicy', policy)

@property
def self_link(self):
"""Retrieve the URI for the bucket.
Expand Down
86 changes: 86 additions & 0 deletions storage/tests/unit/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,92 @@ def test_project_number_string_val(self):
bucket = self._make_one(properties=properties)
self.assertEqual(bucket.project_number, PROJECT_NUMBER)

def test_retention_policy_effective_time_policy_missing(self):
bucket = self._make_one()
self.assertIsNone(bucket.retention_policy_effective_time)

def test_retention_policy_effective_time_et_missing(self):
properties = {
'retentionPolicy': {
},
}
bucket = self._make_one(properties=properties)

self.assertIsNone(bucket.retention_policy_effective_time)

def test_retention_policy_effective_time(self):
import datetime
from google.cloud._helpers import _datetime_to_rfc3339
from google.cloud._helpers import UTC

effective_time = datetime.datetime.utcnow().replace(tzinfo=UTC)
properties = {
'retentionPolicy': {
'effectiveTime': _datetime_to_rfc3339(effective_time),
},
}
bucket = self._make_one(properties=properties)

self.assertEqual(
bucket.retention_policy_effective_time, effective_time)

def test_retention_policy_locked_missing(self):
bucket = self._make_one()
self.assertFalse(bucket.retention_policy_locked)

def test_retention_policy_locked_false(self):
properties = {
'retentionPolicy': {
'isLocked': False,
},
}
bucket = self._make_one(properties=properties)
self.assertFalse(bucket.retention_policy_locked)

def test_retention_policy_locked_true(self):
properties = {
'retentionPolicy': {
'isLocked': True,
},
}
bucket = self._make_one(properties=properties)
self.assertTrue(bucket.retention_policy_locked)

def test_retention_period_getter_policymissing(self):
bucket = self._make_one()

self.assertIsNone(bucket.retention_period)

def test_retention_period_getter_pr_missing(self):
properties = {
'retentionPolicy': {
},
}
bucket = self._make_one(properties=properties)

self.assertIsNone(bucket.retention_period)

def test_retention_period_getter(self):
period = 86400 * 100 # 100 days
properties = {
'retentionPolicy': {
'retentionPeriod': str(period),
},
}
bucket = self._make_one(properties=properties)

self.assertEqual(bucket.retention_period, period)

def test_retention_period_setter(self):
period = 86400 * 100 # 100 days
bucket = self._make_one()

bucket.retention_period = period

self.assertEqual(
bucket._properties['retentionPolicy']['retentionPeriod'],
str(period))

def test_self_link(self):
SELF_LINK = 'http://example.com/self/'
properties = {'selfLink': SELF_LINK}
Expand Down

0 comments on commit 6a1866e

Please sign in to comment.