| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,8 +25,8 @@ | |||
| 25 | 25 | import requests | |
| 26 | 26 | ||
| 27 | 27 | import storage_add_bucket_label | |
| 28 | - import storage_async_upload | ||
| 29 | 28 | import storage_async_download | |
| 29 | + import storage_async_upload | ||
| 30 | 30 | import storage_batch_request | |
| 31 | 31 | import storage_bucket_delete_default_kms_key | |
| 32 | 32 | import storage_change_default_storage_class | |
@@ -44,6 +44,7 @@ | |||
| 44 | 44 | import storage_delete_file | |
| 45 | 45 | import storage_delete_file_archived_generation | |
| 46 | 46 | import storage_disable_bucket_lifecycle_management | |
| 47 | + import storage_disable_soft_delete | ||
| 47 | 48 | import storage_disable_versioning | |
| 48 | 49 | import storage_download_byte_range | |
| 49 | 50 | import storage_download_file | |
@@ -59,26 +60,31 @@ | |||
| 59 | 60 | import storage_get_autoclass | |
| 60 | 61 | import storage_get_bucket_labels | |
| 61 | 62 | import storage_get_bucket_metadata | |
| 62 | - import storage_get_soft_deleted_bucket | ||
| 63 | 63 | import storage_get_metadata | |
| 64 | 64 | import storage_get_service_account | |
| 65 | + import storage_get_soft_delete_policy | ||
| 66 | + import storage_get_soft_deleted_bucket | ||
| 65 | 67 | import storage_list_buckets | |
| 66 | - import storage_list_soft_deleted_buckets | ||
| 67 | - import storage_restore_soft_deleted_bucket | ||
| 68 | 68 | import storage_list_file_archived_generations | |
| 69 | 69 | import storage_list_files | |
| 70 | 70 | import storage_list_files_with_prefix | |
| 71 | + import storage_list_soft_deleted_buckets | ||
| 72 | + import storage_list_soft_deleted_object_versions | ||
| 73 | + import storage_list_soft_deleted_objects | ||
| 71 | 74 | import storage_make_public | |
| 72 | 75 | import storage_move_file | |
| 73 | 76 | import storage_object_get_kms_key | |
| 74 | 77 | import storage_remove_bucket_label | |
| 75 | 78 | import storage_remove_cors_configuration | |
| 76 | 79 | import storage_rename_file | |
| 80 | + import storage_restore_object | ||
| 81 | + import storage_restore_soft_deleted_bucket | ||
| 77 | 82 | import storage_set_autoclass | |
| 78 | 83 | import storage_set_bucket_default_kms_key | |
| 79 | 84 | import storage_set_client_endpoint | |
| 80 | - import storage_set_object_retention_policy | ||
| 81 | 85 | import storage_set_metadata | |
| 86 | + import storage_set_object_retention_policy | ||
| 87 | + import storage_set_soft_delete_policy | ||
| 82 | 88 | import storage_trace_quickstart | |
| 83 | 89 | import storage_transfer_manager_download_bucket | |
| 84 | 90 | import storage_transfer_manager_download_chunks_concurrently | |
@@ -147,6 +153,21 @@ def test_soft_deleted_bucket(): | |||
| 147 | 153 | yield bucket | |
| 148 | 154 | ||
| 149 | 155 | ||
| 156 | + @pytest.fixture(scope="function") | ||
| 157 | + def test_soft_delete_enabled_bucket(): | ||
| 158 | + """Yields a bucket with soft-delete enabled that is deleted after the test completes.""" | ||
| 159 | + bucket = None | ||
| 160 | + while bucket is None or bucket.exists(): | ||
| 161 | + bucket_name = f"storage-snippets-test-{uuid.uuid4()}" | ||
| 162 | + bucket = storage.Client().bucket(bucket_name) | ||
| 163 | + # Soft-delete retention for 7 days (minimum allowed by API) | ||
| 164 | + bucket.soft_delete_policy.retention_duration_seconds = 7 * 24 * 60 * 60 | ||
| 165 | + # Soft-delete requires a region | ||
| 166 | + bucket.create(location="US-CENTRAL1") | ||
| 167 | + yield bucket | ||
| 168 | + bucket.delete(force=True) | ||
| 169 | + | ||
| 170 | + | ||
| 150 | 171 | @pytest.fixture(scope="function") | |
| 151 | 172 | def test_public_bucket(): | |
| 152 | 173 | # The new projects don't allow to make a bucket available to public, so | |
@@ -230,13 +251,17 @@ def test_bucket_metadata(test_bucket, capsys): | |||
| 230 | 251 | ||
| 231 | 252 | ||
| 232 | 253 | def test_get_soft_deleted_bucket(test_soft_deleted_bucket, capsys): | |
| 233 | - storage_get_soft_deleted_bucket.get_soft_deleted_bucket(test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation) | ||
| 254 | + storage_get_soft_deleted_bucket.get_soft_deleted_bucket( | ||
| 255 | + test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation | ||
| 256 | + ) | ||
| 234 | 257 | out, _ = capsys.readouterr() | |
| 235 | 258 | assert test_soft_deleted_bucket.name in out | |
| 236 | 259 | ||
| 237 | 260 | ||
| 238 | 261 | def test_restore_soft_deleted_bucket(test_soft_deleted_bucket, capsys): | |
| 239 | - storage_restore_soft_deleted_bucket.restore_bucket(test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation) | ||
| 262 | + storage_restore_soft_deleted_bucket.restore_bucket( | ||
| 263 | + test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation | ||
| 264 | + ) | ||
| 240 | 265 | out, _ = capsys.readouterr() | |
| 241 | 266 | assert test_soft_deleted_bucket.name in out | |
| 242 | 267 | ||
@@ -309,7 +334,9 @@ def test_async_download(test_bucket, capsys): | |||
| 309 | 334 | blob = test_bucket.blob(source) | |
| 310 | 335 | blob.upload_from_string(source) | |
| 311 | 336 | ||
| 312 | - asyncio.run(storage_async_download.async_download_blobs(test_bucket.name, *source_files)) | ||
| 337 | + asyncio.run( | ||
| 338 | + storage_async_download.async_download_blobs(test_bucket.name, *source_files) | ||
| 339 | + ) | ||
| 313 | 340 | out, _ = capsys.readouterr() | |
| 314 | 341 | for x in range(object_count): | |
| 315 | 342 | assert f"Downloaded storage object async_sample_blob_{x}" in out | |
@@ -877,7 +904,10 @@ def test_object_retention_policy(test_bucket_create, capsys): | |||
| 877 | 904 | test_bucket_create.name | |
| 878 | 905 | ) | |
| 879 | 906 | out, _ = capsys.readouterr() | |
| 880 | - assert f"Created bucket {test_bucket_create.name} with object retention enabled setting" in out | ||
| 907 | + assert ( | ||
| 908 | + f"Created bucket {test_bucket_create.name} with object retention enabled setting" | ||
| 909 | + in out | ||
| 910 | + ) | ||
| 881 | 911 | ||
| 882 | 912 | blob_name = "test_object_retention" | |
| 883 | 913 | storage_set_object_retention_policy.set_object_retention_policy( | |
@@ -898,7 +928,10 @@ def test_create_bucket_hierarchical_namespace(test_bucket_create, capsys): | |||
| 898 | 928 | test_bucket_create.name | |
| 899 | 929 | ) | |
| 900 | 930 | out, _ = capsys.readouterr() | |
| 901 | - assert f"Created bucket {test_bucket_create.name} with hierarchical namespace enabled" in out | ||
| 931 | + assert ( | ||
| 932 | + f"Created bucket {test_bucket_create.name} with hierarchical namespace enabled" | ||
| 933 | + in out | ||
| 934 | + ) | ||
| 902 | 935 | ||
| 903 | 936 | ||
| 904 | 937 | def test_storage_trace_quickstart(test_bucket, capsys): | |
@@ -911,3 +944,96 @@ def test_storage_trace_quickstart(test_bucket, capsys): | |||
| 911 | 944 | assert ( | |
| 912 | 945 | f"Downloaded storage object {blob_name} from bucket {test_bucket.name}" in out | |
| 913 | 946 | ) | |
| 947 | + | ||
| 948 | + | ||
| 949 | + def test_storage_disable_soft_delete(test_soft_delete_enabled_bucket, capsys): | ||
| 950 | + bucket_name = test_soft_delete_enabled_bucket.name | ||
| 951 | + storage_disable_soft_delete.disable_soft_delete(bucket_name) | ||
| 952 | + out, _ = capsys.readouterr() | ||
| 953 | + assert f"Soft-delete policy is disabled for bucket {bucket_name}" in out | ||
| 954 | + | ||
| 955 | + | ||
| 956 | + def test_storage_get_soft_delete_policy(test_soft_delete_enabled_bucket, capsys): | ||
| 957 | + bucket_name = test_soft_delete_enabled_bucket.name | ||
| 958 | + storage_get_soft_delete_policy.get_soft_delete_policy(bucket_name) | ||
| 959 | + out, _ = capsys.readouterr() | ||
| 960 | + assert f"Soft-delete policy for {bucket_name}" in out | ||
| 961 | + assert "Object soft-delete policy is enabled" in out | ||
| 962 | + assert "Object retention duration: " in out | ||
| 963 | + assert "Policy effective time: " in out | ||
| 964 | + | ||
| 965 | + # Disable the soft-delete policy | ||
| 966 | + test_soft_delete_enabled_bucket.soft_delete_policy.retention_duration_seconds = 0 | ||
| 967 | + test_soft_delete_enabled_bucket.patch() | ||
| 968 | + storage_get_soft_delete_policy.get_soft_delete_policy(bucket_name) | ||
| 969 | + out, _ = capsys.readouterr() | ||
| 970 | + assert f"Soft-delete policy for {bucket_name}" in out | ||
| 971 | + assert "Object soft-delete policy is disabled" in out | ||
| 972 | + | ||
| 973 | + | ||
| 974 | + def test_storage_set_soft_delete_policy(test_soft_delete_enabled_bucket, capsys): | ||
| 975 | + bucket_name = test_soft_delete_enabled_bucket.name | ||
| 976 | + retention_duration_seconds = 10 * 24 * 60 * 60 # 10 days | ||
| 977 | + storage_set_soft_delete_policy.set_soft_delete_policy( | ||
| 978 | + bucket_name, retention_duration_seconds | ||
| 979 | + ) | ||
| 980 | + out, _ = capsys.readouterr() | ||
| 981 | + assert ( | ||
| 982 | + f"Soft delete policy for bucket {bucket_name} was set to {retention_duration_seconds} seconds retention period" | ||
| 983 | + in out | ||
| 984 | + ) | ||
| 985 | + | ||
| 986 | + | ||
| 987 | + def test_storage_list_soft_deleted_objects(test_soft_delete_enabled_bucket, capsys): | ||
| 988 | + bucket_name = test_soft_delete_enabled_bucket.name | ||
| 989 | + blob_name = f"test_object_{uuid.uuid4().hex}.txt" | ||
| 990 | + blob_content = "This object will be soft-deleted for listing." | ||
| 991 | + blob = test_soft_delete_enabled_bucket.blob(blob_name) | ||
| 992 | + blob.upload_from_string(blob_content) | ||
| 993 | + blob_generation = blob.generation | ||
| 994 | + | ||
| 995 | + blob.delete() # Soft-delete the object | ||
| 996 | + storage_list_soft_deleted_objects.list_soft_deleted_objects(bucket_name) | ||
| 997 | + out, _ = capsys.readouterr() | ||
| 998 | + assert f"Name: {blob_name}, Generation: {blob_generation}" in out | ||
| 999 | + | ||
| 1000 | + | ||
| 1001 | + def test_storage_list_soft_deleted_object_versions( | ||
| 1002 | + test_soft_delete_enabled_bucket, capsys | ||
| 1003 | + ): | ||
| 1004 | + bucket_name = test_soft_delete_enabled_bucket.name | ||
| 1005 | + blob_name = f"test_object_{uuid.uuid4().hex}.txt" | ||
| 1006 | + blob_content = "This object will be soft-deleted for version listing." | ||
| 1007 | + blob = test_soft_delete_enabled_bucket.blob(blob_name) | ||
| 1008 | + blob.upload_from_string(blob_content) | ||
| 1009 | + blob_generation = blob.generation | ||
| 1010 | + | ||
| 1011 | + blob.delete() # Soft-delete the object | ||
| 1012 | + storage_list_soft_deleted_object_versions.list_soft_deleted_object_versions( | ||
| 1013 | + bucket_name, blob_name | ||
| 1014 | + ) | ||
| 1015 | + out, _ = capsys.readouterr() | ||
| 1016 | + assert f"Version ID: {blob_generation}" in out | ||
| 1017 | + | ||
| 1018 | + | ||
| 1019 | + def test_storage_restore_soft_deleted_object(test_soft_delete_enabled_bucket, capsys): | ||
| 1020 | + bucket_name = test_soft_delete_enabled_bucket.name | ||
| 1021 | + blob_name = f"test-restore-sd-obj-{uuid.uuid4().hex}.txt" | ||
| 1022 | + blob_content = "This object will be soft-deleted and restored." | ||
| 1023 | + blob = test_soft_delete_enabled_bucket.blob(blob_name) | ||
| 1024 | + blob.upload_from_string(blob_content) | ||
| 1025 | + blob_generation = blob.generation | ||
| 1026 | + | ||
| 1027 | + blob.delete() # Soft-delete the object | ||
| 1028 | + storage_restore_object.restore_soft_deleted_object( | ||
| 1029 | + bucket_name, blob_name, blob_generation | ||
| 1030 | + ) | ||
| 1031 | + out, _ = capsys.readouterr() | ||
| 1032 | + assert ( | ||
| 1033 | + f"Soft-deleted object {blob_name} is restored in the bucket {bucket_name}" | ||
| 1034 | + in out | ||
| 1035 | + ) | ||
| 1036 | + | ||
| 1037 | + # Verify the restoration | ||
| 1038 | + blob = test_soft_delete_enabled_bucket.get_blob(blob_name) | ||
| 1039 | + assert blob is not None | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + #!/usr/bin/env python | ||
| 2 | + | ||
| 3 | + # Copyright 2025 Google LLC | ||
| 4 | + # | ||
| 5 | + # Licensed under the Apache License, Version 2.0 (the 'License'); | ||
| 6 | + # you may not use this file except in compliance with the License. | ||
| 7 | + # You may obtain a copy of the License at | ||
| 8 | + # | ||
| 9 | + # http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | + # | ||
| 11 | + # Unless required by applicable law or agreed to in writing, software | ||
| 12 | + # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | + # See the License for the specific language governing permissions and | ||
| 15 | + # limitations under the License. | ||
| 16 | + | ||
| 17 | + import sys | ||
| 18 | + | ||
| 19 | + # [START storage_disable_soft_delete] | ||
| 20 | + from google.cloud import storage | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + def disable_soft_delete(bucket_name): | ||
| 24 | + """Disable soft-delete policy for the bucket.""" | ||
| 25 | + # bucket_name = "your-bucket-name" | ||
| 26 | + | ||
| 27 | + storage_client = storage.Client() | ||
| 28 | + bucket = storage_client.get_bucket(bucket_name) | ||
| 29 | + | ||
| 30 | + # Setting the retention duration to 0 disables soft-delete. | ||
| 31 | + bucket.soft_delete_policy.retention_duration_seconds = 0 | ||
| 32 | + bucket.patch() | ||
| 33 | + | ||
| 34 | + print(f"Soft-delete policy is disabled for bucket {bucket_name}") | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + # [END storage_disable_soft_delete] | ||
| 38 | + | ||
| 39 | + if __name__ == "__main__": | ||
| 40 | + disable_soft_delete(bucket_name=sys.argv[1]) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,47 @@ | |||
| 1 | + #!/usr/bin/env python | ||
| 2 | + | ||
| 3 | + # Copyright 2025 Google LLC | ||
| 4 | + # | ||
| 5 | + # Licensed under the Apache License, Version 2.0 (the 'License'); | ||
| 6 | + # you may not use this file except in compliance with the License. | ||
| 7 | + # You may obtain a copy of the License at | ||
| 8 | + # | ||
| 9 | + # http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | + # | ||
| 11 | + # Unless required by applicable law or agreed to in writing, software | ||
| 12 | + # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | + # See the License for the specific language governing permissions and | ||
| 15 | + # limitations under the License. | ||
| 16 | + | ||
| 17 | + import sys | ||
| 18 | + | ||
| 19 | + # [START storage_get_soft_delete_policy] | ||
| 20 | + from google.cloud import storage | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + def get_soft_delete_policy(bucket_name): | ||
| 24 | + """Gets the soft-delete policy of the bucket""" | ||
| 25 | + # bucket_name = "your-bucket-name" | ||
| 26 | + | ||
| 27 | + storage_client = storage.Client() | ||
| 28 | + bucket = storage_client.get_bucket(bucket_name) | ||
| 29 | + | ||
| 30 | + print(f"Soft-delete policy for {bucket_name}") | ||
| 31 | + if ( | ||
| 32 | + bucket.soft_delete_policy | ||
| 33 | + and bucket.soft_delete_policy.retention_duration_seconds | ||
| 34 | + ): | ||
| 35 | + print("Object soft-delete policy is enabled") | ||
| 36 | + print( | ||
| 37 | + f"Object retention duration: {bucket.soft_delete_policy.retention_duration_seconds} seconds" | ||
| 38 | + ) | ||
| 39 | + print(f"Policy effective time: {bucket.soft_delete_policy.effective_time}") | ||
| 40 | + else: | ||
| 41 | + print("Object soft-delete policy is disabled") | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + # [END storage_get_soft_delete_policy] | ||
| 45 | + | ||
| 46 | + if __name__ == "__main__": | ||
| 47 | + get_soft_delete_policy(bucket_name=sys.argv[1]) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,41 @@ | |||
| 1 | + #!/usr/bin/env python | ||
| 2 | + | ||
| 3 | + # Copyright 2025 Google LLC | ||
| 4 | + # | ||
| 5 | + # Licensed under the Apache License, Version 2.0 (the 'License'); | ||
| 6 | + # you may not use this file except in compliance with the License. | ||
| 7 | + # You may obtain a copy of the License at | ||
| 8 | + # | ||
| 9 | + # http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | + # | ||
| 11 | + # Unless required by applicable law or agreed to in writing, software | ||
| 12 | + # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | + # See the License for the specific language governing permissions and | ||
| 15 | + # limitations under the License. | ||
| 16 | + | ||
| 17 | + import sys | ||
| 18 | + | ||
| 19 | + # [START storage_list_soft_deleted_object_versions] | ||
| 20 | + from google.cloud import storage | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + def list_soft_deleted_object_versions(bucket_name, blob_name): | ||
| 24 | + """Lists all versions of a soft-deleted object in the bucket.""" | ||
| 25 | + # bucket_name = "your-bucket-name" | ||
| 26 | + # blob_name = "your-object-name" | ||
| 27 | + | ||
| 28 | + storage_client = storage.Client() | ||
| 29 | + blobs = storage_client.list_blobs(bucket_name, prefix=blob_name, soft_deleted=True) | ||
| 30 | + | ||
| 31 | + # Note: The call returns a response only when the iterator is consumed. | ||
| 32 | + for blob in blobs: | ||
| 33 | + print( | ||
| 34 | + f"Version ID: {blob.generation}, Soft Delete Time: {blob.soft_delete_time}" | ||
| 35 | + ) | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + # [END storage_list_soft_deleted_object_versions] | ||
| 39 | + | ||
| 40 | + if __name__ == "__main__": | ||
| 41 | + list_soft_deleted_object_versions(bucket_name=sys.argv[1], blob_name=sys.argv[2]) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + #!/usr/bin/env python | ||
| 2 | + | ||
| 3 | + # Copyright 2025 Google LLC | ||
| 4 | + # | ||
| 5 | + # Licensed under the Apache License, Version 2.0 (the 'License'); | ||
| 6 | + # you may not use this file except in compliance with the License. | ||
| 7 | + # You may obtain a copy of the License at | ||
| 8 | + # | ||
| 9 | + # http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | + # | ||
| 11 | + # Unless required by applicable law or agreed to in writing, software | ||
| 12 | + # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | + # See the License for the specific language governing permissions and | ||
| 15 | + # limitations under the License. | ||
| 16 | + | ||
| 17 | + import sys | ||
| 18 | + | ||
| 19 | + # [START storage_list_soft_deleted_objects] | ||
| 20 | + from google.cloud import storage | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + def list_soft_deleted_objects(bucket_name): | ||
| 24 | + """Lists all soft-deleted objects in the bucket.""" | ||
| 25 | + # bucket_name = "your-bucket-name" | ||
| 26 | + | ||
| 27 | + storage_client = storage.Client() | ||
| 28 | + blobs = storage_client.list_blobs(bucket_name, soft_deleted=True) | ||
| 29 | + | ||
| 30 | + # Note: The call returns a response only when the iterator is consumed. | ||
| 31 | + for blob in blobs: | ||
| 32 | + print( | ||
| 33 | + f"Name: {blob.name}, Generation: {blob.generation}, Soft Delete Time: {blob.soft_delete_time}" | ||
| 34 | + ) | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + # [END storage_list_soft_deleted_objects] | ||
| 38 | + | ||
| 39 | + if __name__ == "__main__": | ||
| 40 | + list_soft_deleted_objects(bucket_name=sys.argv[1]) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments