Skip to content

Commit

Permalink
Merge pull request #1559 from tseaver/1555-reload_on_missing_media_link
Browse files Browse the repository at this point in the history
#1555: reload missing properties before blob download
  • Loading branch information
tseaver committed Mar 3, 2016
2 parents 63aa65c + 4f16cf5 commit cba090e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
8 changes: 8 additions & 0 deletions gcloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@ def delete(self, client=None):
def download_to_file(self, file_obj, client=None):
"""Download the contents of this blob into a file-like object.
.. note::
If the server-set property, :attr:`media_link`, is not yet
initialized, makes an additional API request to load it.
:type file_obj: file
:param file_obj: A file handle to which to write the blob's data.
Expand All @@ -287,6 +292,9 @@ def download_to_file(self, file_obj, client=None):
:raises: :class:`gcloud.exceptions.NotFound`
"""
client = self._require_client(client)
if self.media_link is None: # not yet loaded
self.reload()

download_url = self.media_link

# Use apitools 'Download' facility.
Expand Down
43 changes: 35 additions & 8 deletions gcloud/storage/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ def test_generate_signed_url_w_method_arg(self):
def test_exists_miss(self):
from six.moves.http_client import NOT_FOUND
NONESUCH = 'nonesuch'
not_found_response = {'status': NOT_FOUND}
not_found_response = ({'status': NOT_FOUND}, b'')
connection = _Connection(not_found_response)
client = _Client(connection)
bucket = _Bucket(client)
Expand All @@ -270,7 +270,7 @@ def test_exists_miss(self):
def test_exists_hit(self):
from six.moves.http_client import OK
BLOB_NAME = 'blob-name'
found_response = {'status': OK}
found_response = ({'status': OK}, b'')
connection = _Connection(found_response)
client = _Client(connection)
bucket = _Bucket(client)
Expand All @@ -281,7 +281,7 @@ def test_exists_hit(self):
def test_delete(self):
from six.moves.http_client import NOT_FOUND
BLOB_NAME = 'blob-name'
not_found_response = {'status': NOT_FOUND}
not_found_response = ({'status': NOT_FOUND}, b'')
connection = _Connection(not_found_response)
client = _Client(connection)
bucket = _Bucket(client)
Expand All @@ -291,6 +291,32 @@ def test_delete(self):
self.assertFalse(blob.exists())
self.assertEqual(bucket._deleted, [(BLOB_NAME, None)])

def test_download_to_file_wo_media_link(self):
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
from io import BytesIO
BLOB_NAME = 'blob-name'
MEDIA_LINK = 'http://example.com/media/'
chunk1_response = {'status': PARTIAL_CONTENT,
'content-range': 'bytes 0-2/6'}
chunk2_response = {'status': OK,
'content-range': 'bytes 3-5/6'}
connection = _Connection(
(chunk1_response, b'abc'),
(chunk2_response, b'def'),
)
# Only the 'reload' request hits on this side: the others are done
# through the 'http' object.
reload_response = {'status': OK, 'content-type': 'application/json'}
connection._responses = [(reload_response, {"mediaLink": MEDIA_LINK})]
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
fh = BytesIO()
blob.download_to_file(fh)
self.assertEqual(fh.getvalue(), b'abcdef')
self.assertEqual(blob.media_link, MEDIA_LINK)

def _download_to_file_helper(self, chunk_size=None):
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
Expand Down Expand Up @@ -749,10 +775,11 @@ def test_upload_from_string_w_text(self):
self.assertEqual(rq[0]['body'], ENCODED)

def test_make_public(self):
from six.moves.http_client import OK
from gcloud.storage.acl import _ACLEntity
BLOB_NAME = 'blob-name'
permissive = [{'entity': 'allUsers', 'role': _ACLEntity.READER_ROLE}]
after = {'acl': permissive}
after = ({'status': OK}, {'acl': permissive})
connection = _Connection(after)
client = _Client(connection)
bucket = _Bucket(client=client)
Expand Down Expand Up @@ -1092,10 +1119,10 @@ def __init__(self, *responses):
def api_request(self, **kw):
from six.moves.http_client import NOT_FOUND
from gcloud.exceptions import NotFound
result = self._respond(**kw)
if result.get('status') == NOT_FOUND:
raise NotFound(result)
return result
info, content = self._respond(**kw)
if info.get('status') == NOT_FOUND:
raise NotFound(info)
return content

def build_api_url(self, path, query_params=None,
api_base_url=API_BASE_URL):
Expand Down

0 comments on commit cba090e

Please sign in to comment.