Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

[1]: https://pypi.org/project/google-cloud-storage/#history

## [3.4.1](https://github.com/googleapis/python-storage/compare/v3.4.0...v3.5.0) (2025-10-08)

### Bug Fixes

* Fixes [#1561](https://github.com/googleapis/python-storage/issues/1561) by adding an option to specify the entire object checksum for resumable uploads via the `upload_from_string`, `upload_from_file`, and `upload_from_filename` methods ([acb918e](https://github.com/googleapis/python-storage/commit/acb918e20f7092e13d72fc63fe4ae2560bfecd40))

## [3.4.0](https://github.com/googleapis/python-storage/compare/v3.3.1...v3.4.0) (2025-09-15)


Expand Down
46 changes: 23 additions & 23 deletions google/cloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def __init__(

if generation is not None:
self._properties["generation"] = generation

@property
def bucket(self):
"""Bucket which contains the object.
Expand Down Expand Up @@ -2178,12 +2179,12 @@ def _initiate_resumable_upload(
unless otherwise directed.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `file`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -2204,7 +2205,7 @@ def _initiate_resumable_upload(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down Expand Up @@ -2396,12 +2397,12 @@ def _do_resumable_upload(
unless otherwise directed.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `stream`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -2422,7 +2423,7 @@ def _do_resumable_upload(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down Expand Up @@ -2578,12 +2579,12 @@ def _do_upload(
unless otherwise directed.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `file_obj`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -2604,7 +2605,7 @@ def _do_upload(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down Expand Up @@ -2795,12 +2796,12 @@ def _prep_and_do_upload(
unless otherwise directed.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `file_obj`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -2821,7 +2822,7 @@ def _prep_and_do_upload(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down Expand Up @@ -2978,12 +2979,12 @@ def upload_from_file(
to configure them.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `file_obj`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -3004,7 +3005,7 @@ def upload_from_file(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down Expand Up @@ -3068,7 +3069,6 @@ def upload_from_filename(
checksum="auto",
retry=DEFAULT_RETRY,
crc32c_checksum_value=None,

):
"""Upload this blob's contents from the content of a named file.

Expand Down Expand Up @@ -3163,14 +3163,14 @@ def upload_from_filename(
See the retry.py source code and docstrings in this package
(google.cloud.storage.retry) for information on retry types and how
to configure them.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `filename`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -3191,7 +3191,7 @@ def upload_from_filename(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down Expand Up @@ -3314,12 +3314,12 @@ def upload_from_string(
to configure them.

:type crc32c_checksum_value: str
:param crc32c_checksum_value: (Optional) This should be the checksum of
:param crc32c_checksum_value: (Optional) This should be the checksum of
the entire contents of `file_obj`. Applicable while uploading object
greater than `_MAX_MULTIPART_SIZE` bytes.

It can be obtained by running

`gcloud storage hash /path/to/your/file`

or
Expand All @@ -3340,7 +3340,7 @@ def upload_from_string(

Above code block prints 8 char string of base64 encoded big-endian
bytes of 32 bit CRC32c integer.

More details on CRC32c can be found in Appendix B:
https://datatracker.ietf.org/doc/html/rfc4960#appendix-B and
base64: https://datatracker.ietf.org/doc/html/rfc4648#section-4
Expand Down
2 changes: 1 addition & 1 deletion google/cloud/storage/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = "3.4.0"
__version__ = "3.4.1"
3 changes: 2 additions & 1 deletion tests/system/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ def test_large_file_write_from_stream_w_user_provided_wrong_checksum(
info = file_data["big_9MiB"]
with pytest.raises(exceptions.BadRequest) as excep_info:
with open(info["path"], "rb") as file_obj:
blob.upload_from_file(file_obj,crc32c_checksum_value="A0tD7w==")
blob.upload_from_file(file_obj, crc32c_checksum_value="A0tD7w==")
blobs_to_delete.append(blob)
assert excep_info.value.code == 400


def test_touch_and_write_large_file_w_user_provided_checksum(
shared_bucket,
blobs_to_delete,
Expand Down
21 changes: 16 additions & 5 deletions tests/unit/asyncio/test_async_read_object_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,17 @@ async def test_recv_without_open_should_raise_error(
# assert
assert str(exc.value) == "Stream is not open"

@mock.patch("google.cloud.storage._experimental.asyncio.async_read_object_stream.AsyncBidiRpc")
@mock.patch("google.cloud.storage._experimental.asyncio.async_grpc_client.AsyncGrpcClient.grpc_client")

@mock.patch(
"google.cloud.storage._experimental.asyncio.async_read_object_stream.AsyncBidiRpc"
)
@mock.patch(
"google.cloud.storage._experimental.asyncio.async_grpc_client.AsyncGrpcClient.grpc_client"
)
@pytest.mark.asyncio
async def test_recv_updates_read_handle_on_refresh(mock_client, mock_cls_async_bidi_rpc):
async def test_recv_updates_read_handle_on_refresh(
mock_client, mock_cls_async_bidi_rpc
):
"""
Verify that the `recv` method correctly updates the stream's handle
when a new one is provided in a server response.
Expand All @@ -289,11 +296,15 @@ async def test_recv_updates_read_handle_on_refresh(mock_client, mock_cls_async_b
socket_like_rpc.open = AsyncMock()

initial_handle = _storage_v2.BidiReadHandle(handle=b"initial-handle-token")
response_with_initial_handle = _storage_v2.BidiReadObjectResponse(read_handle=initial_handle)
response_with_initial_handle = _storage_v2.BidiReadObjectResponse(
read_handle=initial_handle
)
response_without_handle = _storage_v2.BidiReadObjectResponse(read_handle=None)

refreshed_handle = _storage_v2.BidiReadHandle(handle=b"new-refreshed-handle-token")
response_with_refreshed_handle = _storage_v2.BidiReadObjectResponse(read_handle=refreshed_handle)
response_with_refreshed_handle = _storage_v2.BidiReadObjectResponse(
read_handle=refreshed_handle
)

socket_like_rpc.recv.side_effect = [
response_with_initial_handle,
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -3572,7 +3572,7 @@ def _do_upload_mock_call_helper(
kwargs,
{
"timeout": expected_timeout,
'crc32c_checksum_value': None,
"crc32c_checksum_value": None,
"checksum": None,
"retry": retry,
"command": None,
Expand Down