Skip to content

Commit f23963c

Browse files
feat(storage): support delete_source_objects in compose API
Implements the delete_source_objects parameter in Blob.compose() to allow automatic deletion of source objects upon successful composition. Reference PR: googleapis/google-cloud-java#12873 Co-authored-by: nidhiii-27 <224584462+nidhiii-27@users.noreply.github.com>
1 parent 471eb13 commit f23963c

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

packages/google-cloud-storage/google/cloud/storage/blob.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3849,6 +3849,7 @@ def compose(
38493849
if_metageneration_match=None,
38503850
if_source_generation_match=None,
38513851
retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED,
3852+
delete_source_objects=None,
38523853
):
38533854
"""Concatenate source blobs into this one.
38543855
@@ -3908,6 +3909,11 @@ def compose(
39083909
Change the value to ``DEFAULT_RETRY`` or another `google.api_core.retry.Retry` object
39093910
to enable retries regardless of generation precondition setting.
39103911
See [Configuring Retries](https://cloud.google.com/python/docs/reference/storage/latest/retry_timeout).
3912+
3913+
:type delete_source_objects: bool
3914+
:param delete_source_objects:
3915+
(Optional) If True, the source objects will be deleted after a
3916+
successful composition.
39113917
"""
39123918
with create_trace_span(name="Storage.Blob.compose"):
39133919
sources_len = len(sources)
@@ -3964,6 +3970,9 @@ def compose(
39643970
"destination": self._properties.copy(),
39653971
}
39663972

3973+
if delete_source_objects is not None:
3974+
request["deleteSourceObjects"] = delete_source_objects
3975+
39673976
if self.user_project is not None:
39683977
query_params["userProject"] = self.user_project
39693978

packages/google-cloud-storage/tests/unit/test_blob.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,6 +4480,43 @@ def test_compose_wo_content_type_set(self):
44804480
_target_object=destination,
44814481
)
44824482

4483+
def test_compose_w_delete_source_objects(self):
4484+
source_1_name = "source-1"
4485+
source_2_name = "source-2"
4486+
destination_name = "destination"
4487+
delete_source_objects = True
4488+
api_response = {}
4489+
client = mock.Mock(spec=["_post_resource"])
4490+
client._post_resource.return_value = api_response
4491+
bucket = _Bucket(client=client)
4492+
source_1 = self._make_one(source_1_name, bucket=bucket)
4493+
source_2 = self._make_one(source_2_name, bucket=bucket)
4494+
destination = self._make_one(destination_name, bucket=bucket)
4495+
4496+
destination.compose(
4497+
sources=[source_1, source_2],
4498+
delete_source_objects=delete_source_objects,
4499+
)
4500+
4501+
expected_path = f"/b/name/o/{destination_name}/compose"
4502+
expected_data = {
4503+
"sourceObjects": [
4504+
{"name": source_1.name, "generation": source_1.generation},
4505+
{"name": source_2.name, "generation": source_2.generation},
4506+
],
4507+
"destination": {},
4508+
"deleteSourceObjects": delete_source_objects,
4509+
}
4510+
expected_query_params = {}
4511+
client._post_resource.assert_called_once_with(
4512+
expected_path,
4513+
expected_data,
4514+
query_params=expected_query_params,
4515+
timeout=self._get_default_timeout(),
4516+
retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED,
4517+
_target_object=destination,
4518+
)
4519+
44834520
def test_compose_minimal_w_user_project_w_timeout(self):
44844521
source_1_name = "source-1"
44854522
source_2_name = "source-2"

0 commit comments

Comments
 (0)