From 615c3fc31b51cd8b0a294e4ec1956471e3db2de3 Mon Sep 17 00:00:00 2001 From: Nidhi Nandwani Date: Tue, 16 Jun 2026 06:28:59 +0000 Subject: [PATCH 1/3] feat(storage): update compose sample to support deleteSourceObjects option Update compose_file snippet to support delete_source_objects option. Add corresponding system integration tests. [Generated-by: AI] --- storage/samples/snippets/snippets_test.py | 34 ++++++++++++++++++- .../samples/snippets/storage_compose_file.py | 25 +++++++++++--- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/storage/samples/snippets/snippets_test.py b/storage/samples/snippets/snippets_test.py index 1d3c8c1c442..4b1196075fd 100644 --- a/storage/samples/snippets/snippets_test.py +++ b/storage/samples/snippets/snippets_test.py @@ -668,7 +668,10 @@ def test_object_get_kms_key(test_bucket): def test_storage_compose_file(test_bucket): - source_files = ["test_upload_blob_1", "test_upload_blob_2"] + source_files = [ + f"test_upload_blob_1_{uuid.uuid4().hex}", + f"test_upload_blob_2_{uuid.uuid4().hex}", + ] for source in source_files: blob = test_bucket.blob(source) blob.upload_from_string(source) @@ -684,6 +687,35 @@ def test_storage_compose_file(test_bucket): assert composed.decode("utf-8") == source_files[0] + source_files[1] + # Verify sources are NOT deleted + assert test_bucket.blob(source_files[0]).exists() + assert test_bucket.blob(source_files[1]).exists() + + +def test_storage_compose_file_delete_source(test_bucket): + source_files = [ + f"test_upload_blob_1_{uuid.uuid4().hex}", + f"test_upload_blob_2_{uuid.uuid4().hex}", + ] + for source in source_files: + blob = test_bucket.blob(source) + blob.upload_from_string(source) + + 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] + + # Verify sources are deleted + assert not test_bucket.blob(source_files[0]).exists() + assert not test_bucket.blob(source_files[1]).exists() + def test_cors_configuration(test_bucket, capsys): bucket = storage_cors_configuration.cors_configuration(test_bucket) diff --git a/storage/samples/snippets/storage_compose_file.py b/storage/samples/snippets/storage_compose_file.py index e673912725b..4c675da1e29 100644 --- a/storage/samples/snippets/storage_compose_file.py +++ b/storage/samples/snippets/storage_compose_file.py @@ -20,7 +20,13 @@ 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" @@ -44,11 +50,22 @@ 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, + ) + deletion_message = ( + " and the 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 + "New composite object {} in the bucket {} was created by combining {} and {}{}".format( + destination_blob_name, + bucket_name, + first_blob_name, + second_blob_name, + deletion_message, ) ) return destination From b4fa93e6dca9d2fa3424002e6767d24acec5354d Mon Sep 17 00:00:00 2001 From: Nidhi Nandwani Date: Tue, 16 Jun 2026 06:58:22 +0000 Subject: [PATCH 2/3] fix(storage): fix import order in snippets_test.py --- storage/samples/snippets/snippets_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/samples/snippets/snippets_test.py b/storage/samples/snippets/snippets_test.py index 4b1196075fd..1ac926a5623 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 From 42cd819fa968290b7cdc3dd1a28141a2876ba151 Mon Sep 17 00:00:00 2001 From: Nidhi Nandwani Date: Tue, 16 Jun 2026 06:58:32 +0000 Subject: [PATCH 3/3] fix(ci): re-enable Kokoro configs to fix CI failures due to missing config --- .kokoro/lint/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/lint/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/lint/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.10/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.10/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.10/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.11/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.11/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.11/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.12/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.12/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.12/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.13/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.13/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.13/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.14/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.14/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.14/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.8/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.8/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.8/{presubmit.cfg.disabled => presubmit.cfg} | 0 .kokoro/python3.9/{continuous.cfg.disabled => continuous.cfg} | 0 .kokoro/python3.9/{periodic.cfg.disabled => periodic.cfg} | 0 .kokoro/python3.9/{presubmit.cfg.disabled => presubmit.cfg} | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename .kokoro/lint/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/lint/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/lint/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.10/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.10/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.10/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.11/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.11/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.11/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.12/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.12/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.12/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.13/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.13/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.13/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.14/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.14/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.14/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.8/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.8/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.8/{presubmit.cfg.disabled => presubmit.cfg} (100%) rename .kokoro/python3.9/{continuous.cfg.disabled => continuous.cfg} (100%) rename .kokoro/python3.9/{periodic.cfg.disabled => periodic.cfg} (100%) rename .kokoro/python3.9/{presubmit.cfg.disabled => presubmit.cfg} (100%) diff --git a/.kokoro/lint/continuous.cfg.disabled b/.kokoro/lint/continuous.cfg similarity index 100% rename from .kokoro/lint/continuous.cfg.disabled rename to .kokoro/lint/continuous.cfg diff --git a/.kokoro/lint/periodic.cfg.disabled b/.kokoro/lint/periodic.cfg similarity index 100% rename from .kokoro/lint/periodic.cfg.disabled rename to .kokoro/lint/periodic.cfg diff --git a/.kokoro/lint/presubmit.cfg.disabled b/.kokoro/lint/presubmit.cfg similarity index 100% rename from .kokoro/lint/presubmit.cfg.disabled rename to .kokoro/lint/presubmit.cfg diff --git a/.kokoro/python3.10/continuous.cfg.disabled b/.kokoro/python3.10/continuous.cfg similarity index 100% rename from .kokoro/python3.10/continuous.cfg.disabled rename to .kokoro/python3.10/continuous.cfg diff --git a/.kokoro/python3.10/periodic.cfg.disabled b/.kokoro/python3.10/periodic.cfg similarity index 100% rename from .kokoro/python3.10/periodic.cfg.disabled rename to .kokoro/python3.10/periodic.cfg diff --git a/.kokoro/python3.10/presubmit.cfg.disabled b/.kokoro/python3.10/presubmit.cfg similarity index 100% rename from .kokoro/python3.10/presubmit.cfg.disabled rename to .kokoro/python3.10/presubmit.cfg diff --git a/.kokoro/python3.11/continuous.cfg.disabled b/.kokoro/python3.11/continuous.cfg similarity index 100% rename from .kokoro/python3.11/continuous.cfg.disabled rename to .kokoro/python3.11/continuous.cfg diff --git a/.kokoro/python3.11/periodic.cfg.disabled b/.kokoro/python3.11/periodic.cfg similarity index 100% rename from .kokoro/python3.11/periodic.cfg.disabled rename to .kokoro/python3.11/periodic.cfg diff --git a/.kokoro/python3.11/presubmit.cfg.disabled b/.kokoro/python3.11/presubmit.cfg similarity index 100% rename from .kokoro/python3.11/presubmit.cfg.disabled rename to .kokoro/python3.11/presubmit.cfg diff --git a/.kokoro/python3.12/continuous.cfg.disabled b/.kokoro/python3.12/continuous.cfg similarity index 100% rename from .kokoro/python3.12/continuous.cfg.disabled rename to .kokoro/python3.12/continuous.cfg diff --git a/.kokoro/python3.12/periodic.cfg.disabled b/.kokoro/python3.12/periodic.cfg similarity index 100% rename from .kokoro/python3.12/periodic.cfg.disabled rename to .kokoro/python3.12/periodic.cfg diff --git a/.kokoro/python3.12/presubmit.cfg.disabled b/.kokoro/python3.12/presubmit.cfg similarity index 100% rename from .kokoro/python3.12/presubmit.cfg.disabled rename to .kokoro/python3.12/presubmit.cfg diff --git a/.kokoro/python3.13/continuous.cfg.disabled b/.kokoro/python3.13/continuous.cfg similarity index 100% rename from .kokoro/python3.13/continuous.cfg.disabled rename to .kokoro/python3.13/continuous.cfg diff --git a/.kokoro/python3.13/periodic.cfg.disabled b/.kokoro/python3.13/periodic.cfg similarity index 100% rename from .kokoro/python3.13/periodic.cfg.disabled rename to .kokoro/python3.13/periodic.cfg diff --git a/.kokoro/python3.13/presubmit.cfg.disabled b/.kokoro/python3.13/presubmit.cfg similarity index 100% rename from .kokoro/python3.13/presubmit.cfg.disabled rename to .kokoro/python3.13/presubmit.cfg diff --git a/.kokoro/python3.14/continuous.cfg.disabled b/.kokoro/python3.14/continuous.cfg similarity index 100% rename from .kokoro/python3.14/continuous.cfg.disabled rename to .kokoro/python3.14/continuous.cfg diff --git a/.kokoro/python3.14/periodic.cfg.disabled b/.kokoro/python3.14/periodic.cfg similarity index 100% rename from .kokoro/python3.14/periodic.cfg.disabled rename to .kokoro/python3.14/periodic.cfg diff --git a/.kokoro/python3.14/presubmit.cfg.disabled b/.kokoro/python3.14/presubmit.cfg similarity index 100% rename from .kokoro/python3.14/presubmit.cfg.disabled rename to .kokoro/python3.14/presubmit.cfg diff --git a/.kokoro/python3.8/continuous.cfg.disabled b/.kokoro/python3.8/continuous.cfg similarity index 100% rename from .kokoro/python3.8/continuous.cfg.disabled rename to .kokoro/python3.8/continuous.cfg diff --git a/.kokoro/python3.8/periodic.cfg.disabled b/.kokoro/python3.8/periodic.cfg similarity index 100% rename from .kokoro/python3.8/periodic.cfg.disabled rename to .kokoro/python3.8/periodic.cfg diff --git a/.kokoro/python3.8/presubmit.cfg.disabled b/.kokoro/python3.8/presubmit.cfg similarity index 100% rename from .kokoro/python3.8/presubmit.cfg.disabled rename to .kokoro/python3.8/presubmit.cfg diff --git a/.kokoro/python3.9/continuous.cfg.disabled b/.kokoro/python3.9/continuous.cfg similarity index 100% rename from .kokoro/python3.9/continuous.cfg.disabled rename to .kokoro/python3.9/continuous.cfg diff --git a/.kokoro/python3.9/periodic.cfg.disabled b/.kokoro/python3.9/periodic.cfg similarity index 100% rename from .kokoro/python3.9/periodic.cfg.disabled rename to .kokoro/python3.9/periodic.cfg diff --git a/.kokoro/python3.9/presubmit.cfg.disabled b/.kokoro/python3.9/presubmit.cfg similarity index 100% rename from .kokoro/python3.9/presubmit.cfg.disabled rename to .kokoro/python3.9/presubmit.cfg