Skip to content

Commit c2cd474

Browse files
chore(main): release 3.5.0 (#1568)
* chore(main): release 3.5.0 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 71b0f8a commit c2cd474

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@
44

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

7+
## [3.5.0](https://github.com/googleapis/python-storage/compare/v3.4.1...v3.5.0) (2025-11-05)
8+
9+
10+
### Features
11+
12+
* **experimental:** Add base resumption strategy for bidi streams ([#1594](https://github.com/googleapis/python-storage/issues/1594)) ([5fb85ea](https://github.com/googleapis/python-storage/commit/5fb85ea544dcc9ed9dca65957c872c3811f02b87))
13+
* **experimental:** Add checksum for bidi reads operation ([#1566](https://github.com/googleapis/python-storage/issues/1566)) ([93ce515](https://github.com/googleapis/python-storage/commit/93ce515d60f0ac77ab83680ba2b4d6a9f57e75d0))
14+
* **experimental:** Add read resumption strategy ([#1599](https://github.com/googleapis/python-storage/issues/1599)) ([5d5e895](https://github.com/googleapis/python-storage/commit/5d5e895e173075da557b58614fecc84086aaf9cb))
15+
* **experimental:** Handle BidiReadObjectRedirectedError for bidi reads ([#1600](https://github.com/googleapis/python-storage/issues/1600)) ([71b0f8a](https://github.com/googleapis/python-storage/commit/71b0f8a368a61bed9bd793a059f980562061223e))
16+
* Indicate that md5 is used as a CRC ([#1522](https://github.com/googleapis/python-storage/issues/1522)) ([961536c](https://github.com/googleapis/python-storage/commit/961536c7bf3652a824c207754317030526b9dd28))
17+
* Provide option to update user_agent ([#1596](https://github.com/googleapis/python-storage/issues/1596)) ([02f1451](https://github.com/googleapis/python-storage/commit/02f1451aaa8dacd10a862e97abb62ae48249b9b4))
18+
19+
20+
### Bug Fixes
21+
22+
* Deprecate credentials_file argument ([74415a2](https://github.com/googleapis/python-storage/commit/74415a2a120e9bfa42f4f5fc8bd2f8e0d4cf5d18))
23+
* Flaky system tests for resumable_media ([#1592](https://github.com/googleapis/python-storage/issues/1592)) ([7fee3dd](https://github.com/googleapis/python-storage/commit/7fee3dd3390cfb5475a39d8f8272ea825dbda449))
24+
* Make `download_ranges` compatible with `asyncio.create_task(..)` ([#1591](https://github.com/googleapis/python-storage/issues/1591)) ([faf8b83](https://github.com/googleapis/python-storage/commit/faf8b83b1f0ac378f8f6f47ce33dc23a866090c9))
25+
* Make `download_ranges` compatible with `asyncio.create_task(..)` ([#1591](https://github.com/googleapis/python-storage/issues/1591)) ([faf8b83](https://github.com/googleapis/python-storage/commit/faf8b83b1f0ac378f8f6f47ce33dc23a866090c9))
26+
* Redact sensitive data from OTEL traces and fix env var parsing ([#1553](https://github.com/googleapis/python-storage/issues/1553)) ([a38ca19](https://github.com/googleapis/python-storage/commit/a38ca1977694def98f65ae7239e300a987bbd262))
27+
* Redact sensitive data from OTEL traces and fix env var parsing ([#1553](https://github.com/googleapis/python-storage/issues/1553)) ([a38ca19](https://github.com/googleapis/python-storage/commit/a38ca1977694def98f65ae7239e300a987bbd262))
28+
* Use separate header object for each upload in Transfer Manager MPU ([#1595](https://github.com/googleapis/python-storage/issues/1595)) ([0d867bd](https://github.com/googleapis/python-storage/commit/0d867bd4f405d2dbeca1edfc8072080c5a96c1cd))
29+
730
## [3.4.1](https://github.com/googleapis/python-storage/compare/v3.4.0...v3.5.0) (2025-10-08)
831

932
### Bug Fixes

google/cloud/storage/_experimental/asyncio/retry/base_strategy.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import abc
22
from typing import Any, Iterable
33

4+
45
class _BaseResumptionStrategy(abc.ABC):
56
"""Abstract base class defining the interface for a bidi stream resumption strategy.
67

google/cloud/storage/_experimental/asyncio/retry/reads_resumption_strategy.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
)
88
from google.cloud._storage_v2.types.storage import BidiReadObjectRedirectedError
99

10+
1011
class _DownloadState:
1112
"""A helper class to track the state of a single range download."""
12-
def __init__(self, initial_offset: int, initial_length: int, user_buffer: IO[bytes]):
13+
14+
def __init__(
15+
self, initial_offset: int, initial_length: int, user_buffer: IO[bytes]
16+
):
1317
self.initial_offset = initial_offset
1418
self.initial_length = initial_length
1519
self.user_buffer = user_buffer
@@ -42,7 +46,9 @@ def generate_requests(self, state: dict) -> List[storage_v2.ReadRange]:
4246
pending_requests.append(new_request)
4347
return pending_requests
4448

45-
def update_state_from_response(self, response: storage_v2.BidiReadObjectResponse, state: dict) -> None:
49+
def update_state_from_response(
50+
self, response: storage_v2.BidiReadObjectResponse, state: dict
51+
) -> None:
4652
"""Processes a server response, performs integrity checks, and updates state."""
4753
for object_data_range in response.object_data_ranges:
4854
read_id = object_data_range.read_range.read_id
@@ -62,13 +68,18 @@ def update_state_from_response(self, response: storage_v2.BidiReadObjectResponse
6268
# Final Byte Count Verification
6369
if object_data_range.range_end:
6470
read_state.is_complete = True
65-
if read_state.initial_length != 0 and read_state.bytes_written != read_state.initial_length:
66-
raise DataCorruption(response, f"Byte count mismatch for read_id {read_id}")
71+
if (
72+
read_state.initial_length != 0
73+
and read_state.bytes_written != read_state.initial_length
74+
):
75+
raise DataCorruption(
76+
response, f"Byte count mismatch for read_id {read_id}"
77+
)
6778

6879
async def recover_state_on_failure(self, error: Exception, state: Any) -> None:
6980
"""Handles BidiReadObjectRedirectedError for reads."""
7081
# This would parse the gRPC error details, extract the routing_token,
7182
# and store it on the shared state object.
7283
cause = getattr(error, "cause", error)
7384
if isinstance(cause, BidiReadObjectRedirectedError):
74-
state['routing_token'] = cause.routing_token
85+
state["routing_token"] = cause.routing_token

google/cloud/storage/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__ = "3.4.1"
15+
__version__ = "3.5.0"

tests/unit/asyncio/retry/test_reads_resumption_strategy.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ def test_update_state_processes_single_chunk_successfully(self):
107107
response = storage_v2.BidiReadObjectResponse(
108108
object_data_ranges=[
109109
storage_v2.types.ObjectRangeData(
110-
read_range=storage_v2.ReadRange(read_id=_READ_ID, read_offset=0, read_length=len(data)),
110+
read_range=storage_v2.ReadRange(
111+
read_id=_READ_ID, read_offset=0, read_length=len(data)
112+
),
111113
checksummed_data=storage_v2.ChecksummedData(content=data),
112114
)
113115
]
@@ -130,7 +132,9 @@ def test_update_state_from_response_offset_mismatch(self):
130132
response = storage_v2.BidiReadObjectResponse(
131133
object_data_ranges=[
132134
storage_v2.types.ObjectRangeData(
133-
read_range=storage_v2.ReadRange(read_id=_READ_ID, read_offset=0, read_length=4),
135+
read_range=storage_v2.ReadRange(
136+
read_id=_READ_ID, read_offset=0, read_length=4
137+
),
134138
checksummed_data=storage_v2.ChecksummedData(content=b"data"),
135139
)
136140
]
@@ -149,7 +153,9 @@ def test_update_state_from_response_final_byte_count_mismatch(self):
149153
response = storage_v2.BidiReadObjectResponse(
150154
object_data_ranges=[
151155
storage_v2.types.ObjectRangeData(
152-
read_range=storage_v2.ReadRange(read_id=_READ_ID, read_offset=0, read_length=4),
156+
read_range=storage_v2.ReadRange(
157+
read_id=_READ_ID, read_offset=0, read_length=4
158+
),
153159
checksummed_data=storage_v2.ChecksummedData(content=b"data"),
154160
range_end=True,
155161
)
@@ -171,7 +177,9 @@ def test_update_state_from_response_completes_download(self):
171177
response = storage_v2.BidiReadObjectResponse(
172178
object_data_ranges=[
173179
storage_v2.types.ObjectRangeData(
174-
read_range=storage_v2.ReadRange(read_id=_READ_ID, read_offset=0, read_length=len(data)),
180+
read_range=storage_v2.ReadRange(
181+
read_id=_READ_ID, read_offset=0, read_length=len(data)
182+
),
175183
checksummed_data=storage_v2.ChecksummedData(content=data),
176184
range_end=True,
177185
)
@@ -195,7 +203,9 @@ def test_update_state_from_response_completes_download_zero_length(self):
195203
response = storage_v2.BidiReadObjectResponse(
196204
object_data_ranges=[
197205
storage_v2.types.ObjectRangeData(
198-
read_range=storage_v2.ReadRange(read_id=_READ_ID, read_offset=0, read_length=len(data)),
206+
read_range=storage_v2.ReadRange(
207+
read_id=_READ_ID, read_offset=0, read_length=len(data)
208+
),
199209
checksummed_data=storage_v2.ChecksummedData(content=data),
200210
range_end=True,
201211
)
@@ -215,9 +225,7 @@ async def test_recover_state_on_failure_handles_redirect(self):
215225
self.assertIsNone(state.get("routing_token"))
216226

217227
dummy_token = "dummy-routing-token"
218-
redirect_error = BidiReadObjectRedirectedError(
219-
routing_token=dummy_token
220-
)
228+
redirect_error = BidiReadObjectRedirectedError(routing_token=dummy_token)
221229

222230
final_error = exceptions.RetryError("Retry failed", cause=redirect_error)
223231

0 commit comments

Comments
 (0)