From 54fc24a8ca217b6ee1efaa19544fea4ea58a3dc5 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Tue, 11 Aug 2015 14:07:18 -0700 Subject: [PATCH] Moving rename() from Blob to Bucket. This is to fit the pattern already in place for Bucket.copy_blob. The philosophy being to treat copy and rename as operations associated with the container (Bucket) rather than with the object itself (Blob). Fixes #1007. --- gcloud/storage/blob.py | 26 -------------------------- gcloud/storage/bucket.py | 31 ++++++++++++++++++++++++++++++- gcloud/storage/test_blob.py | 20 -------------------- gcloud/storage/test_bucket.py | 26 ++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 47 deletions(-) diff --git a/gcloud/storage/blob.py b/gcloud/storage/blob.py index 688c3a244d49..0be46a6469e6 100644 --- a/gcloud/storage/blob.py +++ b/gcloud/storage/blob.py @@ -227,32 +227,6 @@ def exists(self, client=None): except NotFound: return False - def rename(self, new_name, client=None): - """Renames this blob using copy and delete operations. - - Effectively, copies blob to the same bucket with a new name, then - deletes the blob. - - .. warning:: - This method will first duplicate the data and then delete the - old blob. This means that with very large objects renaming - could be a very (temporarily) costly or a very slow operation. - - :type new_name: string - :param new_name: The new name for this blob. - - :type client: :class:`gcloud.storage.client.Client` or ``NoneType`` - :param client: Optional. The client to use. If not passed, falls back - to the ``client`` stored on the blob's bucket. - - :rtype: :class:`Blob` - :returns: The newly-copied blob. - """ - new_blob = self.bucket.copy_blob(self, self.bucket, new_name, - client=client) - self.delete(client=client) - return new_blob - def delete(self, client=None): """Deletes a blob from Cloud Storage. diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index 309a333af3e1..4329e978ed0f 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -434,7 +434,7 @@ def copy_blob(self, blob, destination_bucket, new_name=None, client=None): """Copy the given blob to the given bucket, optionally with a new name. - :type blob: string or :class:`gcloud.storage.blob.Blob` + :type blob: :class:`gcloud.storage.blob.Blob` :param blob: The blob to be copied. :type destination_bucket: :class:`gcloud.storage.bucket.Bucket` @@ -461,6 +461,35 @@ def copy_blob(self, blob, destination_bucket, new_name=None, new_blob._set_properties(copy_result) return new_blob + def rename_blob(self, blob, new_name, client=None): + """Rename the given blob using copy and delete operations. + + Effectively, copies blob to the same bucket with a new name, then + deletes the blob. + + .. warning:: + + This method will first duplicate the data and then delete the + old blob. This means that with very large objects renaming + could be a very (temporarily) costly or a very slow operation. + + :type blob: :class:`gcloud.storage.blob.Blob` + :param blob: The blob to be renamed. + + :type new_name: string + :param new_name: The new name for this blob. + + :type client: :class:`gcloud.storage.client.Client` or ``NoneType`` + :param client: Optional. The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :rtype: :class:`Blob` + :returns: The newly-renamed blob. + """ + new_blob = self.copy_blob(blob, self, new_name, client=client) + blob.delete(client=client) + return new_blob + @property def cors(self): """Retrieve CORS policies configured for this bucket. diff --git a/gcloud/storage/test_blob.py b/gcloud/storage/test_blob.py index 46433800b08a..a8be71047da7 100644 --- a/gcloud/storage/test_blob.py +++ b/gcloud/storage/test_blob.py @@ -232,21 +232,6 @@ def test_exists_hit(self): bucket._blobs[BLOB_NAME] = 1 self.assertTrue(blob.exists()) - def test_rename(self): - BLOB_NAME = 'blob-name' - NEW_NAME = 'new-name' - connection = _Connection() - client = _Client(connection) - bucket = _Bucket(client=client) - blob = self._makeOne(BLOB_NAME, bucket=bucket) - bucket._blobs[BLOB_NAME] = 1 - new_blob = blob.rename(NEW_NAME) - self.assertEqual(blob.name, BLOB_NAME) - self.assertEqual(new_blob.name, NEW_NAME) - self.assertFalse(BLOB_NAME in bucket._blobs) - self.assertEqual(bucket._deleted, [(BLOB_NAME, None)]) - self.assertTrue(NEW_NAME in bucket._blobs) - def test_delete(self): from six.moves.http_client import NOT_FOUND BLOB_NAME = 'blob-name' @@ -1058,11 +1043,6 @@ def __init__(self, client=None): self._copied = [] self._deleted = [] - def copy_blob(self, blob, destination_bucket, new_name, client=None): - self._copied.append((blob, destination_bucket, new_name, client)) - destination_bucket._blobs[new_name] = self._blobs[blob.name] - return blob.__class__(new_name, bucket=destination_bucket) - def delete_blob(self, blob_name, client=None): del self._blobs[blob_name] self._deleted.append((blob_name, client)) diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index 9589ff4ed1f6..97f213be6f21 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -519,6 +519,32 @@ class _Blob(object): self.assertEqual(kw['method'], 'POST') self.assertEqual(kw['path'], COPY_PATH) + def test_rename_blob(self): + BUCKET_NAME = 'BUCKET_NAME' + BLOB_NAME = 'blob-name' + NEW_BLOB_NAME = 'new-blob-name' + + DATA = {'name': NEW_BLOB_NAME} + connection = _Connection(DATA) + client = _Client(connection) + bucket = self._makeOne(client=client, name=BUCKET_NAME) + + class _Blob(object): + + def __init__(self, name, bucket_name): + self.name = name + self.path = '/b/%s/o/%s' % (bucket_name, name) + self._deleted = [] + + def delete(self, client=None): + self._deleted.append(client) + + blob = _Blob(BLOB_NAME, BUCKET_NAME) + renamed_blob = bucket.rename_blob(blob, NEW_BLOB_NAME, client=client) + self.assertTrue(renamed_blob.bucket is bucket) + self.assertEqual(renamed_blob.name, NEW_BLOB_NAME) + self.assertEqual(blob._deleted, [client]) + def test_etag(self): ETAG = 'ETAG' properties = {'etag': ETAG}