From 73107c35f23c4a358e957c2b8188300a7fa958fe Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 11 Aug 2020 02:56:07 +0530 Subject: [PATCH] feat: rename 'Blob.download_as_{string,bytes}', add 'Blob.download_as_text' (#182) Leave 'Blob.download_as_string' as a deprecated alias for 'download_as_bytes'. Co-authored-by: Tres Seaver --- google/cloud/storage/blob.py | 176 ++++++++++++++++++++++++++++++++++- tests/system/test_system.py | 89 ++++++++++-------- tests/unit/test_blob.py | 130 +++++++++++++++++++++++--- 3 files changed, 340 insertions(+), 55 deletions(-) diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 07a17867c..1380f41bb 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -1100,7 +1100,7 @@ def download_to_filename( mtime = updated.timestamp() os.utime(file_obj.name, (mtime, mtime)) - def download_as_string( + def download_as_bytes( self, client=None, start=None, @@ -1180,6 +1180,180 @@ def download_as_string( ) return string_buffer.getvalue() + def download_as_string( + self, + client=None, + start=None, + end=None, + raw_download=False, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + ): + """(Deprecated) Download the contents of this blob as a bytes object. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + .. note:: + Deprecated alias for :meth:`download_as_bytes`. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type if_generation_match: long + :param if_generation_match: (Optional) Make the operation conditional on whether + the blob's current generation matches the given value. + Setting to 0 makes the operation succeed only if there + are no live versions of the blob. + + :type if_generation_not_match: long + :param if_generation_not_match: (Optional) Make the operation conditional on whether + the blob's current generation does not match the given + value. If no live blob exists, the precondition fails. + Setting to 0 makes the operation succeed only if there + is a live version of the blob. + + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type timeout: float or tuple + :param timeout: + (Optional) The number of seconds the transport should wait for the + server response. Depending on the retry strategy, a request may be + repeated several times using the same timeout each time. + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + :rtype: bytes + :returns: The data stored in this blob. + + :raises: :class:`google.cloud.exceptions.NotFound` + """ + warnings.warn( + "Blob.download_as_string() is deprecated and will be removed in future." + "Use Blob.download_as_bytes() instead.", + PendingDeprecationWarning, + stacklevel=1, + ) + return self.download_as_bytes( + client=client, + start=start, + end=end, + raw_download=raw_download, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + ) + + def download_as_text( + self, + client=None, + start=None, + end=None, + raw_download=False, + encoding="utf-8", + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + ): + """Download the contents of this blob as a string. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type encoding: str + :param encoding: (Optional) The data of the blob will be decoded by + encoding method. Defaults to UTF-8. Apply only + if the value of ``blob.content_encoding`` is None. + + :type if_generation_match: long + :param if_generation_match: (Optional) Make the operation conditional on whether + the blob's current generation matches the given value. + Setting to 0 makes the operation succeed only if there + are no live versions of the blob. + + :type if_generation_not_match: long + :param if_generation_not_match: (Optional) Make the operation conditional on whether + the blob's current generation does not match the given + value. If no live blob exists, the precondition fails. + Setting to 0 makes the operation succeed only if there + is a live version of the blob. + + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type timeout: float or tuple + :param timeout: + (Optional) The number of seconds the transport should wait for the + server response. Depending on the retry strategy, a request may be + repeated several times using the same timeout each time. + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + :rtype: text + :returns: The data stored in this blob. + + :raises: :class:`google.cloud.exceptions.NotFound` + """ + data = self.download_as_bytes( + client=client, + start=start, + end=end, + raw_download=raw_download, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + ) + + if self.content_encoding: + return data.decode(self.content_encoding) + else: + return data.decode(encoding) + def _get_content_type(self, content_type, filename=None): """Determine the content type from the current object. diff --git a/tests/system/test_system.py b/tests/system/test_system.py index e48f4e230..3fb701d39 100644 --- a/tests/system/test_system.py +++ b/tests/system/test_system.py @@ -421,8 +421,8 @@ def test_copy_existing_file_with_user_project(self): ) to_delete.append(new_blob) - base_contents = blob.download_as_string() - copied_contents = new_blob.download_as_string() + base_contents = blob.download_as_bytes() + copied_contents = new_blob.download_as_bytes() self.assertEqual(base_contents, copied_contents) finally: for blob in to_delete: @@ -451,8 +451,8 @@ def test_copy_file_with_generation_match(self): ) to_delete.append(new_blob) - base_contents = blob.download_as_string() - copied_contents = new_blob.download_as_string() + base_contents = blob.download_as_bytes() + copied_contents = new_blob.download_as_bytes() self.assertEqual(base_contents, copied_contents) finally: for blob in to_delete: @@ -481,8 +481,8 @@ def test_copy_file_with_metageneration_match(self): ) to_delete.append(new_blob) - base_contents = blob.download_as_string() - copied_contents = new_blob.download_as_string() + base_contents = blob.download_as_bytes() + copied_contents = new_blob.download_as_bytes() self.assertEqual(base_contents, copied_contents) finally: for blob in to_delete: @@ -508,7 +508,7 @@ def test_bucket_get_blob_with_user_project(self): to_add.upload_from_string(data) try: found = with_user_project.get_blob("blob-name") - self.assertEqual(found.download_as_string(), data) + self.assertEqual(found.download_as_bytes(), data) finally: to_add.delete() @@ -623,8 +623,8 @@ def test_crud_blob_w_user_project(self): blob.reload() # Exercise 'objects.get' (media) w/ userProject. - self.assertEqual(blob0.download_as_string(), file_contents) - self.assertEqual(blob1.download_as_string(), b"gen1") + self.assertEqual(blob0.download_as_bytes(), file_contents) + self.assertEqual(blob1.download_as_bytes(), b"gen1") # Exercise 'objects.patch' w/ userProject. blob0.content_language = "en" @@ -684,10 +684,10 @@ def test_crud_blob_w_generation_match(self): # Exercise 'objects.get' (media) w/ generation match. self.assertEqual( - blob0.download_as_string(if_generation_match=gen0), file_contents + blob0.download_as_bytes(if_generation_match=gen0), file_contents ) self.assertEqual( - blob1.download_as_string(if_generation_not_match=gen0), b"gen1" + blob1.download_as_bytes(if_generation_not_match=gen0), b"gen1" ) # Exercise 'objects.patch' w/ generation match. @@ -825,8 +825,8 @@ def test_copy_existing_file(self): ) self.case_blobs_to_delete.append(new_blob) - base_contents = blob.download_as_string() - copied_contents = new_blob.download_as_string() + base_contents = blob.download_as_bytes() + copied_contents = new_blob.download_as_bytes() self.assertEqual(base_contents, copied_contents) def test_download_blob_w_uri(self): @@ -846,6 +846,15 @@ def test_download_blob_w_uri(self): self.assertEqual(file_contents, stored_contents) + def test_download_blob_as_text(self): + blob = self.bucket.blob("MyBuffer") + file_contents = "Hello World" + blob.upload_from_string(file_contents) + self.case_blobs_to_delete.append(blob) + + stored_contents = blob.download_as_text() + self.assertEqual(file_contents, stored_contents) + def test_upload_gzip_encoded_download_raw(self): payload = b"DEADBEEF" * 1000 raw_stream = io.BytesIO() @@ -857,10 +866,10 @@ def test_upload_gzip_encoded_download_raw(self): blob.content_encoding = "gzip" blob.upload_from_file(raw_stream, rewind=True) - expanded = blob.download_as_string() + expanded = blob.download_as_bytes() self.assertEqual(expanded, payload) - raw = blob.download_as_string(raw_download=True) + raw = blob.download_as_bytes(raw_download=True) self.assertEqual(raw, zipped) def test_resumable_upload_with_generation_match(self): @@ -920,7 +929,7 @@ def test_fetch_object_and_check_content(self): for blob_name, file_contents in test_data.items(): blob = bucket.blob(blob_name) self.assertEqual(blob.name, blob_name) - self.assertEqual(blob.download_as_string(), file_contents) + self.assertEqual(blob.download_as_bytes(), file_contents) class TestStorageListFiles(TestStorageFiles): @@ -1410,7 +1419,7 @@ def test_compose_create_new_blob(self): destination.compose([source_1, source_2]) self.case_blobs_to_delete.append(destination) - composed = destination.download_as_string() + composed = destination.download_as_bytes() self.assertEqual(composed, SOURCE_1 + SOURCE_2) def test_compose_create_new_blob_wo_content_type(self): @@ -1430,7 +1439,7 @@ def test_compose_create_new_blob_wo_content_type(self): self.case_blobs_to_delete.append(destination) self.assertIsNone(destination.content_type) - composed = destination.download_as_string() + composed = destination.download_as_bytes() self.assertEqual(composed, SOURCE_1 + SOURCE_2) def test_compose_replace_existing_blob(self): @@ -1447,7 +1456,7 @@ def test_compose_replace_existing_blob(self): original.compose([original, to_append]) - composed = original.download_as_string() + composed = original.download_as_bytes() self.assertEqual(composed, BEFORE + TO_APPEND) def test_compose_with_generation_match(self): @@ -1475,7 +1484,7 @@ def test_compose_with_generation_match(self): if_metageneration_match=[original.metageneration, to_append.metageneration], ) - composed = original.download_as_string() + composed = original.download_as_bytes() self.assertEqual(composed, BEFORE + TO_APPEND) @unittest.skipUnless(USER_PROJECT, "USER_PROJECT not set in environment.") @@ -1501,7 +1510,7 @@ def test_compose_with_user_project(self): destination.content_type = "text/plain" destination.compose([source_1, source_2]) - composed = destination.download_as_string() + composed = destination.download_as_bytes() self.assertEqual(composed, SOURCE_1 + SOURCE_2) finally: retry_429_harder(created.delete)(force=True) @@ -1517,7 +1526,7 @@ def test_rewrite_create_new_blob_add_encryption_key(self): source = self.bucket.blob("source") source.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(source) - source_data = source.download_as_string() + source_data = source.download_as_bytes() KEY = os.urandom(32) dest = self.bucket.blob("dest", encryption_key=KEY) @@ -1528,7 +1537,7 @@ def test_rewrite_create_new_blob_add_encryption_key(self): self.assertEqual(rewritten, len(source_data)) self.assertEqual(total, len(source_data)) - self.assertEqual(source.download_as_string(), dest.download_as_string()) + self.assertEqual(source.download_as_bytes(), dest.download_as_bytes()) def test_rewrite_rotate_encryption_key(self): BLOB_NAME = "rotating-keys" @@ -1538,7 +1547,7 @@ def test_rewrite_rotate_encryption_key(self): source = self.bucket.blob(BLOB_NAME, encryption_key=SOURCE_KEY) source.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(source) - source_data = source.download_as_string() + source_data = source.download_as_bytes() DEST_KEY = os.urandom(32) dest = self.bucket.blob(BLOB_NAME, encryption_key=DEST_KEY) @@ -1550,7 +1559,7 @@ def test_rewrite_rotate_encryption_key(self): self.assertEqual(rewritten, len(source_data)) self.assertEqual(total, len(source_data)) - self.assertEqual(dest.download_as_string(), source_data) + self.assertEqual(dest.download_as_bytes(), source_data) @unittest.skipUnless(USER_PROJECT, "USER_PROJECT not set in environment.") def test_rewrite_add_key_with_user_project(self): @@ -1566,7 +1575,7 @@ def test_rewrite_add_key_with_user_project(self): source = with_user_project.blob("source") source.upload_from_filename(file_data["path"]) - source_data = source.download_as_string() + source_data = source.download_as_bytes() KEY = os.urandom(32) dest = with_user_project.blob("dest", encryption_key=KEY) @@ -1576,7 +1585,7 @@ def test_rewrite_add_key_with_user_project(self): self.assertEqual(rewritten, len(source_data)) self.assertEqual(total, len(source_data)) - self.assertEqual(source.download_as_string(), dest.download_as_string()) + self.assertEqual(source.download_as_bytes(), dest.download_as_bytes()) finally: retry_429_harder(created.delete)(force=True) @@ -1596,7 +1605,7 @@ def test_rewrite_rotate_with_user_project(self): SOURCE_KEY = os.urandom(32) source = with_user_project.blob(BLOB_NAME, encryption_key=SOURCE_KEY) source.upload_from_filename(file_data["path"]) - source_data = source.download_as_string() + source_data = source.download_as_bytes() DEST_KEY = os.urandom(32) dest = with_user_project.blob(BLOB_NAME, encryption_key=DEST_KEY) @@ -1606,7 +1615,7 @@ def test_rewrite_rotate_with_user_project(self): self.assertEqual(rewritten, len(source_data)) self.assertEqual(total, len(source_data)) - self.assertEqual(dest.download_as_string(), source_data) + self.assertEqual(dest.download_as_bytes(), source_data) finally: retry_429_harder(created.delete)(force=True) @@ -1622,7 +1631,7 @@ def test_rewrite_with_generation_match(self): source = bucket.blob(BLOB_NAME) source.upload_from_filename(file_data["path"]) - source_data = source.download_as_string() + source_data = source.download_as_bytes() dest = bucket.blob(BLOB_NAME) @@ -1640,7 +1649,7 @@ def test_rewrite_with_generation_match(self): self.assertEqual(token, None) self.assertEqual(rewritten, len(source_data)) self.assertEqual(total, len(source_data)) - self.assertEqual(dest.download_as_string(), source_data) + self.assertEqual(dest.download_as_bytes(), source_data) finally: retry_429_harder(created.delete)(force=True) @@ -1907,7 +1916,7 @@ def test_blob_w_explicit_kms_key_name(self): blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(blob) with open(file_data["path"], "rb") as _file_data: - self.assertEqual(blob.download_as_string(), _file_data.read()) + self.assertEqual(blob.download_as_bytes(), _file_data.read()) # We don't know the current version of the key. self.assertTrue(blob.kms_key_name.startswith(kms_key_name)) @@ -1935,7 +1944,7 @@ def test_bucket_w_default_kms_key_name(self): defaulted_blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(defaulted_blob) - self.assertEqual(defaulted_blob.download_as_string(), contents) + self.assertEqual(defaulted_blob.download_as_bytes(), contents) # We don't know the current version of the key. self.assertTrue(defaulted_blob.kms_key_name.startswith(kms_key_name)) @@ -1947,7 +1956,7 @@ def test_bucket_w_default_kms_key_name(self): override_blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(override_blob) - self.assertEqual(override_blob.download_as_string(), contents) + self.assertEqual(override_blob.download_as_bytes(), contents) # We don't know the current version of the key. self.assertTrue(override_blob.kms_key_name.startswith(alt_kms_key_name)) @@ -1958,7 +1967,7 @@ def test_bucket_w_default_kms_key_name(self): alt_blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(alt_blob) - self.assertEqual(alt_blob.download_as_string(), contents) + self.assertEqual(alt_blob.download_as_bytes(), contents) # We don't know the current version of the key. self.assertTrue(alt_blob.kms_key_name.startswith(alt_kms_key_name)) @@ -1969,7 +1978,7 @@ def test_bucket_w_default_kms_key_name(self): cleartext_blob.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(cleartext_blob) - self.assertEqual(cleartext_blob.download_as_string(), contents) + self.assertEqual(cleartext_blob.download_as_bytes(), contents) self.assertIsNone(cleartext_blob.kms_key_name) def test_rewrite_rotate_csek_to_cmek(self): @@ -1980,7 +1989,7 @@ def test_rewrite_rotate_csek_to_cmek(self): source = self.bucket.blob(BLOB_NAME, encryption_key=SOURCE_KEY) source.upload_from_filename(file_data["path"]) self.case_blobs_to_delete.append(source) - source_data = source.download_as_string() + source_data = source.download_as_bytes() kms_key_name = self._kms_key_name() @@ -2002,7 +2011,7 @@ def test_rewrite_rotate_csek_to_cmek(self): self.assertEqual(rewritten, len(source_data)) self.assertEqual(total, len(source_data)) - self.assertEqual(dest.download_as_string(), source_data) + self.assertEqual(dest.download_as_bytes(), source_data) def test_upload_new_blob_w_bucket_cmek_enabled(self): blob_name = "test-blob" @@ -2022,7 +2031,7 @@ def test_upload_new_blob_w_bucket_cmek_enabled(self): blob.upload_from_string(alt_payload, if_generation_match=blob.generation) self.case_blobs_to_delete.append(blob) - self.assertEqual(blob.download_as_string(), alt_payload) + self.assertEqual(blob.download_as_bytes(), alt_payload) self.bucket.default_kms_key_name = None self.bucket.patch() @@ -2250,7 +2259,7 @@ def test_new_bucket_w_ubla(self): blob.upload_from_string(payload) found = bucket.get_blob(blob_name) - self.assertEqual(found.download_as_string(), payload) + self.assertEqual(found.download_as_bytes(), payload) blob_acl = blob.acl with self.assertRaises(exceptions.BadRequest): diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py index cd4a129d1..68011e438 100644 --- a/tests/unit/test_blob.py +++ b/tests/unit/test_blob.py @@ -1417,7 +1417,7 @@ def test_download_to_filename_w_key(self): stream = blob._do_download.mock_calls[0].args[1] self.assertEqual(stream.name, temp.name) - def _download_as_string_helper(self, raw_download, timeout=None): + def _download_as_bytes_helper(self, raw_download, timeout=None): blob_name = "blob-name" client = mock.Mock(spec=["_http"]) bucket = _Bucket(client) @@ -1428,13 +1428,10 @@ def _download_as_string_helper(self, raw_download, timeout=None): if timeout is None: expected_timeout = self._get_default_timeout() - fetched = blob.download_as_string(raw_download=raw_download) + fetched = blob.download_as_bytes(raw_download=raw_download) else: expected_timeout = timeout - fetched = blob.download_as_string( - raw_download=raw_download, timeout=timeout - ) - + fetched = blob.download_as_bytes(raw_download=raw_download, timeout=timeout) self.assertEqual(fetched, b"") headers = {"accept-encoding": "gzip"} @@ -1501,7 +1498,7 @@ def test_download_as_string_w_hash_response_header_none(self): self.assertIsNone(blob.md5_hash) self.assertIsNone(blob.crc32c) - def test_download_as_string_w_generation_match(self): + def test_download_as_bytes_w_generation_match(self): GENERATION_NUMBER = 6 MEDIA_LINK = "http://example.com/media/" @@ -1511,7 +1508,7 @@ def test_download_as_string_w_generation_match(self): ) blob.download_to_file = mock.Mock() - fetched = blob.download_as_string(if_generation_match=GENERATION_NUMBER) + fetched = blob.download_as_bytes(if_generation_match=GENERATION_NUMBER) self.assertEqual(fetched, b"") blob.download_to_file.assert_called_once_with( @@ -1527,14 +1524,119 @@ def test_download_as_string_w_generation_match(self): timeout=self._get_default_timeout(), ) - def test_download_as_string_wo_raw(self): - self._download_as_string_helper(raw_download=False) + def test_download_as_bytes_wo_raw(self): + self._download_as_bytes_helper(raw_download=False) + + def test_download_as_bytes_w_raw(self): + self._download_as_bytes_helper(raw_download=True) + + def test_download_as_byte_w_custom_timeout(self): + self._download_as_bytes_helper(raw_download=False, timeout=9.58) + + def _download_as_text_helper(self, raw_download, encoding=None, timeout=None): + blob_name = "blob-name" + client = mock.Mock(spec=["_http"]) + bucket = _Bucket(client) + media_link = "http://example.com/media/" + properties = {"mediaLink": media_link} + if encoding: + properties["contentEncoding"] = encoding + blob = self._make_one(blob_name, bucket=bucket, properties=properties) + blob._do_download = mock.Mock() + + if timeout is None: + expected_timeout = self._get_default_timeout() + fetched = blob.download_as_text(raw_download=raw_download) + else: + expected_timeout = timeout + fetched = blob.download_as_text(raw_download=raw_download, timeout=timeout) + + self.assertEqual(fetched, "") + + headers = {"accept-encoding": "gzip"} + blob._do_download.assert_called_once_with( + client._http, + mock.ANY, + media_link, + headers, + None, + None, + raw_download, + timeout=expected_timeout, + ) + stream = blob._do_download.mock_calls[0].args[1] + self.assertIsInstance(stream, io.BytesIO) + + def test_download_as_text_w_generation_match(self): + GENERATION_NUMBER = 6 + MEDIA_LINK = "http://example.com/media/" + + client = mock.Mock(spec=["_http"]) + blob = self._make_one( + "blob-name", bucket=_Bucket(client), properties={"mediaLink": MEDIA_LINK} + ) + blob.download_to_file = mock.Mock() + + fetched = blob.download_as_text(if_generation_match=GENERATION_NUMBER) + self.assertEqual(fetched, "") + + blob.download_to_file.assert_called_once_with( + mock.ANY, + client=None, + start=None, + end=None, + raw_download=False, + if_generation_match=GENERATION_NUMBER, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=self._get_default_timeout(), + ) + + def test_download_as_text_wo_raw(self): + self._download_as_text_helper(raw_download=False) + + def test_download_as_text_w_raw(self): + self._download_as_text_helper(raw_download=True) - def test_download_as_string_w_raw(self): - self._download_as_string_helper(raw_download=True) + def test_download_as_text_w_custom_timeout(self): + self._download_as_text_helper(raw_download=False, timeout=9.58) - def test_download_as_string_w_custom_timeout(self): - self._download_as_string_helper(raw_download=False, timeout=9.58) + def test_download_as_text_w_encoding(self): + self._download_as_text_helper(raw_download=False, encoding="utf-8") + + @mock.patch("warnings.warn") + def test_download_as_string(self, mock_warn): + MEDIA_LINK = "http://example.com/media/" + + client = mock.Mock(spec=["_http"]) + blob = self._make_one( + "blob-name", bucket=_Bucket(client), properties={"mediaLink": MEDIA_LINK} + ) + blob.download_to_file = mock.Mock() + + fetched = blob.download_as_string() + self.assertEqual(fetched, b"") + + blob.download_to_file.assert_called_once_with( + mock.ANY, + client=None, + start=None, + end=None, + raw_download=False, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=self._get_default_timeout(), + ) + + mock_warn.assert_called_with( + "Blob.download_as_string() is deprecated and will be removed in future." + "Use Blob.download_as_bytes() instead.", + PendingDeprecationWarning, + stacklevel=1, + ) def test__get_content_type_explicit(self): blob = self._make_one(u"blob-name", bucket=None)