Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #64 - Add Bucket.copy_key() and Key.rename() methods. #99

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions gcloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,28 @@ def delete_keys(self, keys):
for key in keys:
self.delete_key(key)

def copy_key(self):
raise NotImplementedError
def copy_key(self, key, destination_bucket, new_name=None):
"""Copy the given key to the given bucket, optionally with a new name.

:type key: string or :class:`gcloud.storage.key.Key`
:param key: The key to be copied.

:type destination_bucket: :class:`gcloud.storage.bucket.Bucket`
:param destination_bucket: The bucket where the key should be copied into.

:type new_name: string
:param new_name: (optional) the new name for the copied file.

:rtype: :class:`gcloud.storage.key.Key`
:returns: The new Key.
"""
# TODO: Check that the user has WRITE permissions on the dst bucket?
if new_name is None:
new_name = key.name
new_key = destination_bucket.new_key(new_name)
api_path = key.path + '/copyTo' + new_key.path
self.connection.api_request(method='POST', path=api_path)
return new_key

def upload_file(self, filename, key=None):
# TODO: What do we do about overwriting data?
Expand Down
13 changes: 13 additions & 0 deletions gcloud/storage/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ def exists(self):

return self.bucket.get_key(self.name) is not None

def rename(self, new_name):
"""Renames this key.

:type new_name: string
:param new_name: The new name for this key.
"""
new_key = self.bucket.copy_key(self, self.bucket, new_name)
self.delete()
# This feels like a dirty hack, but since the bucket is the same we can
# just change the name attribute of this instance to have it point to the
# new key.
self.name = new_key.name

def delete(self):
"""Deletes a key from Cloud Storage.

Expand Down
36 changes: 36 additions & 0 deletions gcloud/storage/test_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import unittest2

from gcloud.storage.bucket import Bucket
from gcloud.storage.connection import Connection
from gcloud.storage.key import Key


class TestKey(unittest2.TestCase):

def setUp(self):
# Mock Connection.api_request with a method that just stores the HTTP
# method, path and query params in an instance variable for later
# inspection.
# TODO: It'd be better to make the Connection talk to a local HTTP server
# that we can inspect, but a simple test using a mock is certainly better
# than no tests.
self.connection = Connection('project-name')
self.connection.api_request = self.mock_api_request
self.api_request_calls = []

def mock_api_request(self, method, path=None, query_params=None,
data=None, content_type=None,
api_base_url=None, api_version=None,
expect_json=True):
self.api_request_calls.append([method, path, query_params])

def test_rename(self):
bucket = Bucket(self.connection, 'bucket')
key = Key(bucket, 'key')
orig_key_path = key.path
key.rename('new-name')
expected = [
['POST', orig_key_path + '/copyTo/b/bucket/o/new-name', None],
['DELETE', orig_key_path, None]]
self.assertEqual(key.name, 'new-name')
self.assertEqual(self.api_request_calls, expected)