Skip to content

Commit 62e887d

Browse files
committed
Merge pull request #145 from kleyow/files
Added bucket method to upload files from a file object.
2 parents 5c3d8ae + 2f93065 commit 62e887d

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

gcloud/storage/bucket.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from gcloud.storage import exceptions
24
from gcloud.storage.acl import BucketACL
35
from gcloud.storage.acl import DefaultObjectACL
@@ -233,6 +235,51 @@ def upload_file(self, filename, key=None):
233235
key = self.new_key(key)
234236
return key.set_contents_from_filename(filename)
235237

238+
def upload_file_object(self, fh, key=None):
239+
# TODO: What do we do about overwriting data?
240+
"""Shortcut method to upload a file into this bucket.
241+
242+
Use this method to quickly put a local file in Cloud Storage.
243+
244+
For example::
245+
246+
>>> from gcloud import storage
247+
>>> connection = storage.get_connection(project, email, key_path)
248+
>>> bucket = connection.get_bucket('my-bucket')
249+
>>> bucket.upload_file(open('~/my-file.txt'), 'remote-text-file.txt')
250+
>>> print bucket.get_all_keys()
251+
[<Key: my-bucket, remote-text-file.txt>]
252+
253+
If you don't provide a key value,
254+
we will try to upload the file using the local filename
255+
as the key
256+
(**not** the complete path)::
257+
258+
>>> from gcloud import storage
259+
>>> connection = storage.get_connection(project, email, key_path)
260+
>>> bucket = connection.get_bucket('my-bucket')
261+
>>> bucket.upload_file(open('~/my-file.txt'))
262+
>>> print bucket.get_all_keys()
263+
[<Key: my-bucket, my-file.txt>]
264+
265+
:type fh: file
266+
:param fh: A file handle open for reading.
267+
268+
:type key: string or :class:`gcloud.storage.key.Key`
269+
:param key: The key (either an object or a remote path)
270+
of where to put the file.
271+
272+
If this is blank,
273+
we will try to upload the file
274+
to the root of the bucket
275+
with the same name as on your local file system.
276+
"""
277+
if key:
278+
key = self.new_key(key)
279+
else:
280+
key = self.new_key(os.path.basename(fh.name))
281+
return key.set_contents_from_file(fh)
282+
236283
def has_metadata(self, field=None):
237284
"""Check if metadata is available locally.
238285

gcloud/storage/test_bucket.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import io
2+
13
import unittest2
24

35

@@ -266,6 +268,41 @@ def set_contents_from_filename(self, filename):
266268
bucket.upload_file(FILENAME, KEY)
267269
self.assertEqual(_uploaded, [(bucket, KEY, FILENAME)])
268270

271+
def test_upload_file_object_no_key(self):
272+
from gcloud.test_credentials import _Monkey
273+
from gcloud.storage import bucket as MUT
274+
FILENAME = 'file.txt'
275+
FILEOBJECT = MockFile(FILENAME)
276+
_uploaded = []
277+
class _Key(object):
278+
def __init__(self, bucket, name):
279+
self._bucket = bucket
280+
self._name = name
281+
def set_contents_from_file(self, fh):
282+
_uploaded.append((self._bucket, self._name, fh))
283+
bucket = self._makeOne()
284+
with _Monkey(MUT, Key=_Key):
285+
bucket.upload_file_object(FILEOBJECT)
286+
self.assertEqual(_uploaded, [(bucket, FILENAME, FILEOBJECT)])
287+
288+
def test_upload_file_object_explicit_key(self):
289+
from gcloud.test_credentials import _Monkey
290+
from gcloud.storage import bucket as MUT
291+
FILENAME = 'file.txt'
292+
FILEOBJECT = MockFile(FILENAME)
293+
KEY = 'key'
294+
_uploaded = []
295+
class _Key(object):
296+
def __init__(self, bucket, name):
297+
self._bucket = bucket
298+
self._name = name
299+
def set_contents_from_file(self, fh):
300+
_uploaded.append((self._bucket, self._name, fh))
301+
bucket = self._makeOne()
302+
with _Monkey(MUT, Key=_Key):
303+
bucket.upload_file_object(FILEOBJECT, KEY)
304+
self.assertEqual(_uploaded, [(bucket, KEY, FILEOBJECT)])
305+
269306
def test_has_metdata_none_set(self):
270307
NONESUCH = 'nonesuch'
271308
bucket = self._makeOne()
@@ -788,4 +825,10 @@ def delete_bucket(self, bucket, force=False):
788825
if not self._delete_ok:
789826
raise NotFoundError('miss', None)
790827
return True
791-
828+
829+
830+
class MockFile(io.StringIO):
831+
name = None
832+
def __init__(self, name, buffer_ = None):
833+
super(MockFile, self).__init__(buffer_)
834+
self.name = name

0 commit comments

Comments
 (0)