Better handling of streams that report their size as 0.
Reviewed in http://codereview.appspot.com/6300093/. Fixes issue #146.
This commit is contained in:
@@ -289,7 +289,6 @@ class MediaIoBaseUpload(MediaUpload):
|
||||
Note that the Python file object is compatible with io.Base and can be used
|
||||
with this class also.
|
||||
|
||||
|
||||
fh = io.BytesIO('...Some data to upload...')
|
||||
media = MediaIoBaseUpload(fh, mimetype='image/png',
|
||||
chunksize=1024*1024, resumable=True)
|
||||
@@ -304,7 +303,8 @@ class MediaIoBaseUpload(MediaUpload):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
fh: io.Base or file object, The source of the bytes to upload.
|
||||
fh: io.Base or file object, The source of the bytes to upload. MUST be
|
||||
opened in blocking mode, do not use streams opened in non-blocking mode.
|
||||
mimetype: string, Mime-type of the file. If None then a mime-type will be
|
||||
guessed from the file extension.
|
||||
chunksize: int, File will be uploaded in chunks of this many bytes. Only
|
||||
@@ -320,7 +320,11 @@ class MediaIoBaseUpload(MediaUpload):
|
||||
try:
|
||||
if hasattr(self._fh, 'fileno'):
|
||||
fileno = self._fh.fileno()
|
||||
self._size = os.fstat(fileno).st_size
|
||||
|
||||
# Pipes and such show up as 0 length files.
|
||||
size = os.fstat(fileno).st_size
|
||||
if size:
|
||||
self._size = os.fstat(fileno).st_size
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
@@ -616,6 +620,11 @@ class HttpRequest(object):
|
||||
|
||||
data = self.resumable.getbytes(
|
||||
self.resumable_progress, self.resumable.chunksize())
|
||||
|
||||
# A short read implies that we are at EOF, so finish the upload.
|
||||
if len(data) < self.resumable.chunksize():
|
||||
size = str(self.resumable_progress + len(data))
|
||||
|
||||
headers = {
|
||||
'Content-Range': 'bytes %d-%d/%s' % (
|
||||
self.resumable_progress, self.resumable_progress + len(data) - 1,
|
||||
|
||||
@@ -560,12 +560,32 @@ class Discovery(unittest.TestCase):
|
||||
|
||||
# Create an upload that doesn't know the full size of the media.
|
||||
upload = MediaIoBaseUpload(
|
||||
fh=fh, mimetype='image/png', chunksize=500, resumable=True)
|
||||
fh=fh, mimetype='image/png', chunksize=10, resumable=True)
|
||||
|
||||
request = zoo.animals().insert(media_body=upload, body=None)
|
||||
status, body = request.next_chunk(http)
|
||||
self.assertEqual(body, {'Content-Range': 'bytes 0-13/*'},
|
||||
'Should be 14 out of * bytes.')
|
||||
self.assertEqual(body, {'Content-Range': 'bytes 0-9/*'},
|
||||
'Should be 10 out of * bytes.')
|
||||
|
||||
def test_resumable_media_handle_uploads_of_unknown_size_eof(self):
|
||||
http = HttpMockSequence([
|
||||
({'status': '200',
|
||||
'location': 'http://upload.example.com'}, ''),
|
||||
({'status': '200'}, 'echo_request_headers_as_json'),
|
||||
])
|
||||
|
||||
self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
|
||||
zoo = build('zoo', 'v1', self.http)
|
||||
|
||||
fh = StringIO.StringIO('data goes here')
|
||||
|
||||
# Create an upload that doesn't know the full size of the media.
|
||||
upload = MediaIoBaseUpload(
|
||||
fh=fh, mimetype='image/png', chunksize=15, resumable=True)
|
||||
|
||||
request = zoo.animals().insert(media_body=upload, body=None)
|
||||
status, body = request.next_chunk(http)
|
||||
self.assertEqual(body, {'Content-Range': 'bytes 0-13/14'})
|
||||
|
||||
def test_resumable_media_handle_resume_of_upload_of_unknown_size(self):
|
||||
http = HttpMockSequence([
|
||||
|
||||
Reference in New Issue
Block a user