Skip to content

Commit a0171ae

Browse files
yuxin00jparthea
andauthored
feat(storage): expose object_metadata on AsyncMultiRangeDownloader (#17411)
This PR exposes the `object_metadata` attribute on the `AsyncMultiRangeDownloader` class. ### Context In PR #17261, `object_metadata` was successfully exposed on the `AsyncReadObjectStream`. However, it was not surfaced on the `AsyncMultiRangeDownloader` (MRD), meaning high-level libraries relying on MRD (like `fsspec`/`gcsfs`) cannot access the underlying gRPC metadata. By inheriting and surfacing `self.object_metadata = self.read_obj_str.object_metadata`, this allows downstream users to completely bypass redundant `REST` `info()` API calls and extract fields like `crc32c`, `size`, and `generation` directly from the MRD instance. cc @chandra-siri --------- Co-authored-by: Anthonios Partheniou <partheniou@google.com>
1 parent dfed785 commit a0171ae

2 files changed

Lines changed: 8 additions & 0 deletions

File tree

packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,3 +565,8 @@ async def close(self):
565565
@property
566566
def is_stream_open(self) -> bool:
567567
return self._is_stream_open
568+
569+
@property
570+
def object_metadata(self) -> Optional[_storage_v2.Object]:
571+
"""The metadata of the object being downloaded."""
572+
return self.read_obj_str.object_metadata if self.read_obj_str else None

packages/google-cloud-storage/tests/unit/asyncio/test_async_multi_range_downloader.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ async def _make_mock_mrd(
6161
mock_stream.generation_number = _TEST_GENERATION_NUMBER
6262
mock_stream.persisted_size = _TEST_OBJECT_SIZE
6363
mock_stream.read_handle = _TEST_READ_HANDLE
64+
mock_stream.object_metadata = mock.Mock()
6465

6566
mrd = await AsyncMultiRangeDownloader.create_mrd(
6667
mock_client, bucket_name, object_name, generation, read_handle
@@ -94,6 +95,7 @@ async def test_create_mrd(self, mock_cls_async_read_object_stream):
9495
assert mrd.read_handle == _TEST_READ_HANDLE
9596
assert mrd.persisted_size == _TEST_OBJECT_SIZE
9697
assert mrd.is_stream_open
98+
assert mrd.object_metadata == mrd.read_obj_str.object_metadata
9799
assert mrd._open_retries == 0
98100

99101
@mock.patch(
@@ -276,6 +278,7 @@ async def test_close_mrd(self, mock_cls_async_read_object_stream):
276278

277279
# Assert
278280
assert not mrd.is_stream_open
281+
assert mrd.object_metadata is None
279282

280283
@pytest.mark.asyncio
281284
async def test_close_mrd_not_opened_should_throw_error(self):

0 commit comments

Comments
 (0)