From 44685a007e4053e70be7231cde6e276cb8d3a094 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Tue, 4 Nov 2014 16:30:37 -0500 Subject: [PATCH] Add location support to buckets. See: https://cloud.google.com/storage/docs/json_api/v1/buckets and https://cloud.google.com/storage/docs/concepts-techniques#specifyinglocations Addresses 'location' part of 314. --- gcloud/storage/bucket.py | 25 ++++++++++++++++++ gcloud/storage/test_bucket.py | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index 6efa3a0d7afb..68fdd9d6a48e 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -24,6 +24,7 @@ class Bucket(_MetadataMixin): CUSTOM_METADATA_FIELDS = { 'acl': 'get_acl', 'defaultObjectAcl': 'get_default_object_acl', + 'location': 'get_location', } """Mapping of field name -> accessor for fields w/ custom accessors.""" @@ -441,6 +442,30 @@ def make_public(self, recursive=False, future=False): key.get_acl().all().grant_read() key.save_acl() + def get_location(self): + """Retrieve location configured for this bucket. + + See: https://cloud.google.com/storage/docs/json_api/v1/buckets and + https://cloud.google.com/storage/docs/concepts-techniques#specifyinglocations + + :rtype: string + :returns: The configured location. + """ + if not self.has_metadata('location'): + self.reload_metadata() + return self.metadata.get('location') + + def set_location(self, location): + """Update location configured for this bucket. + + See: https://cloud.google.com/storage/docs/json_api/v1/buckets and + https://cloud.google.com/storage/docs/concepts-techniques#specifyinglocations + + :type location: string + :param location: The new configured location. + """ + self.patch_metadata({'location': location}) + class BucketIterator(Iterator): """An iterator listing all buckets. diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index 7ca687acea76..ca4de4a6fb1a 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -489,6 +489,23 @@ def test_get_metadata_none_set_defaultObjectAcl_miss_clear_default(self): kw = connection._requested self.assertEqual(len(kw), 0) + def test_get_metadata_location_no_default(self): + NAME = 'name' + connection = _Connection() + bucket = self._makeOne(connection, NAME) + self.assertRaises(KeyError, bucket.get_metadata, 'location') + kw = connection._requested + self.assertEqual(len(kw), 0) + + def test_get_metadata_location_w_default(self): + NAME = 'name' + connection = _Connection() + bucket = self._makeOne(connection, NAME) + default = object() + self.assertRaises(KeyError, bucket.get_metadata, 'location', default) + kw = connection._requested + self.assertEqual(len(kw), 0) + def test_get_metadata_miss(self): NAME = 'name' before = {'bar': 'Bar'} @@ -713,6 +730,38 @@ def get_items_from_response(self, response): self.assertEqual(kw[1]['path'], '/b/%s/o' % NAME) self.assertEqual(kw[1]['query_params'], None) + def test_get_location_eager(self): + NAME = 'name' + connection = _Connection() + before = {'location': 'AS'} + bucket = self._makeOne(connection, NAME, before) + self.assertEqual(bucket.get_location(), 'AS') + kw = connection._requested + self.assertEqual(len(kw), 0) + + def test_get_location_lazy(self): + NAME = 'name' + connection = _Connection({'location': 'AS'}) + bucket = self._makeOne(connection, NAME) + self.assertEqual(bucket.get_location(), 'AS') + kw = connection._requested + self.assertEqual(len(kw), 1) + self.assertEqual(kw[0]['method'], 'GET') + self.assertEqual(kw[0]['path'], '/b/%s' % NAME) + + def test_update_location(self): + NAME = 'name' + connection = _Connection({'location': 'AS'}) + bucket = self._makeOne(connection, NAME) + bucket.set_location('AS') + self.assertEqual(bucket.get_location(), 'AS') + kw = connection._requested + self.assertEqual(len(kw), 1) + self.assertEqual(kw[0]['method'], 'PATCH') + self.assertEqual(kw[0]['path'], '/b/%s' % NAME) + self.assertEqual(kw[0]['data'], {'location': 'AS'}) + self.assertEqual(kw[0]['query_params'], {'projection': 'full'}) + class TestBucketIterator(unittest2.TestCase):