From 00c2c30a2641673dc1e23cb823477f7471cfaded Mon Sep 17 00:00:00 2001 From: yuxin00j Date: Wed, 10 Jun 2026 04:23:57 +0000 Subject: [PATCH 1/3] feat(storage): expose object_metadata on AsyncMultiRangeDownloader --- .../cloud/storage/asyncio/async_multi_range_downloader.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py b/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py index 6d3f5e2fab4b..e5176051a3ae 100644 --- a/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py +++ b/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py @@ -233,6 +233,7 @@ def __init__( self._open_retries: int = 0 self.is_finalized: bool = False self.full_obj_server_crc32c: Optional[int] = None + self.object_metadata: Optional[_storage_v2.Object] = None async def __aenter__(self): """Opens the underlying bidi-gRPC connection to read from the object.""" @@ -330,6 +331,7 @@ async def _do_open(): self.persisted_size = self.read_obj_str.persisted_size self.is_finalized = self.read_obj_str.is_finalized self.full_obj_server_crc32c = self.read_obj_str.full_obj_server_crc32c + self.object_metadata = self.read_obj_str.object_metadata self._is_stream_open = True @@ -368,6 +370,7 @@ async def factory(): self.read_handle = stream.read_handle self.is_finalized = stream.is_finalized self.full_obj_server_crc32c = stream.full_obj_server_crc32c + self.object_metadata = stream.object_metadata self.read_obj_str = stream self._is_stream_open = True From 649291ff406e7cffe2399dceafdf3b7c9a556435 Mon Sep 17 00:00:00 2001 From: yuxin00j Date: Wed, 10 Jun 2026 04:28:55 +0000 Subject: [PATCH 2/3] refactor: use property for object_metadata --- .../storage/asyncio/async_multi_range_downloader.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py b/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py index e5176051a3ae..400e73128433 100644 --- a/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py +++ b/packages/google-cloud-storage/google/cloud/storage/asyncio/async_multi_range_downloader.py @@ -233,7 +233,6 @@ def __init__( self._open_retries: int = 0 self.is_finalized: bool = False self.full_obj_server_crc32c: Optional[int] = None - self.object_metadata: Optional[_storage_v2.Object] = None async def __aenter__(self): """Opens the underlying bidi-gRPC connection to read from the object.""" @@ -331,7 +330,6 @@ async def _do_open(): self.persisted_size = self.read_obj_str.persisted_size self.is_finalized = self.read_obj_str.is_finalized self.full_obj_server_crc32c = self.read_obj_str.full_obj_server_crc32c - self.object_metadata = self.read_obj_str.object_metadata self._is_stream_open = True @@ -370,7 +368,6 @@ async def factory(): self.read_handle = stream.read_handle self.is_finalized = stream.is_finalized self.full_obj_server_crc32c = stream.full_obj_server_crc32c - self.object_metadata = stream.object_metadata self.read_obj_str = stream self._is_stream_open = True @@ -580,3 +577,9 @@ async def close(self): @property def is_stream_open(self) -> bool: return self._is_stream_open + + @property + def object_metadata(self) -> Optional[_storage_v2.Object]: + """The metadata of the object being downloaded.""" + stream = getattr(self, "read_obj_str", None) + return stream.object_metadata if stream else None From 47cf748e24470ad45528aea88b734bfff0183073 Mon Sep 17 00:00:00 2001 From: yuxin00j Date: Wed, 10 Jun 2026 04:46:29 +0000 Subject: [PATCH 3/3] test: add assertions for object_metadata property --- .../tests/unit/asyncio/test_async_multi_range_downloader.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/google-cloud-storage/tests/unit/asyncio/test_async_multi_range_downloader.py b/packages/google-cloud-storage/tests/unit/asyncio/test_async_multi_range_downloader.py index 6ead8d8964e9..24196d317ab6 100644 --- a/packages/google-cloud-storage/tests/unit/asyncio/test_async_multi_range_downloader.py +++ b/packages/google-cloud-storage/tests/unit/asyncio/test_async_multi_range_downloader.py @@ -60,6 +60,7 @@ async def _make_mock_mrd( mock_stream.generation_number = _TEST_GENERATION_NUMBER mock_stream.persisted_size = _TEST_OBJECT_SIZE mock_stream.read_handle = _TEST_READ_HANDLE + mock_stream.object_metadata = mock.Mock() mrd = await AsyncMultiRangeDownloader.create_mrd( mock_client, bucket_name, object_name, generation, read_handle @@ -93,6 +94,7 @@ async def test_create_mrd(self, mock_cls_async_read_object_stream): assert mrd.read_handle == _TEST_READ_HANDLE assert mrd.persisted_size == _TEST_OBJECT_SIZE assert mrd.is_stream_open + assert mrd.object_metadata == mrd.read_obj_str.object_metadata assert mrd._open_retries == 0 @mock.patch( @@ -275,6 +277,7 @@ async def test_close_mrd(self, mock_cls_async_read_object_stream): # Assert assert not mrd.is_stream_open + assert mrd.object_metadata is None @pytest.mark.asyncio async def test_close_mrd_not_opened_should_throw_error(self):