diff --git a/storage/google/cloud/storage/_helpers.py b/storage/google/cloud/storage/_helpers.py index 88f9b8dc0ca7..56a75c684f4c 100644 --- a/storage/google/cloud/storage/_helpers.py +++ b/storage/google/cloud/storage/_helpers.py @@ -147,6 +147,22 @@ def patch(self, client=None): query_params={'projection': 'full'}, _target_object=self) self._set_properties(api_response) + def update(self, client=None): + """Sends all properties in a PUT request. + + Updates the ``_properties`` with the response from the backend. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + """ + client = self._require_client(client) + api_response = client._connection.api_request( + method='PUT', path=self.path, data=self._properties, + query_params={'projection': 'full'}, _target_object=self) + self._set_properties(api_response) + def _scalar_property(fieldname): """Create a property descriptor around the :class:`_PropertyMixin` helpers. diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index f9ff7219f4b8..06550b09ffcb 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -556,6 +556,7 @@ def cors(self): >>> policies[1]['maxAgeSeconds'] = 3600 >>> del policies[0] >>> bucket.cors = policies + >>> bucket.update() :setter: Set CORS policies for this bucket. :getter: Gets the CORS policies for this bucket. @@ -595,6 +596,7 @@ def labels(self): >>> labels['new_key'] = 'some-label' >>> del labels['old_key'] >>> bucket.labels = labels + >>> bucket.update() :setter: Set labels for this bucket. :getter: Gets the labels for this bucket. @@ -663,6 +665,7 @@ def lifecycle_rules(self): >>> rules[1]['rule']['action']['type'] = 'Delete' >>> del rules[0] >>> bucket.lifecycle_rules = rules + >>> bucket.update() :setter: Set lifestyle rules for this bucket. :getter: Gets the lifestyle rules for this bucket. diff --git a/storage/tests/system.py b/storage/tests/system.py index a89c45edbf25..bc8169c356b3 100644 --- a/storage/tests/system.py +++ b/storage/tests/system.py @@ -114,6 +114,26 @@ def test_list_buckets(self): if bucket.name in buckets_to_create] self.assertEqual(len(created_buckets), len(buckets_to_create)) + def test_bucket_update_labels(self): + bucket_name = 'update-labels' + unique_resource_id('-') + bucket = retry_429(Config.CLIENT.create_bucket)(bucket_name) + self.case_buckets_to_delete.append(bucket_name) + self.assertTrue(bucket.exists()) + + updated_labels = {'test-label': 'label-value'} + bucket.labels = updated_labels + bucket.update() + self.assertEqual(bucket.labels, updated_labels) + + new_labels = {'another-label': 'another-value'} + bucket.labels = new_labels + bucket.update() + self.assertEqual(bucket.labels, new_labels) + + bucket.labels = {} + bucket.update() + self.assertEqual(bucket.labels, {}) + class TestStorageFiles(unittest.TestCase): diff --git a/storage/tests/unit/test__helpers.py b/storage/tests/unit/test__helpers.py index 89967f3a0db0..90def4867268 100644 --- a/storage/tests/unit/test__helpers.py +++ b/storage/tests/unit/test__helpers.py @@ -95,6 +95,26 @@ def test_patch(self): # Make sure changes get reset by patch(). self.assertEqual(derived._changes, set()) + def test_update(self): + connection = _Connection({'foo': 'Foo'}) + client = _Client(connection) + derived = self._derivedClass('/path')() + # Make sure changes is non-empty, so we can observe a change. + BAR = object() + BAZ = object() + derived._properties = {'bar': BAR, 'baz': BAZ} + derived._changes = set(['bar']) # Update sends 'baz' anyway. + derived.update(client=client) + self.assertEqual(derived._properties, {'foo': 'Foo'}) + kw = connection._requested + self.assertEqual(len(kw), 1) + self.assertEqual(kw[0]['method'], 'PUT') + self.assertEqual(kw[0]['path'], '/path') + self.assertEqual(kw[0]['query_params'], {'projection': 'full'}) + self.assertEqual(kw[0]['data'], {'bar': BAR, 'baz': BAZ}) + # Make sure changes get reset by patch(). + self.assertEqual(derived._changes, set()) + class Test__scalar_property(unittest.TestCase):