From f9701b236e32ce5031ce7c88d38f0bb9f34668d5 Mon Sep 17 00:00:00 2001 From: Nidhi Nandwani Date: Wed, 24 Jun 2026 05:23:43 +0000 Subject: [PATCH 1/2] feat(storage): support deleteSourceObjects option in compose sample Add deleteSourceObjects parameter to compose sample. Updated test to assert both delete behavior scenarios. [Generated-by: AI] --- storage/samples/snippets/snippets_test.py | 24 +++++++++++++++ .../samples/snippets/storage_compose_file.py | 30 +++++++++++++++---- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/storage/samples/snippets/snippets_test.py b/storage/samples/snippets/snippets_test.py index 1d3c8c1c442..b945236e987 100644 --- a/storage/samples/snippets/snippets_test.py +++ b/storage/samples/snippets/snippets_test.py @@ -673,6 +673,7 @@ def test_storage_compose_file(test_bucket): blob = test_bucket.blob(source) blob.upload_from_string(source) + # Test with delete_source_objects = False (default) with tempfile.NamedTemporaryFile() as dest_file: destination = storage_compose_file.compose_file( test_bucket.name, @@ -683,6 +684,29 @@ def test_storage_compose_file(test_bucket): composed = destination.download_as_bytes() assert composed.decode("utf-8") == source_files[0] + source_files[1] + assert test_bucket.blob(source_files[0]).exists() + assert test_bucket.blob(source_files[1]).exists() + + # Clean up destination file + destination.delete() + + # Test with delete_source_objects = True + with tempfile.NamedTemporaryFile() as dest_file: + destination = storage_compose_file.compose_file( + test_bucket.name, + source_files[0], + source_files[1], + dest_file.name, + delete_source_objects=True, + ) + composed = destination.download_as_bytes() + + assert composed.decode("utf-8") == source_files[0] + source_files[1] + assert not test_bucket.blob(source_files[0]).exists() + assert not test_bucket.blob(source_files[1]).exists() + + # Clean up destination file + destination.delete() def test_cors_configuration(test_bucket, capsys): diff --git a/storage/samples/snippets/storage_compose_file.py b/storage/samples/snippets/storage_compose_file.py index e673912725b..a3780adc5c4 100644 --- a/storage/samples/snippets/storage_compose_file.py +++ b/storage/samples/snippets/storage_compose_file.py @@ -20,12 +20,19 @@ from google.cloud import storage -def compose_file(bucket_name, first_blob_name, second_blob_name, destination_blob_name): +def compose_file( + bucket_name, + first_blob_name, + second_blob_name, + destination_blob_name, + delete_source_objects=False, +): """Concatenate source blobs into destination blob.""" # bucket_name = "your-bucket-name" # first_blob_name = "first-object-name" # second_blob_name = "second-blob-name" # destination_blob_name = "destination-object-name" + # delete_source_objects = False storage_client = storage.Client() bucket = storage_client.bucket(bucket_name) @@ -44,13 +51,24 @@ def compose_file(bucket_name, first_blob_name, second_blob_name, destination_blo # There is also an `if_source_generation_match` parameter, which is not used in this example. destination_generation_match_precondition = 0 - destination.compose(sources, if_generation_match=destination_generation_match_precondition) + destination.compose( + sources, + if_generation_match=destination_generation_match_precondition, + delete_source_objects=delete_source_objects, + ) - print( - "New composite object {} in the bucket {} was created by combining {} and {}".format( - destination_blob_name, bucket_name, first_blob_name, second_blob_name + if delete_source_objects: + print( + "New composite object {} in the bucket {} was created by combining {} and {}. Source objects were deleted.".format( + destination_blob_name, bucket_name, first_blob_name, second_blob_name + ) + ) + else: + print( + "New composite object {} in the bucket {} was created by combining {} and {}".format( + destination_blob_name, bucket_name, first_blob_name, second_blob_name + ) ) - ) return destination From 7cf2380ff8b8664384bf1add635bb823ab11ab12 Mon Sep 17 00:00:00 2001 From: Nidhi Nandwani Date: Wed, 24 Jun 2026 06:43:10 +0000 Subject: [PATCH 2/2] fix(storage): fix flake8 import order and address review comments - Reordered imports in snippets_test.py to satisfy flake8. - Refactored storage_compose_file.py print statements to avoid duplication. [Generated-by: AI] --- storage/samples/snippets/snippets_test.py | 2 +- .../samples/snippets/storage_compose_file.py | 20 +++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/storage/samples/snippets/snippets_test.py b/storage/samples/snippets/snippets_test.py index b945236e987..9786f01012a 100644 --- a/storage/samples/snippets/snippets_test.py +++ b/storage/samples/snippets/snippets_test.py @@ -15,10 +15,10 @@ import asyncio import io import os +import sys import tempfile import time import uuid -import sys from google.cloud import storage import google.cloud.exceptions diff --git a/storage/samples/snippets/storage_compose_file.py b/storage/samples/snippets/storage_compose_file.py index a3780adc5c4..dc05675df91 100644 --- a/storage/samples/snippets/storage_compose_file.py +++ b/storage/samples/snippets/storage_compose_file.py @@ -57,18 +57,16 @@ def compose_file( delete_source_objects=delete_source_objects, ) - if delete_source_objects: - print( - "New composite object {} in the bucket {} was created by combining {} and {}. Source objects were deleted.".format( - destination_blob_name, bucket_name, first_blob_name, second_blob_name - ) - ) - else: - print( - "New composite object {} in the bucket {} was created by combining {} and {}".format( - destination_blob_name, bucket_name, first_blob_name, second_blob_name - ) + suffix = " Source objects were deleted." if delete_source_objects else "" + print( + "New composite object {} in the bucket {} was created by combining {} and {}.{}".format( + destination_blob_name, + bucket_name, + first_blob_name, + second_blob_name, + suffix, ) + ) return destination