Skip to content

Commit 4de2450

Browse files
authored
Streaming directly into file on storage downloads. (googleapis#3713)
1 parent ac23b77 commit 4de2450

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

storage/google/cloud/storage/blob.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,8 @@ def _do_download(self, transport, file_obj, download_url, headers):
414414
:param headers: Optional headers to be sent with the request(s).
415415
"""
416416
if self.chunk_size is None:
417-
download = Download(download_url, headers=headers)
418-
response = download.consume(transport)
419-
file_obj.write(response.content)
417+
download = Download(download_url, stream=file_obj, headers=headers)
418+
download.consume(transport)
420419
else:
421420
download = ChunkedDownload(
422421
download_url, self.chunk_size, file_obj, headers=headers)

storage/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
REQUIREMENTS = [
5454
'google-cloud-core >= 0.25.0, < 0.26dev',
5555
'google-auth >= 1.0.0',
56-
'google-resumable-media >= 0.2.1',
56+
'google-resumable-media >= 0.2.2',
5757
'requests >= 2.0.0',
5858
]
5959

storage/tests/unit/test_blob.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -375,13 +375,20 @@ def test__get_download_url_on_the_fly_with_generation(self):
375375
self.assertEqual(download_url, expected_url)
376376

377377
@staticmethod
378-
def _mock_requests_response(status_code, headers, content=b''):
378+
def _mock_requests_response(
379+
status_code, headers, content=b'', stream=False):
379380
import requests
380381

381382
response = requests.Response()
382383
response.status_code = status_code
383384
response.headers.update(headers)
384-
response._content = content
385+
if stream:
386+
response.raw = io.BytesIO(content)
387+
response._content = False
388+
else:
389+
response.raw = None
390+
response._content = content
391+
385392
response.request = requests.Request(
386393
'POST', 'http://example.com').prepare()
387394
return response
@@ -429,7 +436,9 @@ def test__do_download_simple(self):
429436
transport.request.return_value = self._mock_requests_response(
430437
http_client.OK,
431438
{'content-length': '6', 'content-range': 'bytes 0-5/6'},
432-
content=b'abcdef')
439+
content=b'abcdef',
440+
stream=True,
441+
)
433442
file_obj = io.BytesIO()
434443
download_url = 'http://test.invalid'
435444
headers = {}
@@ -438,7 +447,7 @@ def test__do_download_simple(self):
438447
self.assertEqual(file_obj.getvalue(), b'abcdef')
439448

440449
transport.request.assert_called_once_with(
441-
'GET', download_url, data=None, headers=headers)
450+
'GET', download_url, data=None, headers=headers, stream=True)
442451

443452
def test__do_download_chunked(self):
444453
blob_name = 'blob-name'
@@ -493,7 +502,7 @@ def test_download_to_file_with_failure(self):
493502
self.assertEqual(file_obj.tell(), 0)
494503
# Check that the transport was called once.
495504
transport.request.assert_called_once_with(
496-
'GET', blob.media_link, data=None, headers={})
505+
'GET', blob.media_link, data=None, headers={}, stream=True)
497506

498507
def test_download_to_file_wo_media_link(self):
499508
blob_name = 'blob-name'
@@ -535,7 +544,9 @@ def _download_to_file_helper(self, use_chunks=False):
535544
single_chunk_response = self._mock_requests_response(
536545
http_client.OK,
537546
{'content-length': '6', 'content-range': 'bytes 0-5/6'},
538-
content=b'abcdef')
547+
content=b'abcdef',
548+
stream=True,
549+
)
539550
transport.request.side_effect = [single_chunk_response]
540551

541552
file_obj = io.BytesIO()
@@ -546,7 +557,7 @@ def _download_to_file_helper(self, use_chunks=False):
546557
self._check_session_mocks(client, transport, media_link)
547558
else:
548559
transport.request.assert_called_once_with(
549-
'GET', media_link, data=None, headers={})
560+
'GET', media_link, data=None, headers={}, stream=True)
550561

551562
def test_download_to_file_default(self):
552563
self._download_to_file_helper()

0 commit comments

Comments
 (0)