Skip to content

Commit afc9994

Browse files
committed
Make storage upload have no chunk size by default.
Fixes #546.
1 parent b395360 commit afc9994

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

gcloud/storage/blob.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ def download_as_string(self):
271271
return string_buffer.getvalue()
272272

273273
def upload_from_file(self, file_obj, rewind=False, size=None,
274-
content_type=None, num_retries=6):
274+
content_type=None, num_retries=6,
275+
upload_chunk_size=None):
275276
"""Upload the contents of this blob from a file-like object.
276277
277278
.. note::
@@ -285,6 +286,11 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
285286
`lifecycle <https://cloud.google.com/storage/docs/lifecycle>`_
286287
API documents for details.
287288
289+
The current ``Blob``'s chunk size is not used by default. Default
290+
behavior is instead to attempt uploading the entire object. See
291+
https://github.com/GoogleCloudPlatform/gcloud-python/issues/546
292+
for more details.
293+
288294
:type file_obj: file
289295
:param file_obj: A file handle open for reading.
290296
@@ -296,6 +302,15 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
296302
:param size: The number of bytes to read from the file handle.
297303
If not provided, we'll try to guess the size using
298304
:func:`os.fstat`
305+
306+
:type content_type: string or ``NoneType``
307+
:param content_type: Optional content type of uploaded content.
308+
309+
:type num_retries: int
310+
:param num_retries: Optional number of retries. Defaults to 6.
311+
312+
:type upload_chunk_size: int or ``NoneType``
313+
:param upload_chunk_size: Optional size of chunks to upload with.
299314
"""
300315
# Rewind the file if desired.
301316
if rewind:
@@ -313,7 +328,7 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
313328
upload = transfer.Upload(file_obj,
314329
content_type or 'application/unknown',
315330
total_bytes, auto_transfer=False,
316-
chunksize=self.CHUNK_SIZE)
331+
chunksize=upload_chunk_size)
317332

318333
url_builder = _UrlBuilder(bucket_name=self.bucket.name,
319334
object_name=self.name)
@@ -611,7 +626,7 @@ def updated(self):
611626

612627

613628
class _UploadConfig(object):
614-
""" Faux message FBO apitools' 'ConfigureRequest'.
629+
"""Faux message for benefit of apitools' 'ConfigureRequest'.
615630
616631
Values extracted from apitools
617632
'samples/storage_sample/storage/storage_v1_client.py'
@@ -625,7 +640,7 @@ class _UploadConfig(object):
625640

626641

627642
class _UrlBuilder(object):
628-
"""Faux builder FBO apitools' 'ConfigureRequest'"""
643+
"""Faux builder for benefit of apitools' 'ConfigureRequest'"""
629644
def __init__(self, bucket_name, object_name):
630645
self.query_params = {'name': object_name}
631646
self._bucket_name = bucket_name

gcloud/storage/test_blob.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,13 +382,14 @@ def test_upload_from_file_resumable(self):
382382
)
383383
bucket = _Bucket(connection)
384384
blob = self._makeOne(BLOB_NAME, bucket=bucket)
385-
blob.CHUNK_SIZE = 5
385+
UPLOAD_CHUNK_SIZE = 5
386386
# Set the threshhold low enough that we force a resumable uploada.
387387
with _Monkey(transfer, _RESUMABLE_UPLOAD_THRESHOLD=5):
388388
with NamedTemporaryFile() as fh:
389389
fh.write(DATA)
390390
fh.flush()
391-
blob.upload_from_file(fh, rewind=True)
391+
blob.upload_from_file(fh, rewind=True,
392+
upload_chunk_size=UPLOAD_CHUNK_SIZE)
392393
rq = connection.http._requested
393394
self.assertEqual(len(rq), 3)
394395
self.assertEqual(rq[0]['method'], 'POST')
@@ -408,16 +409,18 @@ def test_upload_from_file_resumable(self):
408409
self.assertEqual(rq[1]['uri'], UPLOAD_URL)
409410
headers = dict(
410411
[(x.title(), str(y)) for x, y in rq[1]['headers'].items()])
411-
self.assertEqual(rq[1]['body'], DATA[:5])
412+
self.assertEqual(rq[1]['body'], DATA[:UPLOAD_CHUNK_SIZE])
412413
headers = dict(
413414
[(x.title(), str(y)) for x, y in rq[1]['headers'].items()])
414415
self.assertEqual(headers['Content-Range'], 'bytes 0-4/6')
415416
self.assertEqual(rq[2]['method'], 'PUT')
416417
self.assertEqual(rq[2]['uri'], UPLOAD_URL)
417-
self.assertEqual(rq[2]['body'], DATA[5:])
418+
self.assertEqual(rq[2]['body'], DATA[UPLOAD_CHUNK_SIZE:])
418419
headers = dict(
419420
[(x.title(), str(y)) for x, y in rq[2]['headers'].items()])
420-
self.assertEqual(headers['Content-Range'], 'bytes 5-5/6')
421+
content_range = 'bytes %d-%d/%d' % (
422+
UPLOAD_CHUNK_SIZE, UPLOAD_CHUNK_SIZE, len(DATA))
423+
self.assertEqual(headers['Content-Range'], content_range)
421424

422425
def test_upload_from_file_w_slash_in_name(self):
423426
from six.moves.http_client import OK

0 commit comments

Comments
 (0)