diff --git a/storage/google/cloud/storage/blob.py b/storage/google/cloud/storage/blob.py index cf22a9a77ae2..1b718520865d 100644 --- a/storage/google/cloud/storage/blob.py +++ b/storage/google/cloud/storage/blob.py @@ -59,11 +59,12 @@ from google.cloud.storage._signing import generate_signed_url_v4 from google.cloud.storage.acl import ACL from google.cloud.storage.acl import ObjectACL -from google.cloud.storage.constants import STANDARD_STORAGE_CLASS -from google.cloud.storage.constants import NEARLINE_STORAGE_CLASS +from google.cloud.storage.constants import ARCHIVE_STORAGE_CLASS from google.cloud.storage.constants import COLDLINE_STORAGE_CLASS from google.cloud.storage.constants import MULTI_REGIONAL_LEGACY_STORAGE_CLASS +from google.cloud.storage.constants import NEARLINE_STORAGE_CLASS from google.cloud.storage.constants import REGIONAL_LEGACY_STORAGE_CLASS +from google.cloud.storage.constants import STANDARD_STORAGE_CLASS _STORAGE_HOST = _get_storage_host() @@ -143,6 +144,7 @@ class Blob(_PropertyMixin): STANDARD_STORAGE_CLASS, NEARLINE_STORAGE_CLASS, COLDLINE_STORAGE_CLASS, + ARCHIVE_STORAGE_CLASS, MULTI_REGIONAL_LEGACY_STORAGE_CLASS, REGIONAL_LEGACY_STORAGE_CLASS, ) @@ -1656,6 +1658,7 @@ def update_storage_class(self, new_class, client=None): new storage class for the object. One of: :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, or @@ -1951,6 +1954,7 @@ def kms_key_name(self): :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.DURABLE_REDUCED_AVAILABILITY_STORAGE_CLASS`, diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index 48ab09e23e4f..764bd385789b 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -39,6 +39,7 @@ from google.cloud.storage.acl import BucketACL from google.cloud.storage.acl import DefaultObjectACL from google.cloud.storage.blob import Blob +from google.cloud.storage.constants import ARCHIVE_STORAGE_CLASS from google.cloud.storage.constants import COLDLINE_STORAGE_CLASS from google.cloud.storage.constants import DUAL_REGION_LOCATION_TYPE from google.cloud.storage.constants import ( @@ -402,6 +403,7 @@ class Bucket(_PropertyMixin): STANDARD_STORAGE_CLASS, NEARLINE_STORAGE_CLASS, COLDLINE_STORAGE_CLASS, + ARCHIVE_STORAGE_CLASS, MULTI_REGIONAL_LEGACY_STORAGE_CLASS, # legacy REGIONAL_LEGACY_STORAGE_CLASS, # legacy DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS, # legacy @@ -1634,6 +1636,7 @@ def storage_class(self): If set, one of :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`, @@ -1654,6 +1657,7 @@ def storage_class(self, value): One of :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`, diff --git a/storage/google/cloud/storage/constants.py b/storage/google/cloud/storage/constants.py index e93d3ab29546..faadff1f0702 100644 --- a/storage/google/cloud/storage/constants.py +++ b/storage/google/cloud/storage/constants.py @@ -16,13 +16,28 @@ # Storage classes STANDARD_STORAGE_CLASS = "STANDARD" -"""Storage class for objects accessed more than once per month.""" +"""Storage class for objects accessed more than once per month. + +See: https://cloud.google.com/storage/docs/storage-classes +""" NEARLINE_STORAGE_CLASS = "NEARLINE" -"""Storage class for objects accessed at most once per month.""" +"""Storage class for objects accessed at most once per month. + +See: https://cloud.google.com/storage/docs/storage-classes +""" COLDLINE_STORAGE_CLASS = "COLDLINE" -"""Storage class for objects accessed at most once per year.""" +"""Storage class for objects accessed at most once per year. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +ARCHIVE_STORAGE_CLASS = "ARCHIVE" +"""Storage class for objects accessed less frequently than once per year. + +See: https://cloud.google.com/storage/docs/storage-classes +""" MULTI_REGIONAL_LEGACY_STORAGE_CLASS = "MULTI_REGIONAL" """Legacy storage class. @@ -32,6 +47,8 @@ Can only be used for objects in buckets whose :attr:`~google.cloud.storage.bucket.Bucket.location_type` is :attr:`~google.cloud.storage.bucket.Bucket.MULTI_REGION_LOCATION_TYPE`. + +See: https://cloud.google.com/storage/docs/storage-classes """ REGIONAL_LEGACY_STORAGE_CLASS = "REGIONAL" @@ -42,6 +59,8 @@ Can only be used for objects in buckets whose :attr:`~google.cloud.storage.bucket.Bucket.location_type` is :attr:`~google.cloud.storage.bucket.Bucket.REGION_LOCATION_TYPE`. + +See: https://cloud.google.com/storage/docs/storage-classes """ DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS = "DURABLE_REDUCED_AVAILABILITY" diff --git a/storage/tests/system.py b/storage/tests/system.py index 65f4f976a41f..eb24a6b6ab42 100644 --- a/storage/tests/system.py +++ b/storage/tests/system.py @@ -172,7 +172,23 @@ def test_create_bucket(self): self.case_buckets_to_delete.append(new_bucket_name) self.assertEqual(created.name, new_bucket_name) + def test_bucket_create_w_alt_storage_class(self): + from google.cloud.storage import constants + + new_bucket_name = "bucket-w-archive" + unique_resource_id("-") + self.assertRaises( + exceptions.NotFound, Config.CLIENT.get_bucket, new_bucket_name + ) + bucket = Config.CLIENT.bucket(new_bucket_name) + bucket.storage_class = constants.ARCHIVE_STORAGE_CLASS + retry_429_503(bucket.create)() + self.case_buckets_to_delete.append(new_bucket_name) + created = Config.CLIENT.get_bucket(new_bucket_name) + self.assertEqual(created.storage_class, constants.ARCHIVE_STORAGE_CLASS) + def test_lifecycle_rules(self): + from google.cloud.storage import constants + new_bucket_name = "w-lifcycle-rules" + unique_resource_id("-") self.assertRaises( exceptions.NotFound, Config.CLIENT.get_bucket, new_bucket_name @@ -180,13 +196,17 @@ def test_lifecycle_rules(self): bucket = Config.CLIENT.bucket(new_bucket_name) bucket.add_lifecycle_delete_rule(age=42) bucket.add_lifecycle_set_storage_class_rule( - "COLDLINE", is_live=False, matches_storage_class=["NEARLINE"] + constants.COLDLINE_STORAGE_CLASS, + is_live=False, + matches_storage_class=[constants.NEARLINE_STORAGE_CLASS], ) expected_rules = [ LifecycleRuleDelete(age=42), LifecycleRuleSetStorageClass( - "COLDLINE", is_live=False, matches_storage_class=["NEARLINE"] + constants.COLDLINE_STORAGE_CLASS, + is_live=False, + matches_storage_class=[constants.NEARLINE_STORAGE_CLASS], ), ] @@ -1216,34 +1236,38 @@ def test_rewrite_rotate_with_user_project(self): class TestStorageUpdateStorageClass(TestStorageFiles): def test_update_storage_class_small_file(self): + from google.cloud.storage import constants + blob = self.bucket.blob("SmallFile") file_data = self.FILES["simple"] blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(blob) - blob.update_storage_class("NEARLINE") + blob.update_storage_class(constants.NEARLINE_STORAGE_CLASS) blob.reload() - self.assertEqual(blob.storage_class, "NEARLINE") + self.assertEqual(blob.storage_class, constants.NEARLINE_STORAGE_CLASS) - blob.update_storage_class("COLDLINE") + blob.update_storage_class(constants.COLDLINE_STORAGE_CLASS) blob.reload() - self.assertEqual(blob.storage_class, "COLDLINE") + self.assertEqual(blob.storage_class, constants.COLDLINE_STORAGE_CLASS) def test_update_storage_class_large_file(self): + from google.cloud.storage import constants + blob = self.bucket.blob("BigFile") file_data = self.FILES["big"] blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(blob) - blob.update_storage_class("NEARLINE") + blob.update_storage_class(constants.NEARLINE_STORAGE_CLASS) blob.reload() - self.assertEqual(blob.storage_class, "NEARLINE") + self.assertEqual(blob.storage_class, constants.NEARLINE_STORAGE_CLASS) - blob.update_storage_class("COLDLINE") + blob.update_storage_class(constants.COLDLINE_STORAGE_CLASS) blob.reload() - self.assertEqual(blob.storage_class, "COLDLINE") + self.assertEqual(blob.storage_class, constants.COLDLINE_STORAGE_CLASS) class TestStorageNotificationCRUD(unittest.TestCase): diff --git a/storage/tests/unit/test_bucket.py b/storage/tests/unit/test_bucket.py index de943339e200..2eb6f7d57561 100644 --- a/storage/tests/unit/test_bucket.py +++ b/storage/tests/unit/test_bucket.py @@ -1773,6 +1773,15 @@ def test_storage_class_setter_COLDLINE(self): self.assertEqual(bucket.storage_class, COLDLINE_STORAGE_CLASS) self.assertTrue("storageClass" in bucket._changes) + def test_storage_class_setter_ARCHIVE(self): + from google.cloud.storage.constants import ARCHIVE_STORAGE_CLASS + + NAME = "name" + bucket = self._make_one(name=NAME) + bucket.storage_class = ARCHIVE_STORAGE_CLASS + self.assertEqual(bucket.storage_class, ARCHIVE_STORAGE_CLASS) + self.assertTrue("storageClass" in bucket._changes) + def test_storage_class_setter_MULTI_REGIONAL(self): from google.cloud.storage.constants import MULTI_REGIONAL_LEGACY_STORAGE_CLASS