google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_cla -->
google-cla[bot]: All (the pull request submitter and all commit authors) CLAs are signed, **but** one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project.  Please have them confirm that by leaving a comment that contains only `@googlebot I consent.` in this pull request.

*Note to project maintainer:* There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent.  In those cases, you can manually confirm consent of the commit author(s), and set the `cla` label to `yes` (if enabled on your project).

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_consent -->
google-cla[bot]: All (the pull request submitter and all commit authors) CLAs are signed, **but** one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project.  Please have them confirm that by leaving a comment that contains only `@googlebot I consent.` in this pull request.

*Note to project maintainer:* There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent.  In those cases, you can manually confirm consent of the commit author(s), and set the `cla` label to `yes` (if enabled on your project).

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_consent -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_cla -->
googlebot: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_cla -->
MartinKilonzo: Thanks for the review!
Added the proposed changes. @tseaver, would you mind checking your CLA per @googlebot: 

> We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
> In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.
> 
> ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.
tseaver: @googlebot I consent
google-cla[bot]: All (the pull request submitter and all commit authors) CLAs are signed, **but** one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project.  Please have them confirm that by leaving a comment that contains only `@googlebot I consent.` in this pull request.

*Note to project maintainer:* There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent.  In those cases, you can manually confirm consent of the commit author(s), and set the `cla` label to `yes` (if enabled on your project).

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- need_author_consent -->
tseaver: @googlebot I consent
google-cla[bot]: CLAs look good, thanks!

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F267) for more info**.

<!-- ok -->
google-cla[bot]: :frowning_face: Sorry, but only Googlers may change the label `cla: yes`.
diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py
index 2c28f69..a7e6952 100644
--- a/google/cloud/storage/blob.py
+++ b/google/cloud/storage/blob.py
@@ -811,15 +811,16 @@ class Blob(_PropertyMixin):
         #  'X-Goog-Hash': 'crc32c=4gcgLQ==,md5=CS9tHYTtyFntzj7B9nkkJQ==',
         x_goog_hash = response.headers.get("X-Goog-Hash", "")
 
-        digests = {}
-        for encoded_digest in x_goog_hash.split(","):
-            match = re.match(r"(crc32c|md5)=([\w\d/\+/]+={0,3})", encoded_digest)
-            if match:
-                method, digest = match.groups()
-                digests[method] = digest
-
-        self.crc32c = digests.get("crc32c", None)
-        self.md5_hash = digests.get("md5", None)
+        if x_goog_hash:
+            digests = {}
+            for encoded_digest in x_goog_hash.split(","):
+                match = re.match(r"(crc32c|md5)=([\w\d/\+/]+={0,3})", encoded_digest)
+                if match:
+                    method, digest = match.groups()
+                    digests[method] = digest
+
+            self.crc32c = digests.get("crc32c", None)
+            self.md5_hash = digests.get("md5", None)
 
     def _do_download(
         self,

Hashes are no longer returned for partial downloads
#204 Changed behavior for hashes for partial downloads. 
When a partial request is made, we do not return the 'X-Goog-Hash' headers. As a result,
[blob.py:812](https://github.com/googleapis/python-storage/pull/204/files#diff-5d3277a5f0f072a447a1eb89f9fa1ae0R812) overwrites the `blob.crc32c` value with its default, `None`.
[blob.py:813](https://github.com/googleapis/python-storage/pull/204/files#diff-5d3277a5f0f072a447a1eb89f9fa1ae0R813) overwrites the `blob.md5_hash` value with its default, `None`.

#### Environment details

  - OS type and version: Linux 4.19.0-10-cloud-amd64 #1 SMP Debian 4.19.132-1 (2020-07-24) x86_64
  - Python version: `python --version`: 3.7.3, 3.8.2
  - pip version: `pip --version` 18.1
  - `google-cloud-storage` version: `pip show google-cloud-storage` 1.30+

#### Steps to reproduce
1. Get blob
2. issue a partial download (ie `blob.download_to_filename(start=0)`
3. Notice `blob.md5_hash` and `blob.crc32c` are `None`.

#### Code example

```python
client = storage.Client()
bucket = client.get_bucket(BUCKET_ID)
blob = bucket.get_blob(FILE_NAME)
print('blob.md5_hash: {:}'.format(blob.md5_hash)) # blob.md5_hash: 3qgj3i0eVt8mnNjtSErqZQ==
print('blob.crc32c: {:}'.format(blob.crc32c)) # blob.crc32c: AeFI7Q==

# MD5
blob.download_to_filename(FILE_NAME)
print('blob.md5_hash: {:}'.format(blob.md5_hash)) # blob.md5_hash: 3qgj3i0eVt8mnNjtSErqZQ==
blob.download_to_filename(FILE_NAME, start=0)
print('blob.md5_hash: {:}'.format(blob.md5_hash)) # blob.md5_hash: None

# CRC32C
blob.download_to_filename(FILE_NAME)
print('blob.crc32c: {:}'.format(blob.crc32c)) # blob.crc32c: AeFI7Q==
blob.download_to_filename(FILE_NAME, start=0)
print('blob.crc32c: {:}'.format(blob.crc32c)) # blob.crc32c: None
```

diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py
index 0c9e592..f67b650 100644
--- a/tests/unit/test_blob.py
+++ b/tests/unit/test_blob.py
@@ -1542,10 +1542,16 @@ class Test_Blob(unittest.TestCase):
 
     def test_download_as_string_w_hash_response_header_none(self):
         blob_name = "blob-name"
+        md5_hash = "CS9tHYTtyFntzj7B9nkkJQ=="
+        crc32c = "4gcgLQ=="
         client = mock.Mock(spec=["_http"])
         bucket = _Bucket(client)
         media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
+        properties = {
+            "mediaLink": media_link,
+            "md5Hash": md5_hash,
+            "crc32c": crc32c,
+        }
         blob = self._make_one(blob_name, bucket=bucket, properties=properties)
 
         response = self._mock_requests_response(
@@ -1556,8 +1562,8 @@ class Test_Blob(unittest.TestCase):
         )
         blob._extract_headers_from_download(response)
 
-        self.assertIsNone(blob.md5_hash)
-        self.assertIsNone(blob.crc32c)
+        self.assertEqual(blob.md5_hash, md5_hash)
+        self.assertEqual(blob.crc32c, crc32c)
 
     def test_download_as_bytes_w_generation_match(self):
         GENERATION_NUMBER = 6

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov mock
apt-get update apt-get install -y gcc
3.9
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
cachetools==4.2.4
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
exceptiongroup==1.2.2
google-api-core==2.10.2
google-auth==1.35.0
google-cloud-core==1.7.3
-e git+https://github.com/googleapis/python-storage.git@ec52b38df211fad18a86d7e16d83db79de59d5f5#egg=google_cloud_storage
google-crc32c==1.7.1
google-resumable-media==1.3.3
googleapis-common-protos==1.69.2
idna==3.10
iniconfig==2.1.0
mock==5.2.0
packaging==24.2
pluggy==1.5.0
protobuf==4.25.6
pyasn1==0.6.1
pyasn1_modules==0.4.2
pytest==8.3.5
pytest-cov==6.0.0
requests==2.32.3
rsa==4.9
six==1.17.0
tomli==2.2.1
urllib3==2.3.0

name: python-storage
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - cachetools==4.2.4
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - google-api-core==2.10.2
      - google-auth==1.35.0
      - google-cloud-core==1.7.3
      - google-crc32c==1.7.1
      - google-resumable-media==1.3.3
      - googleapis-common-protos==1.69.2
      - idna==3.10
      - iniconfig==2.1.0
      - mock==5.2.0
      - packaging==24.2
      - pluggy==1.5.0
      - protobuf==4.25.6
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - requests==2.32.3
      - rsa==4.9
      - six==1.17.0
      - tomli==2.2.1
      - urllib3==2.3.0
prefix: /opt/conda/envs/python-storage

tests/unit/test_blob.py::Test_Blob::test_download_as_string_w_hash_response_header_none
tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_w_checksum tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_w_range_w_raw tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_w_range_wo_raw tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_wo_checksum tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_wo_range_w_raw tests/unit/test_blob.py::Test_Blob::test__do_download_w_chunks_wo_range_wo_raw tests/unit/test_blob.py::Test_Blob::test__do_download_wo_chunks_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test__do_download_wo_chunks_w_range_w_raw tests/unit/test_blob.py::Test_Blob::test__do_download_wo_chunks_w_range_wo_raw tests/unit/test_blob.py::Test_Blob::test__do_download_wo_chunks_wo_range_w_raw tests/unit/test_blob.py::Test_Blob::test__do_download_wo_chunks_wo_range_wo_raw tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_bad_size tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_no_size tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_custom_timeout tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_generation_match tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_generation_not_match tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_kms tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_kms_with_version tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_retry tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_size tests/unit/test_blob.py::Test_Blob::test__do_multipart_upload_with_user_project tests/unit/test_blob.py::Test_Blob::test__do_resumable_upload_no_size tests/unit/test_blob.py::Test_Blob::test__do_resumable_upload_with_custom_timeout tests/unit/test_blob.py::Test_Blob::test__do_resumable_upload_with_data_corruption tests/unit/test_blob.py::Test_Blob::test__do_resumable_upload_with_predefined_acl tests/unit/test_blob.py::Test_Blob::test__do_resumable_upload_with_retry tests/unit/test_blob.py::Test_Blob::test__do_resumable_upload_with_size tests/unit/test_blob.py::Test_Blob::test__do_upload_uses_multipart tests/unit/test_blob.py::Test_Blob::test__do_upload_uses_multipart_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test__do_upload_uses_resumable tests/unit/test_blob.py::Test_Blob::test__do_upload_uses_resumable_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test__do_upload_with_retry tests/unit/test_blob.py::Test_Blob::test__encryption_headers_w_encryption_key tests/unit/test_blob.py::Test_Blob::test__encryption_headers_wo_encryption_key tests/unit/test_blob.py::Test_Blob::test__get_content_type_default tests/unit/test_blob.py::Test_Blob::test__get_content_type_explicit tests/unit/test_blob.py::Test_Blob::test__get_content_type_from_blob tests/unit/test_blob.py::Test_Blob::test__get_content_type_from_filename tests/unit/test_blob.py::Test_Blob::test__get_download_url_on_the_fly tests/unit/test_blob.py::Test_Blob::test__get_download_url_on_the_fly_with_generation tests/unit/test_blob.py::Test_Blob::test__get_download_url_on_the_fly_with_kms_key_name tests/unit/test_blob.py::Test_Blob::test__get_download_url_on_the_fly_with_user_project tests/unit/test_blob.py::Test_Blob::test__get_download_url_with_generation_match tests/unit/test_blob.py::Test_Blob::test__get_download_url_with_media_link tests/unit/test_blob.py::Test_Blob::test__get_download_url_with_media_link_w_user_project tests/unit/test_blob.py::Test_Blob::test__get_transport tests/unit/test_blob.py::Test_Blob::test__get_upload_arguments tests/unit/test_blob.py::Test_Blob::test__get_writable_metadata_no_changes tests/unit/test_blob.py::Test_Blob::test__get_writable_metadata_unwritable_field tests/unit/test_blob.py::Test_Blob::test__get_writable_metadata_with_changes tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_no_size tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_chunk_size tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_custom_timeout tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_extra_headers tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_generation_match tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_generation_not_match tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_kms tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_kms_with_version tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_predefined_acl tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_retry tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_size tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_with_user_project tests/unit/test_blob.py::Test_Blob::test__initiate_resumable_upload_without_chunk_size tests/unit/test_blob.py::Test_Blob::test__query_params_default tests/unit/test_blob.py::Test_Blob::test__query_params_w_generation tests/unit/test_blob.py::Test_Blob::test__query_params_w_user_project tests/unit/test_blob.py::Test_Blob::test__set_metadata_to_none tests/unit/test_blob.py::Test_Blob::test__set_properties_w_kms_key_name tests/unit/test_blob.py::Test_Blob::test__set_properties_wo_kms_key_name tests/unit/test_blob.py::Test_Blob::test_acl_property tests/unit/test_blob.py::Test_Blob::test_bucket_readonly_property tests/unit/test_blob.py::Test_Blob::test_cache_control_getter tests/unit/test_blob.py::Test_Blob::test_cache_control_setter tests/unit/test_blob.py::Test_Blob::test_chunk_size_ctor tests/unit/test_blob.py::Test_Blob::test_chunk_size_getter tests/unit/test_blob.py::Test_Blob::test_chunk_size_setter tests/unit/test_blob.py::Test_Blob::test_chunk_size_setter_bad_value tests/unit/test_blob.py::Test_Blob::test_client tests/unit/test_blob.py::Test_Blob::test_component_count tests/unit/test_blob.py::Test_Blob::test_component_count_string_val tests/unit/test_blob.py::Test_Blob::test_component_count_unset tests/unit/test_blob.py::Test_Blob::test_compose_minimal_w_user_project tests/unit/test_blob.py::Test_Blob::test_compose_w_additional_property_changes tests/unit/test_blob.py::Test_Blob::test_compose_w_generation_match tests/unit/test_blob.py::Test_Blob::test_compose_w_generation_match_bad_length tests/unit/test_blob.py::Test_Blob::test_compose_w_generation_match_nones tests/unit/test_blob.py::Test_Blob::test_compose_wo_content_type_set tests/unit/test_blob.py::Test_Blob::test_content_disposition_getter tests/unit/test_blob.py::Test_Blob::test_content_disposition_setter tests/unit/test_blob.py::Test_Blob::test_content_encoding_getter tests/unit/test_blob.py::Test_Blob::test_content_encoding_setter tests/unit/test_blob.py::Test_Blob::test_content_language_getter tests/unit/test_blob.py::Test_Blob::test_content_language_setter tests/unit/test_blob.py::Test_Blob::test_content_type_getter tests/unit/test_blob.py::Test_Blob::test_content_type_setter tests/unit/test_blob.py::Test_Blob::test_crc32c_getter tests/unit/test_blob.py::Test_Blob::test_crc32c_setter tests/unit/test_blob.py::Test_Blob::test_create_resumable_upload_session tests/unit/test_blob.py::Test_Blob::test_create_resumable_upload_session_with_custom_timeout tests/unit/test_blob.py::Test_Blob::test_create_resumable_upload_session_with_failure tests/unit/test_blob.py::Test_Blob::test_create_resumable_upload_session_with_origin tests/unit/test_blob.py::Test_Blob::test_ctor_w_encryption_key tests/unit/test_blob.py::Test_Blob::test_ctor_w_kms_key_name tests/unit/test_blob.py::Test_Blob::test_ctor_w_kms_key_name_and_encryption_key tests/unit/test_blob.py::Test_Blob::test_ctor_with_encoded_unicode tests/unit/test_blob.py::Test_Blob::test_ctor_with_generation tests/unit/test_blob.py::Test_Blob::test_ctor_wo_encryption_key tests/unit/test_blob.py::Test_Blob::test_custom_time_getter tests/unit/test_blob.py::Test_Blob::test_custom_time_setter tests/unit/test_blob.py::Test_Blob::test_custom_time_setter_none_value tests/unit/test_blob.py::Test_Blob::test_custom_time_unset tests/unit/test_blob.py::Test_Blob::test_delete_w_generation tests/unit/test_blob.py::Test_Blob::test_delete_w_generation_match tests/unit/test_blob.py::Test_Blob::test_delete_wo_generation tests/unit/test_blob.py::Test_Blob::test_download_as_byte_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test_download_as_bytes_w_generation_match tests/unit/test_blob.py::Test_Blob::test_download_as_bytes_w_raw tests/unit/test_blob.py::Test_Blob::test_download_as_bytes_wo_raw tests/unit/test_blob.py::Test_Blob::test_download_as_string tests/unit/test_blob.py::Test_Blob::test_download_as_string_w_response_headers tests/unit/test_blob.py::Test_Blob::test_download_as_text_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test_download_as_text_w_encoding tests/unit/test_blob.py::Test_Blob::test_download_as_text_w_generation_match tests/unit/test_blob.py::Test_Blob::test_download_as_text_w_raw tests/unit/test_blob.py::Test_Blob::test_download_as_text_wo_raw tests/unit/test_blob.py::Test_Blob::test_download_to_file_w_chunks_w_raw tests/unit/test_blob.py::Test_Blob::test_download_to_file_w_chunks_wo_raw tests/unit/test_blob.py::Test_Blob::test_download_to_file_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test_download_to_file_w_generation_match tests/unit/test_blob.py::Test_Blob::test_download_to_file_with_failure tests/unit/test_blob.py::Test_Blob::test_download_to_file_wo_chunks_w_raw tests/unit/test_blob.py::Test_Blob::test_download_to_file_wo_chunks_wo_raw tests/unit/test_blob.py::Test_Blob::test_download_to_file_wo_media_link tests/unit/test_blob.py::Test_Blob::test_download_to_filename_corrupted tests/unit/test_blob.py::Test_Blob::test_download_to_filename_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test_download_to_filename_w_generation_match tests/unit/test_blob.py::Test_Blob::test_download_to_filename_w_key tests/unit/test_blob.py::Test_Blob::test_download_to_filename_w_updated_w_raw tests/unit/test_blob.py::Test_Blob::test_download_to_filename_w_updated_wo_raw tests/unit/test_blob.py::Test_Blob::test_download_to_filename_wo_updated_w_raw tests/unit/test_blob.py::Test_Blob::test_download_to_filename_wo_updated_wo_raw tests/unit/test_blob.py::Test_Blob::test_etag tests/unit/test_blob.py::Test_Blob::test_event_based_hold_getter_false tests/unit/test_blob.py::Test_Blob::test_event_based_hold_getter_missing tests/unit/test_blob.py::Test_Blob::test_event_based_hold_getter_true tests/unit/test_blob.py::Test_Blob::test_event_based_hold_setter tests/unit/test_blob.py::Test_Blob::test_exists_hit_w_generation tests/unit/test_blob.py::Test_Blob::test_exists_hit_w_user_project tests/unit/test_blob.py::Test_Blob::test_exists_miss tests/unit/test_blob.py::Test_Blob::test_exists_w_generation_match tests/unit/test_blob.py::Test_Blob::test_from_string_w_domain_name_bucket tests/unit/test_blob.py::Test_Blob::test_from_string_w_invalid_uri tests/unit/test_blob.py::Test_Blob::test_from_string_w_valid_uri tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_no_version_passed_warning tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_content_md5 tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_content_type tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_credentials tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_csek tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_csek_and_headers tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_defaults tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_endpoint tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_expiration tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_generation tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_headers tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_lowercase_method tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_method tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_non_ascii_name tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_response_disposition tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_response_type tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_slash_in_name tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v2_w_tilde_in_name tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_bucket_bound_hostname_w_bare_hostname tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_bucket_bound_hostname_w_scheme tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_content_md5 tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_content_type tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_credentials tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_csek tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_csek_and_headers tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_defaults tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_endpoint tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_generation tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_headers tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_lowercase_method tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_method tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_non_ascii_name tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_response_disposition tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_response_type tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_slash_in_name tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_tilde_in_name tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_v4_w_virtual_hostname tests/unit/test_blob.py::Test_Blob::test_generate_signed_url_w_invalid_version tests/unit/test_blob.py::Test_Blob::test_generation tests/unit/test_blob.py::Test_Blob::test_generation_string_val tests/unit/test_blob.py::Test_Blob::test_generation_unset tests/unit/test_blob.py::Test_Blob::test_get_iam_policy tests/unit/test_blob.py::Test_Blob::test_get_iam_policy_w_requested_policy_version tests/unit/test_blob.py::Test_Blob::test_get_iam_policy_w_user_project tests/unit/test_blob.py::Test_Blob::test_id tests/unit/test_blob.py::Test_Blob::test_make_private tests/unit/test_blob.py::Test_Blob::test_make_public tests/unit/test_blob.py::Test_Blob::test_md5_hash_getter tests/unit/test_blob.py::Test_Blob::test_md5_hash_setter tests/unit/test_blob.py::Test_Blob::test_media_link tests/unit/test_blob.py::Test_Blob::test_metadata_getter tests/unit/test_blob.py::Test_Blob::test_metadata_setter tests/unit/test_blob.py::Test_Blob::test_metadata_setter_w_nan tests/unit/test_blob.py::Test_Blob::test_metageneration tests/unit/test_blob.py::Test_Blob::test_metageneration_string_val tests/unit/test_blob.py::Test_Blob::test_metageneration_unset tests/unit/test_blob.py::Test_Blob::test_owner tests/unit/test_blob.py::Test_Blob::test_path_bad_bucket tests/unit/test_blob.py::Test_Blob::test_path_no_name tests/unit/test_blob.py::Test_Blob::test_path_normal tests/unit/test_blob.py::Test_Blob::test_path_w_slash_in_name tests/unit/test_blob.py::Test_Blob::test_path_with_non_ascii tests/unit/test_blob.py::Test_Blob::test_public_url tests/unit/test_blob.py::Test_Blob::test_public_url_w_slash_in_name tests/unit/test_blob.py::Test_Blob::test_public_url_w_tilde_in_name tests/unit/test_blob.py::Test_Blob::test_public_url_with_non_ascii tests/unit/test_blob.py::Test_Blob::test_retention_expiration_time tests/unit/test_blob.py::Test_Blob::test_retention_expiration_time_unset tests/unit/test_blob.py::Test_Blob::test_rewrite_other_bucket_other_name_no_encryption_partial tests/unit/test_blob.py::Test_Blob::test_rewrite_response_without_resource tests/unit/test_blob.py::Test_Blob::test_rewrite_same_name_no_key_new_key_w_token tests/unit/test_blob.py::Test_Blob::test_rewrite_same_name_no_old_key_new_key_done_w_user_project tests/unit/test_blob.py::Test_Blob::test_rewrite_same_name_w_old_key_new_kms_key tests/unit/test_blob.py::Test_Blob::test_rewrite_w_generation_match tests/unit/test_blob.py::Test_Blob::test_rewrite_w_generations tests/unit/test_blob.py::Test_Blob::test_self_link tests/unit/test_blob.py::Test_Blob::test_set_iam_policy tests/unit/test_blob.py::Test_Blob::test_set_iam_policy_w_user_project tests/unit/test_blob.py::Test_Blob::test_size tests/unit/test_blob.py::Test_Blob::test_size_string_val tests/unit/test_blob.py::Test_Blob::test_size_unset tests/unit/test_blob.py::Test_Blob::test_storage_class_getter tests/unit/test_blob.py::Test_Blob::test_storage_class_setter tests/unit/test_blob.py::Test_Blob::test_temporary_hold_getter_false tests/unit/test_blob.py::Test_Blob::test_temporary_hold_getter_missing tests/unit/test_blob.py::Test_Blob::test_temporary_hold_getter_true tests/unit/test_blob.py::Test_Blob::test_temporary_hold_setter tests/unit/test_blob.py::Test_Blob::test_test_iam_permissions tests/unit/test_blob.py::Test_Blob::test_test_iam_permissions_w_user_project tests/unit/test_blob.py::Test_Blob::test_time_created tests/unit/test_blob.py::Test_Blob::test_time_created_unset tests/unit/test_blob.py::Test_Blob::test_time_deleted tests/unit/test_blob.py::Test_Blob::test_time_deleted_unset tests/unit/test_blob.py::Test_Blob::test_update_storage_class_invalid tests/unit/test_blob.py::Test_Blob::test_update_storage_class_large_file tests/unit/test_blob.py::Test_Blob::test_update_storage_class_w_encryption_key_w_user_project tests/unit/test_blob.py::Test_Blob::test_update_storage_class_w_generation_match tests/unit/test_blob.py::Test_Blob::test_update_storage_class_with_custom_timeout tests/unit/test_blob.py::Test_Blob::test_update_storage_class_wo_encryption_key tests/unit/test_blob.py::Test_Blob::test_updated tests/unit/test_blob.py::Test_Blob::test_updated_unset tests/unit/test_blob.py::Test_Blob::test_upload_from_file_failure tests/unit/test_blob.py::Test_Blob::test_upload_from_file_success tests/unit/test_blob.py::Test_Blob::test_upload_from_file_with_custom_timeout tests/unit/test_blob.py::Test_Blob::test_upload_from_file_with_retries tests/unit/test_blob.py::Test_Blob::test_upload_from_file_with_rewind tests/unit/test_blob.py::Test_Blob::test_upload_from_filename tests/unit/test_blob.py::Test_Blob::test_upload_from_filename_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test_upload_from_string_w_bytes tests/unit/test_blob.py::Test_Blob::test_upload_from_string_w_custom_timeout tests/unit/test_blob.py::Test_Blob::test_upload_from_string_w_text tests/unit/test_blob.py::Test_Blob::test_user_project tests/unit/test_blob.py::Test__quote::test_bad_type tests/unit/test_blob.py::Test__quote::test_bytes tests/unit/test_blob.py::Test__quote::test_unicode tests/unit/test_blob.py::Test__quote::test_w_slash_default tests/unit/test_blob.py::Test__quote::test_w_slash_w_safe tests/unit/test_blob.py::Test__quote::test_w_tilde tests/unit/test_blob.py::Test__maybe_rewind::test_default tests/unit/test_blob.py::Test__maybe_rewind::test_do_not_rewind tests/unit/test_blob.py::Test__maybe_rewind::test_do_rewind tests/unit/test_blob.py::Test__raise_from_invalid_response::test_default tests/unit/test_blob.py::Test__raise_from_invalid_response::test_w_206_and_args tests/unit/test_blob.py::Test__add_query_parameters::test_w_empty_list tests/unit/test_blob.py::Test__add_query_parameters::test_w_existing_qs tests/unit/test_blob.py::Test__add_query_parameters::test_wo_existing_qs
google/cloud/storage/blob.py
google/cloud/storage/blob.py