diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index 37691396db5e..d656f5a048df 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -1,3 +1,5 @@ +import os + from gcloud.storage import exceptions from gcloud.storage.acl import BucketACL from gcloud.storage.acl import DefaultObjectACL @@ -233,6 +235,51 @@ def upload_file(self, filename, key=None): key = self.new_key(key) return key.set_contents_from_filename(filename) + def upload_file_object(self, fh, key=None): + # TODO: What do we do about overwriting data? + """Shortcut method to upload a file into this bucket. + + Use this method to quickly put a local file in Cloud Storage. + + For example:: + + >>> from gcloud import storage + >>> connection = storage.get_connection(project, email, key_path) + >>> bucket = connection.get_bucket('my-bucket') + >>> bucket.upload_file(open('~/my-file.txt'), 'remote-text-file.txt') + >>> print bucket.get_all_keys() + [] + + If you don't provide a key value, + we will try to upload the file using the local filename + as the key + (**not** the complete path):: + + >>> from gcloud import storage + >>> connection = storage.get_connection(project, email, key_path) + >>> bucket = connection.get_bucket('my-bucket') + >>> bucket.upload_file(open('~/my-file.txt')) + >>> print bucket.get_all_keys() + [] + + :type fh: file + :param fh: A file handle open for reading. + + :type key: string or :class:`gcloud.storage.key.Key` + :param key: The key (either an object or a remote path) + of where to put the file. + + If this is blank, + we will try to upload the file + to the root of the bucket + with the same name as on your local file system. + """ + if key: + key = self.new_key(key) + else: + key = self.new_key(os.path.basename(fh.name)) + return key.set_contents_from_file(fh) + def has_metadata(self, field=None): """Check if metadata is available locally. diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index fa5f0e9e5b14..66713df52631 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -1,3 +1,5 @@ +import io + import unittest2 @@ -266,6 +268,41 @@ def set_contents_from_filename(self, filename): bucket.upload_file(FILENAME, KEY) self.assertEqual(_uploaded, [(bucket, KEY, FILENAME)]) + def test_upload_file_object_no_key(self): + from gcloud.test_credentials import _Monkey + from gcloud.storage import bucket as MUT + FILENAME = 'file.txt' + FILEOBJECT = MockFile(FILENAME) + _uploaded = [] + class _Key(object): + def __init__(self, bucket, name): + self._bucket = bucket + self._name = name + def set_contents_from_file(self, fh): + _uploaded.append((self._bucket, self._name, fh)) + bucket = self._makeOne() + with _Monkey(MUT, Key=_Key): + bucket.upload_file_object(FILEOBJECT) + self.assertEqual(_uploaded, [(bucket, FILENAME, FILEOBJECT)]) + + def test_upload_file_object_explicit_key(self): + from gcloud.test_credentials import _Monkey + from gcloud.storage import bucket as MUT + FILENAME = 'file.txt' + FILEOBJECT = MockFile(FILENAME) + KEY = 'key' + _uploaded = [] + class _Key(object): + def __init__(self, bucket, name): + self._bucket = bucket + self._name = name + def set_contents_from_file(self, fh): + _uploaded.append((self._bucket, self._name, fh)) + bucket = self._makeOne() + with _Monkey(MUT, Key=_Key): + bucket.upload_file_object(FILEOBJECT, KEY) + self.assertEqual(_uploaded, [(bucket, KEY, FILEOBJECT)]) + def test_has_metdata_none_set(self): NONESUCH = 'nonesuch' bucket = self._makeOne() @@ -790,4 +827,10 @@ def delete_bucket(self, bucket, force=False): if not self._delete_ok: raise NotFoundError('miss', None) return True - + + +class MockFile(io.StringIO): + name = None + def __init__(self, name, buffer_ = None): + super(MockFile, self).__init__(buffer_) + self.name = name