diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index 4f82ef791ab6..322e1193b5e6 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -180,17 +180,26 @@ def delete_key(self, key): self.connection.api_request(method='DELETE', path=key.path) return key - def delete_keys(self, keys): + def delete_keys(self, keys, on_error=None): """Deletes a list of keys from the current bucket. Uses :func:`Bucket.delete_key` to delete each individual key. :type keys: list of string or :class:`gcloud.storage.key.Key` - :param key: A list of key names or Key objects to delete. + :param keys: A list of key names or Key objects to delete. + + :type on_error: a callable taking (key) + :param on_error: If not ``None``, called once for each key which + raises a ``NotFoundError``. """ - # NOTE: boto returns a MultiDeleteResult instance. for key in keys: - self.delete_key(key) + try: + self.delete_key(key) + except exceptions.NotFoundError: + if on_error is not None: + on_error(key) + else: + raise def copy_key(self, key, destination_bucket, new_name=None): """Copy the given key to the given bucket, optionally with a new name. diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index 8ae603a67cd0..3134bde7fc75 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -232,7 +232,7 @@ def test_delete_keys_hit(self): self.assertEqual(kw[0]['method'], 'DELETE') self.assertEqual(kw[0]['path'], '/b/%s/o/%s' % (NAME, KEY)) - def test_delete_keys_miss(self): + def test_delete_keys_miss_no_on_error(self): from gcloud.storage.exceptions import NotFoundError NAME = 'name' KEY = 'key' @@ -247,6 +247,22 @@ def test_delete_keys_miss(self): self.assertEqual(kw[1]['method'], 'DELETE') self.assertEqual(kw[1]['path'], '/b/%s/o/%s' % (NAME, NONESUCH)) + def test_delete_keys_miss_w_on_error(self): + NAME = 'name' + KEY = 'key' + NONESUCH = 'nonesuch' + connection = _Connection({}) + bucket = self._makeOne(connection, NAME) + errors = [] + bucket.delete_keys([KEY, NONESUCH], errors.append) + self.assertEqual(errors, [NONESUCH]) + kw = connection._requested + self.assertEqual(len(kw), 2) + self.assertEqual(kw[0]['method'], 'DELETE') + self.assertEqual(kw[0]['path'], '/b/%s/o/%s' % (NAME, KEY)) + self.assertEqual(kw[1]['method'], 'DELETE') + self.assertEqual(kw[1]['path'], '/b/%s/o/%s' % (NAME, NONESUCH)) + def test_copy_keys_wo_name(self): SOURCE = 'source' DEST = 'dest'