Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.

Commit fb96bb5

Browse files
authored
Merge branch 'main' into ai-gsutil-migration-155aa1bdb6da4c49ae5aed8ff1e059d3
2 parents d0334ea + 77c1eda commit fb96bb5

File tree

12 files changed

+503
-8
lines changed

12 files changed

+503
-8
lines changed

.librarian/state.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:8e2c32496077054105bd06c54a59d6a6694287bc053588e24debe6da6920ad91
22
libraries:
33
- id: google-cloud-storage
4-
version: 3.8.0
4+
version: 3.9.0
55
last_generated_commit: 5400ccce473c439885bd6bf2924fd242271bfcab
66
apis:
77
- path: google/storage/v2

CHANGELOG.md

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

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

7+
## [3.9.0](https://github.com/googleapis/python-storage/compare/v3.8.0...v3.9.0) (2026-02-02)
8+
9+
10+
### Features
11+
12+
* add get_object method for async grpc client (#1735) ([0e5ec29bc6a31b77bcfba4254cef5bffb199095c](https://github.com/googleapis/python-storage/commit/0e5ec29bc6a31b77bcfba4254cef5bffb199095c))
13+
* expose `DELETE_OBJECT` in `AsyncGrpcClient` (#1718) ([c8dd7a0b124c395b7b60189ee78f47aba8d51f7d](https://github.com/googleapis/python-storage/commit/c8dd7a0b124c395b7b60189ee78f47aba8d51f7d))
14+
* update generation for MRD (#1730) ([08bc7082db7392f13bc8c51511b4afa9c7b157c9](https://github.com/googleapis/python-storage/commit/08bc7082db7392f13bc8c51511b4afa9c7b157c9))
15+
* Move Zonal Buckets features of `_experimental` (#1728) ([74c9ecc54173420bfcd48498a8956088a035af50](https://github.com/googleapis/python-storage/commit/74c9ecc54173420bfcd48498a8956088a035af50))
16+
* add default user agent for grpc (#1726) ([7b319469d2e495ea0bf7367f3949190e8f5d9fff](https://github.com/googleapis/python-storage/commit/7b319469d2e495ea0bf7367f3949190e8f5d9fff))
17+
* expose finalized_time in blob.py applicable for GET_OBJECT in ZB (#1719) ([8e21a7fe54d0a043f31937671003630a1985a5d2](https://github.com/googleapis/python-storage/commit/8e21a7fe54d0a043f31937671003630a1985a5d2))
18+
* add context manager to mrd (#1724) ([5ac2808a69195c688ed42c3604d4bfadbb602a66](https://github.com/googleapis/python-storage/commit/5ac2808a69195c688ed42c3604d4bfadbb602a66))
19+
* integrate writes strategy and appendable object writer (#1695) ([dbd162b3583e32e6f705a51f5c3fef333a9b89d0](https://github.com/googleapis/python-storage/commit/dbd162b3583e32e6f705a51f5c3fef333a9b89d0))
20+
* Add support for opening via `write_handle` and fix `write_handle` type (#1715) ([2bc15fa570683ba584230c51b439d189dbdcd580](https://github.com/googleapis/python-storage/commit/2bc15fa570683ba584230c51b439d189dbdcd580))
21+
* Add micro-benchmarks for writes comparing standard (regional) vs rapid (zonal) buckets. (#1707) ([dbe9d8b89d975dfbed8c830a5687ccfafea51d5f](https://github.com/googleapis/python-storage/commit/dbe9d8b89d975dfbed8c830a5687ccfafea51d5f))
22+
* Add micro-benchmarks for reads comparing standard (regional) vs rapid (zonal) buckets. (#1697) ([1917649fac41481da1adea6c2a9f4ab1298a34c4](https://github.com/googleapis/python-storage/commit/1917649fac41481da1adea6c2a9f4ab1298a34c4))
23+
* send `user_agent` to grpc channel (#1712) ([cdb2486bb051dcbfbffc2510aff6aacede5e54d3](https://github.com/googleapis/python-storage/commit/cdb2486bb051dcbfbffc2510aff6aacede5e54d3))
24+
* add samples for appendable objects writes and reads (#1705) ([2e1a1eb5cbe1c909f1f892a0cc74fe63c8ef36ff](https://github.com/googleapis/python-storage/commit/2e1a1eb5cbe1c909f1f892a0cc74fe63c8ef36ff))
25+
* add samples for appendable objects writes and reads ([2e1a1eb5cbe1c909f1f892a0cc74fe63c8ef36ff](https://github.com/googleapis/python-storage/commit/2e1a1eb5cbe1c909f1f892a0cc74fe63c8ef36ff))
26+
* add support for `generation=0` to avoid overwriting existing objects and add `is_stream_open` support (#1709) ([ea0f5bf8316f4bfcff2728d9d1baa68dde6ebdae](https://github.com/googleapis/python-storage/commit/ea0f5bf8316f4bfcff2728d9d1baa68dde6ebdae))
27+
* add support for `generation=0` to prevent overwriting existing objects ([ea0f5bf8316f4bfcff2728d9d1baa68dde6ebdae](https://github.com/googleapis/python-storage/commit/ea0f5bf8316f4bfcff2728d9d1baa68dde6ebdae))
28+
* add `is_stream_open` property to AsyncAppendableObjectWriter for stream status check ([ea0f5bf8316f4bfcff2728d9d1baa68dde6ebdae](https://github.com/googleapis/python-storage/commit/ea0f5bf8316f4bfcff2728d9d1baa68dde6ebdae))
29+
30+
31+
### Bug Fixes
32+
33+
* receive eof while closing reads stream (#1733) ([2ef63396dca1c36f9b0f0f3cf87a61b5aa4bd465](https://github.com/googleapis/python-storage/commit/2ef63396dca1c36f9b0f0f3cf87a61b5aa4bd465))
34+
* Change contructors of MRD and AAOW AsyncGrpcClient.grpc_client to AsyncGrpcClient (#1727) ([e730bf50c4584f737ab86b2e409ddb27b40d2cec](https://github.com/googleapis/python-storage/commit/e730bf50c4584f737ab86b2e409ddb27b40d2cec))
35+
* instance grpc client once per process in benchmarks (#1725) ([721ea2dd6c6db2aa91fd3b90e56a831aaaa64061](https://github.com/googleapis/python-storage/commit/721ea2dd6c6db2aa91fd3b90e56a831aaaa64061))
36+
* update write handle on every recv() (#1716) ([5d9fafe1466b5ccb1db4a814967a5cc8465148a2](https://github.com/googleapis/python-storage/commit/5d9fafe1466b5ccb1db4a814967a5cc8465148a2))
37+
* Fix formatting in setup.py dependencies list (#1713) ([cc4831d7e253b265b0b96e08b5479f4c759be442](https://github.com/googleapis/python-storage/commit/cc4831d7e253b265b0b96e08b5479f4c759be442))
38+
* implement requests_done method to signal end of requests in async streams. Gracefully close streams. (#1700) ([6c160794afded5e8f4179399f1fe5248e32bf707](https://github.com/googleapis/python-storage/commit/6c160794afded5e8f4179399f1fe5248e32bf707))
39+
* implement requests_done method to signal end of requests in async streams. Gracefully close streams. ([6c160794afded5e8f4179399f1fe5248e32bf707](https://github.com/googleapis/python-storage/commit/6c160794afded5e8f4179399f1fe5248e32bf707))
40+
741
## [3.8.0](https://github.com/googleapis/python-storage/compare/v3.7.0...v3.8.0) (2026-01-13)
842

943

google/cloud/_storage_v2/gapic_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "3.8.0" # {x-release-please-version}
16+
__version__ = "3.9.0" # {x-release-please-version}

google/cloud/storage/asyncio/async_grpc_client.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,118 @@ def grpc_client(self):
106106
google.cloud._storage_v2.StorageAsyncClient: The configured GAPIC client.
107107
"""
108108
return self._grpc_client
109+
110+
async def delete_object(
111+
self,
112+
bucket_name,
113+
object_name,
114+
generation=None,
115+
if_generation_match=None,
116+
if_generation_not_match=None,
117+
if_metageneration_match=None,
118+
if_metageneration_not_match=None,
119+
**kwargs,
120+
):
121+
"""Deletes an object and its metadata.
122+
123+
:type bucket_name: str
124+
:param bucket_name: The name of the bucket in which the object resides.
125+
126+
:type object_name: str
127+
:param object_name: The name of the object to delete.
128+
129+
:type generation: int
130+
:param generation:
131+
(Optional) If present, permanently deletes a specific generation
132+
of an object.
133+
134+
:type if_generation_match: int
135+
:param if_generation_match: (Optional)
136+
137+
:type if_generation_not_match: int
138+
:param if_generation_not_match: (Optional)
139+
140+
:type if_metageneration_match: int
141+
:param if_metageneration_match: (Optional)
142+
143+
:type if_metageneration_not_match: int
144+
:param if_metageneration_not_match: (Optional)
145+
146+
147+
"""
148+
# The gRPC API requires the bucket name to be in the format "projects/_/buckets/bucket_name"
149+
bucket_path = f"projects/_/buckets/{bucket_name}"
150+
request = storage_v2.DeleteObjectRequest(
151+
bucket=bucket_path,
152+
object=object_name,
153+
generation=generation,
154+
if_generation_match=if_generation_match,
155+
if_generation_not_match=if_generation_not_match,
156+
if_metageneration_match=if_metageneration_match,
157+
if_metageneration_not_match=if_metageneration_not_match,
158+
**kwargs,
159+
)
160+
await self._grpc_client.delete_object(request=request)
161+
162+
async def get_object(
163+
self,
164+
bucket_name,
165+
object_name,
166+
generation=None,
167+
if_generation_match=None,
168+
if_generation_not_match=None,
169+
if_metageneration_match=None,
170+
if_metageneration_not_match=None,
171+
soft_deleted=None,
172+
**kwargs,
173+
):
174+
"""Retrieves an object's metadata.
175+
176+
In the gRPC API, this is performed by the GetObject RPC, which
177+
returns the object resource (metadata) without the object's data.
178+
179+
:type bucket_name: str
180+
:param bucket_name: The name of the bucket in which the object resides.
181+
182+
:type object_name: str
183+
:param object_name: The name of the object.
184+
185+
:type generation: int
186+
:param generation:
187+
(Optional) If present, selects a specific generation of an object.
188+
189+
:type if_generation_match: int
190+
:param if_generation_match: (Optional) Precondition for object generation match.
191+
192+
:type if_generation_not_match: int
193+
:param if_generation_not_match: (Optional) Precondition for object generation mismatch.
194+
195+
:type if_metageneration_match: int
196+
:param if_metageneration_match: (Optional) Precondition for metageneration match.
197+
198+
:type if_metageneration_not_match: int
199+
:param if_metageneration_not_match: (Optional) Precondition for metageneration mismatch.
200+
201+
:type soft_deleted: bool
202+
:param soft_deleted:
203+
(Optional) If True, return the soft-deleted version of this object.
204+
205+
:rtype: :class:`google.cloud._storage_v2.types.Object`
206+
:returns: The object metadata resource.
207+
"""
208+
bucket_path = f"projects/_/buckets/{bucket_name}"
209+
210+
request = storage_v2.GetObjectRequest(
211+
bucket=bucket_path,
212+
object=object_name,
213+
generation=generation,
214+
if_generation_match=if_generation_match,
215+
if_generation_not_match=if_generation_not_match,
216+
if_metageneration_match=if_metageneration_match,
217+
if_metageneration_not_match=if_metageneration_not_match,
218+
soft_deleted=soft_deleted or False,
219+
**kwargs,
220+
)
221+
222+
# Calls the underlying GAPIC StorageAsyncClient.get_object method
223+
return await self._grpc_client.get_object(request=request)

google/cloud/storage/asyncio/async_write_object_stream.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
from typing import List, Optional, Tuple
16+
import grpc
1617
from google.cloud import _storage_v2
1718
from google.cloud.storage.asyncio import _utils
1819
from google.cloud.storage.asyncio.async_grpc_client import AsyncGrpcClient
@@ -181,9 +182,17 @@ async def close(self) -> None:
181182

182183
async def requests_done(self):
183184
"""Signals that all requests have been sent."""
184-
185185
await self.socket_like_rpc.send(None)
186-
_utils.update_write_handle_if_exists(self, await self.socket_like_rpc.recv())
186+
187+
# The server may send a final "EOF" response immediately, or it may
188+
# first send an intermediate response followed by the EOF response depending on whether the object was finalized or not.
189+
first_resp = await self.socket_like_rpc.recv()
190+
_utils.update_write_handle_if_exists(self, first_resp)
191+
192+
if first_resp != grpc.aio.EOF:
193+
self.persisted_size = first_resp.persisted_size
194+
second_resp = await self.socket_like_rpc.recv()
195+
assert second_resp == grpc.aio.EOF
187196

188197
async def send(
189198
self, bidi_write_object_request: _storage_v2.BidiWriteObjectRequest

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.8.0"
15+
__version__ = "3.9.0"

samples/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,15 @@ for more detailed instructions.
3434
```
3535
source <your-venv>/bin/activate
3636
```
37+
3. To run samples for [Zonal Buckets](https://github.com/googleapis/python-storage/tree/main/samples/snippets/zonal_buckets)
3738
38-
3. Install the dependencies needed to run the samples.
39+
```
40+
pip install "google-cloud-storage[grpc]"
41+
python samples/snippets/zonal_buckets/storage_create_and_write_appendable_object.py --bucket_name <BUCKET_NAME> --object_name <OBJECT_NAME>
42+
43+
```
44+
45+
4. Install the dependencies needed to run the samples.
3946
```
4047
cd samples/snippets
4148
pip install -r requirements.txt

samples/generated_samples/snippet_metadata_google.storage.v2.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
],
99
"language": "PYTHON",
1010
"name": "google-cloud-storage",
11-
"version": "3.8.0"
11+
"version": "3.9.0"
1212
},
1313
"snippets": [
1414
{
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Google Cloud Storage - Zonal Buckets Snippets
2+
3+
This directory contains snippets for interacting with Google Cloud Storage zonal buckets.
4+
5+
## Prerequisites
6+
7+
- A Google Cloud Platform project with the Cloud Storage API enabled.
8+
- A zonal Google Cloud Storage bucket.
9+
10+
## Running the snippets
11+
12+
### Create and write to an appendable object
13+
14+
This snippet uploads an appendable object to a zonal bucket.
15+
16+
```bash
17+
python samples/snippets/zonal_buckets/storage_create_and_write_appendable_object.py --bucket_name <bucket_name> --object_name <object_name>
18+
```
19+
20+
### Finalize an appendable object upload
21+
22+
This snippet creates, writes to, and finalizes an appendable object.
23+
24+
```bash
25+
python samples/snippets/zonal_buckets/storage_finalize_appendable_object_upload.py --bucket_name <bucket_name> --object_name <object_name>
26+
```
27+
28+
### Pause and resume an appendable object upload
29+
30+
This snippet demonstrates pausing and resuming an appendable object upload.
31+
32+
```bash
33+
python samples/snippets/zonal_buckets/storage_pause_and_resume_appendable_upload.py --bucket_name <bucket_name> --object_name <object_name>
34+
```
35+
36+
### Tail an appendable object
37+
38+
This snippet demonstrates tailing an appendable GCS object, similar to `tail -f`.
39+
40+
```bash
41+
python samples/snippets/zonal_buckets/storage_read_appendable_object_tail.py --bucket_name <bucket_name> --object_name <object_name> --duration <duration_in_seconds>
42+
```
43+
44+
45+
### Download a range of bytes from an object
46+
47+
This snippet downloads a range of bytes from an object.
48+
49+
```bash
50+
python samples/snippets/zonal_buckets/storage_open_object_single_ranged_read.py --bucket_name <bucket_name> --object_name <object_name> --start_byte <start_byte> --size <size>
51+
```
52+
53+
54+
### Download multiple ranges of bytes from a single object
55+
56+
This snippet downloads multiple ranges of bytes from a single object into different buffers.
57+
58+
```bash
59+
python samples/snippets/zonal_buckets/storage_open_object_multiple_ranged_read.py --bucket_name <bucket_name> --object_name <object_name>
60+
```
61+
62+
### Download the entire content of an object
63+
64+
This snippet downloads the entire content of an object using a multi-range downloader.
65+
66+
```bash
67+
python samples/snippets/zonal_buckets/storage_open_object_read_full_object.py --bucket_name <bucket_name> --object_name <object_name>
68+
```
69+
70+
71+
72+
### Download a range of bytes from multiple objects concurrently
73+
74+
This snippet downloads a range of bytes from multiple objects concurrently.
75+
76+
```bash
77+
python samples/snippets/zonal_buckets/storage_open_multiple_objects_ranged_read.py --bucket_name <bucket_name> --object_names <object_name_1> <object_name_2>
78+
```

0 commit comments

Comments
 (0)