diff --git a/.coveragerc b/.coveragerc
index 0d8e6297d..742e899d4 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -18,6 +18,7 @@
[run]
branch = True
omit =
+ google/__init__.py
google/cloud/__init__.py
[report]
diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml
index 2567653c0..cb89b2e32 100644
--- a/.github/.OwlBot.lock.yaml
+++ b/.github/.OwlBot.lock.yaml
@@ -1,3 +1,3 @@
docker:
image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest
- digest: sha256:87eee22d276554e4e52863ec9b1cb6a7245815dfae20439712bf644348215a5a
+ digest: sha256:ec49167c606648a063d1222220b48119c912562849a0528f35bfb592a9f72737
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fe940a679..4e9e8be82 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -8,3 +8,7 @@
# The cloud-storage-dpe team is the default owner for anything not
# explicitly taken by someone else.
* @googleapis/cloud-storage-dpe @googleapis/yoshi-python
+
+# Additionally, the python-samples-owners team is also among
+# the default owners for samples changes.
+/samples/ @googleapis/cloud-storage-dpe @googleapis/yoshi-python @googleapis/python-samples-owners
\ No newline at end of file
diff --git a/.kokoro/docs/common.cfg b/.kokoro/docs/common.cfg
index 308bf124b..d3d3d8c50 100644
--- a/.kokoro/docs/common.cfg
+++ b/.kokoro/docs/common.cfg
@@ -30,6 +30,7 @@ env_vars: {
env_vars: {
key: "V2_STAGING_BUCKET"
+ # Push google cloud library docs to the Cloud RAD bucket `docs-staging-v2`
value: "docs-staging-v2"
}
diff --git a/.kokoro/samples/lint/common.cfg b/.kokoro/samples/lint/common.cfg
index 37042fc67..aece33a0d 100644
--- a/.kokoro/samples/lint/common.cfg
+++ b/.kokoro/samples/lint/common.cfg
@@ -31,4 +31,4 @@ gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
# Use the trampoline script to run in docker.
-build_file: "python-storage/.kokoro/trampoline.sh"
\ No newline at end of file
+build_file: "python-storage/.kokoro/trampoline_v2.sh"
\ No newline at end of file
diff --git a/.kokoro/samples/python3.10/common.cfg b/.kokoro/samples/python3.10/common.cfg
new file mode 100644
index 000000000..2d25848c5
--- /dev/null
+++ b/.kokoro/samples/python3.10/common.cfg
@@ -0,0 +1,40 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+# Build logs will be here
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.xml"
+ }
+}
+
+# Specify which tests to run
+env_vars: {
+ key: "RUN_TESTS_SESSION"
+ value: "py-3.10"
+}
+
+# Declare build specific Cloud project.
+env_vars: {
+ key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
+ value: "python-docs-samples-tests-310"
+}
+
+env_vars: {
+ key: "TRAMPOLINE_BUILD_FILE"
+ value: "github/python-storage/.kokoro/test-samples.sh"
+}
+
+# Configure the docker image for kokoro-trampoline.
+env_vars: {
+ key: "TRAMPOLINE_IMAGE"
+ value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker"
+}
+
+# Download secrets for samples
+gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"
+
+# Download trampoline resources.
+gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
+
+# Use the trampoline script to run in docker.
+build_file: "python-storage/.kokoro/trampoline_v2.sh"
\ No newline at end of file
diff --git a/.kokoro/samples/python3.10/continuous.cfg b/.kokoro/samples/python3.10/continuous.cfg
new file mode 100644
index 000000000..a1c8d9759
--- /dev/null
+++ b/.kokoro/samples/python3.10/continuous.cfg
@@ -0,0 +1,6 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+env_vars: {
+ key: "INSTALL_LIBRARY_FROM_SOURCE"
+ value: "True"
+}
\ No newline at end of file
diff --git a/.kokoro/samples/python3.10/periodic-head.cfg b/.kokoro/samples/python3.10/periodic-head.cfg
new file mode 100644
index 000000000..5d0faf58f
--- /dev/null
+++ b/.kokoro/samples/python3.10/periodic-head.cfg
@@ -0,0 +1,11 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+env_vars: {
+ key: "INSTALL_LIBRARY_FROM_SOURCE"
+ value: "True"
+}
+
+env_vars: {
+ key: "TRAMPOLINE_BUILD_FILE"
+ value: "github/python-storage/.kokoro/test-samples-against-head.sh"
+}
diff --git a/.kokoro/samples/python3.10/periodic.cfg b/.kokoro/samples/python3.10/periodic.cfg
new file mode 100644
index 000000000..71cd1e597
--- /dev/null
+++ b/.kokoro/samples/python3.10/periodic.cfg
@@ -0,0 +1,6 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+env_vars: {
+ key: "INSTALL_LIBRARY_FROM_SOURCE"
+ value: "False"
+}
diff --git a/.kokoro/samples/python3.10/presubmit.cfg b/.kokoro/samples/python3.10/presubmit.cfg
new file mode 100644
index 000000000..a1c8d9759
--- /dev/null
+++ b/.kokoro/samples/python3.10/presubmit.cfg
@@ -0,0 +1,6 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+env_vars: {
+ key: "INSTALL_LIBRARY_FROM_SOURCE"
+ value: "True"
+}
\ No newline at end of file
diff --git a/.kokoro/samples/python3.6/common.cfg b/.kokoro/samples/python3.6/common.cfg
index 04e100210..985a0cbfb 100644
--- a/.kokoro/samples/python3.6/common.cfg
+++ b/.kokoro/samples/python3.6/common.cfg
@@ -37,4 +37,4 @@ gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
# Use the trampoline script to run in docker.
-build_file: "python-storage/.kokoro/trampoline.sh"
\ No newline at end of file
+build_file: "python-storage/.kokoro/trampoline_v2.sh"
\ No newline at end of file
diff --git a/.kokoro/samples/python3.6/periodic.cfg b/.kokoro/samples/python3.6/periodic.cfg
index 50fec9649..71cd1e597 100644
--- a/.kokoro/samples/python3.6/periodic.cfg
+++ b/.kokoro/samples/python3.6/periodic.cfg
@@ -3,4 +3,4 @@
env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
-}
\ No newline at end of file
+}
diff --git a/.kokoro/samples/python3.7/common.cfg b/.kokoro/samples/python3.7/common.cfg
index 0089e9b79..8ad0fe6aa 100644
--- a/.kokoro/samples/python3.7/common.cfg
+++ b/.kokoro/samples/python3.7/common.cfg
@@ -37,4 +37,4 @@ gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
# Use the trampoline script to run in docker.
-build_file: "python-storage/.kokoro/trampoline.sh"
\ No newline at end of file
+build_file: "python-storage/.kokoro/trampoline_v2.sh"
\ No newline at end of file
diff --git a/.kokoro/samples/python3.7/periodic.cfg b/.kokoro/samples/python3.7/periodic.cfg
index 50fec9649..71cd1e597 100644
--- a/.kokoro/samples/python3.7/periodic.cfg
+++ b/.kokoro/samples/python3.7/periodic.cfg
@@ -3,4 +3,4 @@
env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
-}
\ No newline at end of file
+}
diff --git a/.kokoro/samples/python3.8/common.cfg b/.kokoro/samples/python3.8/common.cfg
index 2f92d6c76..10781535f 100644
--- a/.kokoro/samples/python3.8/common.cfg
+++ b/.kokoro/samples/python3.8/common.cfg
@@ -37,4 +37,4 @@ gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
# Use the trampoline script to run in docker.
-build_file: "python-storage/.kokoro/trampoline.sh"
\ No newline at end of file
+build_file: "python-storage/.kokoro/trampoline_v2.sh"
\ No newline at end of file
diff --git a/.kokoro/samples/python3.8/periodic.cfg b/.kokoro/samples/python3.8/periodic.cfg
index 50fec9649..71cd1e597 100644
--- a/.kokoro/samples/python3.8/periodic.cfg
+++ b/.kokoro/samples/python3.8/periodic.cfg
@@ -3,4 +3,4 @@
env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
-}
\ No newline at end of file
+}
diff --git a/.kokoro/samples/python3.9/common.cfg b/.kokoro/samples/python3.9/common.cfg
index b4dd47038..a1c578d5c 100644
--- a/.kokoro/samples/python3.9/common.cfg
+++ b/.kokoro/samples/python3.9/common.cfg
@@ -37,4 +37,4 @@ gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
# Use the trampoline script to run in docker.
-build_file: "python-storage/.kokoro/trampoline.sh"
\ No newline at end of file
+build_file: "python-storage/.kokoro/trampoline_v2.sh"
\ No newline at end of file
diff --git a/.kokoro/samples/python3.9/periodic.cfg b/.kokoro/samples/python3.9/periodic.cfg
index 50fec9649..71cd1e597 100644
--- a/.kokoro/samples/python3.9/periodic.cfg
+++ b/.kokoro/samples/python3.9/periodic.cfg
@@ -3,4 +3,4 @@
env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
-}
\ No newline at end of file
+}
diff --git a/.kokoro/test-samples-against-head.sh b/.kokoro/test-samples-against-head.sh
index aa5013db2..ba3a707b0 100755
--- a/.kokoro/test-samples-against-head.sh
+++ b/.kokoro/test-samples-against-head.sh
@@ -23,6 +23,4 @@ set -eo pipefail
# Enables `**` to include files nested inside sub-folders
shopt -s globstar
-cd github/python-storage
-
exec .kokoro/test-samples-impl.sh
diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh
index 421439bc8..11c042d34 100755
--- a/.kokoro/test-samples.sh
+++ b/.kokoro/test-samples.sh
@@ -24,8 +24,6 @@ set -eo pipefail
# Enables `**` to include files nested inside sub-folders
shopt -s globstar
-cd github/python-storage
-
# Run periodic samples tests at latest release
if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then
# preserving the test runner implementation.
diff --git a/.repo-metadata.json b/.repo-metadata.json
index 315fd7657..62797084a 100644
--- a/.repo-metadata.json
+++ b/.repo-metadata.json
@@ -1,14 +1,16 @@
{
- "name": "storage",
- "name_pretty": "Google Cloud Storage",
- "product_documentation": "https://cloud.google.com/storage",
- "client_documentation": "https://googleapis.dev/python/storage/latest",
- "issue_tracker": "https://issuetracker.google.com/savedsearches/559782",
- "release_level": "ga",
- "language": "python",
- "library_type": "GAPIC_MANUAL",
- "repo": "googleapis/python-storage",
- "distribution_name": "google-cloud-storage",
- "api_id": "storage.googleapis.com",
- "requires_billing": true
-}
\ No newline at end of file
+ "name": "storage",
+ "name_pretty": "Google Cloud Storage",
+ "product_documentation": "https://cloud.google.com/storage",
+ "client_documentation": "https://googleapis.dev/python/storage/latest",
+ "issue_tracker": "https://issuetracker.google.com/savedsearches/559782",
+ "release_level": "ga",
+ "language": "python",
+ "library_type": "GAPIC_MANUAL",
+ "repo": "googleapis/python-storage",
+ "distribution_name": "google-cloud-storage",
+ "api_id": "storage.googleapis.com",
+ "requires_billing": true,
+ "default_version": "",
+ "codeowner_team": "@googleapis/cloud-storage-dpe"
+}
diff --git a/.trampolinerc b/.trampolinerc
index 383b6ec89..0eee72ab6 100644
--- a/.trampolinerc
+++ b/.trampolinerc
@@ -16,15 +16,26 @@
# Add required env vars here.
required_envvars+=(
- "STAGING_BUCKET"
- "V2_STAGING_BUCKET"
)
# Add env vars which are passed down into the container here.
pass_down_envvars+=(
+ "NOX_SESSION"
+ ###############
+ # Docs builds
+ ###############
"STAGING_BUCKET"
"V2_STAGING_BUCKET"
- "NOX_SESSION"
+ ##################
+ # Samples builds
+ ##################
+ "INSTALL_LIBRARY_FROM_SOURCE"
+ "RUN_TESTS_SESSION"
+ "BUILD_SPECIFIC_GCLOUD_PROJECT"
+ # Target directories.
+ "RUN_TESTS_DIRS"
+ # The nox session to run.
+ "RUN_TESTS_SESSION"
)
# Prevent unintentional override on the default image.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b09bdd679..fc7d6da38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,27 @@
[1]: https://pypi.org/project/google-cloud-storage/#history
+## [1.43.0](https://www.github.com/googleapis/python-storage/compare/v1.42.3...v1.43.0) (2021-11-15)
+
+
+### Features
+
+* add ignore_flush parameter to BlobWriter ([#644](https://www.github.com/googleapis/python-storage/issues/644)) ([af9c9dc](https://www.github.com/googleapis/python-storage/commit/af9c9dc83d8582167b74105167af17c9809455de))
+* add support for Python 3.10 ([#615](https://www.github.com/googleapis/python-storage/issues/615)) ([f81a2d0](https://www.github.com/googleapis/python-storage/commit/f81a2d054616c1ca1734997a16a8f47f98ab346b))
+
+
+### Bug Fixes
+
+* raise a ValueError in BucketNotification.create() if a topic name is not set ([#617](https://www.github.com/googleapis/python-storage/issues/617)) ([9dd78df](https://www.github.com/googleapis/python-storage/commit/9dd78df444d21af51af7858e8958b505a26c0b79))
+
+
+### Documentation
+
+* add contributing and authoring guides under samples/ ([#633](https://www.github.com/googleapis/python-storage/issues/633)) ([420591a](https://www.github.com/googleapis/python-storage/commit/420591a2b71f823dbe80f4a4405d8a514f87e0fb))
+* add links to samples and how to guides ([#641](https://www.github.com/googleapis/python-storage/issues/641)) ([49f78b0](https://www.github.com/googleapis/python-storage/commit/49f78b09fed6d9f486639fd0a72542c30a0df084))
+* add README to samples subdirectory ([#639](https://www.github.com/googleapis/python-storage/issues/639)) ([58af882](https://www.github.com/googleapis/python-storage/commit/58af882c047c31f59486513c568737082bca6350))
+* update samples readme with cli args ([#651](https://www.github.com/googleapis/python-storage/issues/651)) ([75dda81](https://www.github.com/googleapis/python-storage/commit/75dda810e808074d18dfe7915f1403ad01bf2f02))
+
### [1.42.3](https://www.github.com/googleapis/python-storage/compare/v1.42.2...v1.42.3) (2021-09-30)
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 5352f2953..f0118678a 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -22,7 +22,7 @@ In order to add a feature:
documentation.
- The feature must work fully on the following CPython versions: 2.7,
- 3.5, 3.6, 3.7 and 3.8 on both UNIX and Windows.
+ 3.5, 3.6, 3.7, 3.8, 3.9 and 3.10 on both UNIX and Windows.
- The feature must not add unnecessary dependencies (where
"unnecessary" is of course subjective, but new dependencies should
@@ -111,7 +111,7 @@ Coding Style
should point to the official ``googleapis`` checkout and the
the branch should be the main branch on that remote (``main``).
-- This repository contains configuration for the
+- This repository contains configuration for the
`pre-commit `__ tool, which automates checking
our linters during a commit. If you have it installed on your ``$PATH``,
you can enable enforcing those checks via:
@@ -156,7 +156,7 @@ Running System Tests
`docs `__
for more details.
-- Once you have downloaded your json keys, set the environment variable
+- Once you have downloaded your json keys, set the environment variable
``GOOGLE_APPLICATION_CREDENTIALS`` to the absolute path of the json file::
$ export GOOGLE_APPLICATION_CREDENTIALS="/Users//path/to/app_credentials.json"
diff --git a/README.rst b/README.rst
index 60b43bae8..358a28f29 100644
--- a/README.rst
+++ b/README.rst
@@ -88,21 +88,19 @@ Windows
Example Usage
~~~~~~~~~~~~~
-You need to create a Google Cloud Storage bucket to use this client library.
-Follow along with the `official Google Cloud Storage documentation`_ to learn
-how to create a bucket.
-
-.. _official Google Cloud Storage documentation: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets
-
.. code:: python
from google.cloud import storage
client = storage.Client()
+ new_bucket = client.create_bucket('new-bucket-id')
+ new_blob = new_bucket.blob('remote/path/storage.txt')
+ new_blob.upload_from_filename(filename='/local/path.txt')
+
+ # Retrieve an existing bucket
# https://console.cloud.google.com/storage/browser/[bucket-id]/
- bucket = client.get_bucket('bucket-id-here')
+ bucket = client.get_bucket('bucket-id')
# Then do other things...
blob = bucket.get_blob('remote/path/to/file.txt')
print(blob.download_as_bytes())
blob.upload_from_string('New contents!')
- blob2 = bucket.blob('remote/path/storage.txt')
- blob2.upload_from_filename(filename='/local/path.txt')
+
diff --git a/docs/index.rst b/docs/index.rst
index 9ece79741..777926af3 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -24,6 +24,14 @@ API Reference
retry_timeout
generation_metageneration
+More Examples
+-------------
+.. toctree::
+ :maxdepth: 2
+
+ Official Google Cloud Storage How-to Guides
+ Official Google Cloud Storage Samples
+
Changelog
---------
.. toctree::
diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py
index 737afbe31..2d7eccf25 100644
--- a/google/cloud/storage/blob.py
+++ b/google/cloud/storage/blob.py
@@ -3760,6 +3760,7 @@ def open(
self,
mode="r",
chunk_size=None,
+ ignore_flush=None,
encoding=None,
errors=None,
newline=None,
@@ -3801,6 +3802,19 @@ def open(
chunk_size for writes must be exactly a multiple of 256KiB as with
other resumable uploads. The default is 40 MiB.
+ :type ignore_flush: bool
+ :param ignore_flush:
+ (Optional) For non text-mode writes, makes flush() do nothing
+ instead of raising an error. flush() without closing is not
+ supported by the remote service and therefore calling it normally
+ results in io.UnsupportedOperation. However, that behavior is
+ incompatible with some consumers and wrappers of file objects in
+ Python, such as zipfile.ZipFile or io.TextIOWrapper. Setting
+ ignore_flush will cause flush() to successfully do nothing, for
+ compatibility with those contexts. The correct way to actually flush
+ data to the remote server is to close() (using a context manager,
+ such as in the example, will cause this to happen automatically).
+
:type encoding: str
:param encoding:
(Optional) For text mode only, the name of the encoding that the stream will
@@ -3873,14 +3887,24 @@ def open(
raise ValueError(
"encoding, errors and newline arguments are for text mode only"
)
+ if ignore_flush:
+ raise ValueError(
+ "ignore_flush argument is for non-text write mode only"
+ )
return BlobReader(self, chunk_size=chunk_size, **kwargs)
elif mode == "wb":
if encoding or errors or newline:
raise ValueError(
"encoding, errors and newline arguments are for text mode only"
)
- return BlobWriter(self, chunk_size=chunk_size, **kwargs)
+ return BlobWriter(
+ self, chunk_size=chunk_size, ignore_flush=ignore_flush, **kwargs
+ )
elif mode in ("r", "rt"):
+ if ignore_flush:
+ raise ValueError(
+ "ignore_flush argument is for non-text write mode only"
+ )
return TextIOWrapper(
BlobReader(self, chunk_size=chunk_size, **kwargs),
encoding=encoding,
@@ -3888,8 +3912,13 @@ def open(
newline=newline,
)
elif mode in ("w", "wt"):
+ if ignore_flush is False:
+ raise ValueError(
+ "ignore_flush is required for text mode writing and "
+ "cannot be set to False"
+ )
return TextIOWrapper(
- BlobWriter(self, chunk_size=chunk_size, text_mode=True, **kwargs),
+ BlobWriter(self, chunk_size=chunk_size, ignore_flush=True, **kwargs),
encoding=encoding,
errors=errors,
newline=newline,
diff --git a/google/cloud/storage/fileio.py b/google/cloud/storage/fileio.py
index e9b4c23cf..54d1577f4 100644
--- a/google/cloud/storage/fileio.py
+++ b/google/cloud/storage/fileio.py
@@ -229,11 +229,23 @@ class BlobWriter(io.BufferedIOBase):
writes must be exactly a multiple of 256KiB as with other resumable
uploads. The default is the chunk_size of the blob, or 40 MiB.
- :type text_mode: boolean
+ :type text_mode: bool
:param text_mode:
- Whether this class is wrapped in 'io.TextIOWrapper'. Toggling this
- changes the behavior of flush() to conform to TextIOWrapper's
- expectations.
+ (Deprecated) A synonym for ignore_flush. For backwards-compatibility,
+ if True, sets ignore_flush to True. Use ignore_flush instead. This
+ parameter will be removed in a future release.
+
+ :type ignore_flush: bool
+ :param ignore_flush:
+ Makes flush() do nothing instead of raise an error. flush() without
+ closing is not supported by the remote service and therefore calling it
+ on this class normally results in io.UnsupportedOperation. However, that
+ behavior is incompatible with some consumers and wrappers of file
+ objects in Python, such as zipfile.ZipFile or io.TextIOWrapper. Setting
+ ignore_flush will cause flush() to successfully do nothing, for
+ compatibility with those contexts. The correct way to actually flush
+ data to the remote server is to close() (using this object as a context
+ manager is recommended).
:type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
:param retry:
@@ -278,6 +290,7 @@ def __init__(
blob,
chunk_size=None,
text_mode=False,
+ ignore_flush=False,
retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED,
**upload_kwargs
):
@@ -292,9 +305,8 @@ def __init__(
# Resumable uploads require a chunk size of a multiple of 256KiB.
# self._chunk_size must not be changed after the upload is initiated.
self._chunk_size = chunk_size or blob.chunk_size or DEFAULT_CHUNK_SIZE
- # In text mode this class will be wrapped and TextIOWrapper requires a
- # different behavior of flush().
- self._text_mode = text_mode
+ # text_mode is a deprecated synonym for ignore_flush
+ self._ignore_flush = ignore_flush or text_mode
self._retry = retry
self._upload_kwargs = upload_kwargs
@@ -394,13 +406,14 @@ def tell(self):
return self._buffer.tell() + len(self._buffer)
def flush(self):
- if self._text_mode:
- # TextIOWrapper expects this method to succeed before calling close().
- return
-
- raise io.UnsupportedOperation(
- "Cannot flush without finalizing upload. Use close() instead."
- )
+ # flush() is not fully supported by the remote service, so raise an
+ # error here, unless self._ignore_flush is set.
+ if not self._ignore_flush:
+ raise io.UnsupportedOperation(
+ "Cannot flush without finalizing upload. Use close() instead, "
+ "or set ignore_flush=True when constructing this class (see "
+ "docstring)."
+ )
def close(self):
self._checkClosed() # Raises ValueError if closed.
diff --git a/google/cloud/storage/notification.py b/google/cloud/storage/notification.py
index d23343100..57faea571 100644
--- a/google/cloud/storage/notification.py
+++ b/google/cloud/storage/notification.py
@@ -253,6 +253,8 @@ def create(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=None):
:type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
:param retry:
(Optional) How to retry the RPC. See: :ref:`configuring_retries`
+
+ :raises ValueError: if the notification already exists.
"""
if self.notification_id is not None:
raise ValueError(
@@ -267,7 +269,14 @@ def create(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=None):
path = "/b/{}/notificationConfigs".format(self.bucket.name)
properties = self._properties.copy()
- properties["topic"] = _TOPIC_REF_FMT.format(self.topic_project, self.topic_name)
+
+ if self.topic_name is None:
+ properties["topic"] = _TOPIC_REF_FMT.format(self.topic_project, "")
+ else:
+ properties["topic"] = _TOPIC_REF_FMT.format(
+ self.topic_project, self.topic_name
+ )
+
self._properties = client._post_resource(
path, properties, query_params=query_params, timeout=timeout, retry=retry,
)
diff --git a/google/cloud/storage/version.py b/google/cloud/storage/version.py
index 8b0acef0b..602d66b15 100644
--- a/google/cloud/storage/version.py
+++ b/google/cloud/storage/version.py
@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "1.42.3"
+__version__ = "1.43.0"
diff --git a/noxfile.py b/noxfile.py
index 3e6a7ceaa..67bfa4eeb 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -29,7 +29,7 @@
DEFAULT_PYTHON_VERSION = "3.8"
SYSTEM_TEST_PYTHON_VERSIONS = ["2.7", "3.8"]
-UNIT_TEST_PYTHON_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"]
+UNIT_TEST_PYTHON_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10"]
CONFORMANCE_TEST_PYTHON_VERSIONS = ["3.8"]
_DEFAULT_STORAGE_HOST = "https://storage.googleapis.com"
diff --git a/owlbot.py b/owlbot.py
index 73d931454..828536f24 100644
--- a/owlbot.py
+++ b/owlbot.py
@@ -26,6 +26,7 @@
templated_files = common.py_library(
cov_level=100,
split_system_tests=True,
+ unit_test_python_versions=["3.6", "3.7", "3.8", "3.9", "3.10"],
system_test_external_dependencies=[
"google-cloud-iam",
"google-cloud-pubsub < 2.0.0",
diff --git a/samples/AUTHORING_GUIDE.md b/samples/AUTHORING_GUIDE.md
new file mode 100644
index 000000000..55c97b32f
--- /dev/null
+++ b/samples/AUTHORING_GUIDE.md
@@ -0,0 +1 @@
+See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/AUTHORING_GUIDE.md
\ No newline at end of file
diff --git a/samples/CONTRIBUTING.md b/samples/CONTRIBUTING.md
new file mode 100644
index 000000000..34c882b6f
--- /dev/null
+++ b/samples/CONTRIBUTING.md
@@ -0,0 +1 @@
+See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/CONTRIBUTING.md
\ No newline at end of file
diff --git a/samples/README.md b/samples/README.md
new file mode 100644
index 000000000..bb48adc9b
--- /dev/null
+++ b/samples/README.md
@@ -0,0 +1,1085 @@
+
+
+
+# Google Cloud Storage Python Samples
+
+[![Open in Cloud Shell][shell_img]][shell_link]
+
+
+This directory contains samples for Google Cloud Storage.
+[Cloud Storage](https://cloud.google.com/storage/docs) allows world-wide
+storage and retrieval of any amount of data at any time. You can use Google
+Cloud Storage for a range of scenarios including serving website content,
+storing data for archival and disaster recovery, or distributing large data
+objects to users via direct download.
+
+## Setup
+
+### Before you begin
+
+Before running the samples, make sure you've followed the steps outlined in
+[Quick Start](https://github.com/googleapis/python-storage#quick-start).
+
+### Authentication
+This sample requires you to have authentication setup. Refer to the [Authentication Getting Started Guide](https://cloud.google.com/docs/authentication/getting-started)
+for instructions on setting up credentials for applications.
+
+### Install Dependencies
+1. Clone this repository and change to the sample directory you want to use.
+ ```
+ git clone https://github.com/googleapis/python-storage.git
+ ```
+
+2. Install [pip](https://pip.pypa.io/) and [virtualenv](https://virtualenv.pypa.io) if you do not already have them. You may want to refer to the [Python Development Environment Setup Guide](https://cloud.google.com/python/setup) for Google Cloud Platform for instructions.
+
+3. Create a virtualenv. Samples are compatible with Python 3.6+.
+ ```
+ virtualenv env
+ source env/bin/activate
+ ```
+
+4. Install the dependencies needed to run the samples.
+ ```
+ cd samples/snippets
+ pip install -r requirements.txt
+ ```
+
+## Samples
+
+ List of Samples
+
+* [Activate HMAC Key](#activate-hmac-key)
+* [Add Bucket Conditional IAM Binding](#add-bucket-conditional-iam-binding)
+* [Add Bucket Default Owner](#add-bucket-default-owner)
+* [Add Bucket IAM Member](#add-bucket-iam-member)
+* [Add Bucket Label](#add-bucket-label)
+* [Add Bucket Owner](#add-bucket-owner)
+* [Add File Owner](#add-file-owner)
+* [Bucket Delete Default KMS Key](#bucket-delete-default-kms-key)
+* [Change Default Storage Class](#change-default-storage-class)
+* [Change File Storage Class](#change-file-storage-class)
+* [Compose File](#compose-file)
+* [Configure Retries](#configure-retries)
+* [Copy File](#copy-file)
+* [Copy File Archived Generation](#copy-file-archived-generation)
+* [CORS Configuration](#cors-configuration)
+* [Create Bucket](#create-bucket)
+* [Create Bucket Class Location](#create-bucket-class-location)
+* [Create Bucket Notifications](#create-bucket-notifications)
+* [Create HMAC Key](#create-hmac-key)
+* [Deactivate HMAC Key](#deactivate-hmac-key)
+* [Define Bucket Website Configuration](#define-bucket-website-configuration)
+* [Delete Bucket](#delete-bucket)
+* [Delete Bucket Notification](#delete-bucket-notification)
+* [Delete File](#delete-file)
+* [Delete File Archived Generation](#delete-file-archived-generation)
+* [Delete HMAC Key](#delete-hmac-key)
+* [Disable Bucket Lifecycle Management](#disable-bucket-lifecycle-management)
+* [Disable Default Event Based Hold](#disable-default-event-based-hold)
+* [Disable Requester Pays](#disable-requester-pays)
+* [Disable Uniform Bucket Level Access](#disable-uniform-bucket-level-access)
+* [Disable Versioning](#disable-versioning)
+* [Download Encrypted File](#download-encrypted-file)
+* [Download File](#download-file)
+* [Download File Requester Pays](#download-file-requester-pays)
+* [Download Public File](#download-public-file)
+* [Enable Bucket Lifecycle Management](#enable-bucket-lifecycle-management)
+* [Enable Default Event Based Hold](#enable-default-event-based-hold)
+* [Enable Requester Pays](#enable-requester-pays)
+* [Enable Uniform Bucket Level Access](#enable-uniform-bucket-level-access)
+* [Enable Versioning](#enable-versioning)
+* [FileIO Write-Read] (#fileio-write-read)
+* [FileIO Pandas] (#fileio-pandas)
+* [Generate Encryption Key](#generate-encryption-key)
+* [Generate Signed Post Policy V4](#generate-signed-post-policy-v4)
+* [Generate Signed Url V2](#generate-signed-url-v2)
+* [Generate Signed Url V4](#generate-signed-url-v4)
+* [Generate Upload Signed Url V4](#generate-upload-signed-url-v4)
+* [Get Bucket Labels](#get-bucket-labels)
+* [Get Bucket Metadata](#get-bucket-metadata)
+* [Get Default Event Based Hold](#get-default-event-based-hold)
+* [Get HMAC Key](#get-hmac-key)
+* [Get Metadata](#get-metadata)
+* [Get Public Access Prevention](#get-public-access-prevention)
+* [Get Requester Pays Status](#get-requester-pays-status)
+* [Get Retention Policy](#get-retention-policy)
+* [Get Service Account](#get-service-account)
+* [Get Uniform Bucket Level Access](#get-uniform-bucket-level-access)
+* [List Buckets](#list-buckets)
+* [List Bucket Notifications](#list-bucket-notifications)
+* [List File Archived Generations](#list-file-archived-generations)
+* [List Files](#list-files)
+* [List Files With Prefix](#list-files-with-prefix)
+* [List HMAC Keys](#list-hmac-keys)
+* [Lock Retention Policy](#lock-retention-policy)
+* [Make Public](#make-public)
+* [Move File](#move-file)
+* [Object CSEK To CMEK](#object-csek-to-cmek)
+* [Object Get KMS Key](#object-get-kms-key)
+* [Print Bucket ACL](#print-bucket-acl)
+* [Print Bucket ACL For User](#print-bucket-acl-for-user)
+* [Print File ACL](#print-file-acl)
+* [Print File ACL For User](#print-file-acl-for-user)
+* [Print PubSub Bucket Notification](#print-pubsub-bucket-notification)
+* [Release Event Based Hold](#release-event-based-hold)
+* [Release Temporary Hold](#release-temporary-hold)
+* [Remove Bucket Conditional IAM Binding](#remove-bucket-conditional-iam-binding)
+* [Remove Bucket Default Owner](#remove-bucket-default-owner)
+* [Remove Bucket IAM Member](#remove-bucket-iam-member)
+* [Remove Bucket Label](#remove-bucket-label)
+* [Remove Bucket Owner](#remove-bucket-owner)
+* [Remove Cors Configuration](#remove-cors-configuration)
+* [Remove File Owner](#remove-file-owner)
+* [Remove Retention Policy](#remove-retention-policy)
+* [Rename File](#rename-file)
+* [Rotate Encryption Key](#rotate-encryption-key)
+* [Set Bucket Default KMS Key](#set-bucket-default-kms-key)
+* [Set Bucket Public IAM](#set-bucket-public-iam)
+* [Set Event Based Hold](#set-event-based-hold)
+* [Set Metadata](#set-metadata)
+* [Set Public Access Prevention Enforced](#set-public-access-prevention-enforced)
+* [Set Public Access Prevention Inherited](#set-public-access-prevention-inherited)
+* [Set Public Access Prevention Unspecified](#set-public-access-prevention-unspecified)
+* [Set Retention Policy](#set-retention-policy)
+* [Set Temporary Hold](#set-temporary-hold)
+* [Upload Encrypted File](#upload-encrypted-file)
+* [Upload File](#upload-file)
+* [Upload With KMS Key](#upload-with-kms-key)
+* [View Bucket IAM Members](#view-bucket-iam-members)
+
+
+
+-----
+### Activate HMAC Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_activate_hmac_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_activate_hmac_key.py). To run this sample:
+
+
+`python storage_activate_hmac_key.py `
+
+-----
+
+### Add Bucket Conditional IAM Binding
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_add_bucket_conditional_iam_binding.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_add_bucket_conditional_iam_binding.py). To run this sample:
+
+
+`python storage_add_bucket_conditional_iam_binding.py `
+
+-----
+### Add Bucket Default Owner
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_add_bucket_default_owner.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_add_bucket_default_owner.py). To run this sample:
+
+
+`python storage_add_bucket_default_owner.py `
+
+-----
+### Add Bucket IAM Member
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_add_bucket_iam_member.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_add_bucket_iam_member.py). To run this sample:
+
+
+`python storage_add_bucket_iam_member.py `
+
+-----
+### Add Bucket Label
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_add_bucket_label.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_add_bucket_label.py). To run this sample:
+
+
+`python storage_add_bucket_label.py `
+
+-----
+### Add Bucket Owner
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_add_bucket_owner.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_add_bucket_owner.py). To run this sample:
+
+
+`python storage_add_bucket_owner.py `
+
+-----
+### Add File Owner
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_add_file_owner.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_add_file_owner.py). To run this sample:
+
+
+`python storage_add_file_owner.py `
+
+-----
+### Bucket Delete Default KMS Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_bucket_delete_default_kms_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_bucket_delete_default_kms_key.py). To run this sample:
+
+
+`python storage_bucket_delete_default_kms_key.py `
+
+-----
+### Change Default Storage Class
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_change_default_storage_class.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_change_default_storage_class.py). To run this sample:
+
+
+`python storage_change_default_storage_class.py `
+
+-----
+### Change File Storage Class
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_change_file_storage_class.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_change_file_storage_class.py). To run this sample:
+
+
+`python storage_change_file_storage_class.py `
+
+-----
+### Compose File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_compose_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_compose_file.py). To run this sample:
+
+
+`python storage_compose_file.py `
+
+-----
+### Configure Retries
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_configure_retries.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_configure_retries.py). To run this sample:
+
+
+`python storage_configure_retries.py `
+
+-----
+### Copy File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_copy_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_copy_file.py). To run this sample:
+
+
+`python storage_copy_file.py `
+
+-----
+### Copy File Archived Generation
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_copy_file_archived_generation.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_copy_file_archived_generation.py). To run this sample:
+
+
+`python storage_copy_file_archived_generation.py `
+
+-----
+### CORS Configuration
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_cors_configuration.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_cors_configuration.py). To run this sample:
+
+
+`python storage_cors_configuration.py `
+
+-----
+### Create Bucket
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_create_bucket.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_create_bucket.py). To run this sample:
+
+
+`python storage_create_bucket.py `
+
+-----
+### Create Bucket Class Location
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_create_bucket_class_location.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_create_bucket_class_location.py). To run this sample:
+
+
+`python storage_create_bucket_class_location.py `
+
+-----
+### Create Bucket Notifications
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_create_bucket_notifications.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_create_bucket_notifications.py). To run this sample:
+
+
+`python storage_create_bucket_notifications.py `
+
+-----
+### Create HMAC Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_create_hmac_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_create_hmac_key.py). To run this sample:
+
+
+`python storage_create_hmac_key.py `
+
+-----
+### Deactivate HMAC Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_deactivate_hmac_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_deactivate_hmac_key.py). To run this sample:
+
+
+`python storage_deactivate_hmac_key.py `
+
+-----
+### Define Bucket Website Configuration
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_define_bucket_website_configuration.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_define_bucket_website_configuration.py). To run this sample:
+
+
+`python storage_define_bucket_website_configuration.py `
+
+-----
+### Delete Bucket
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_delete_bucket.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_delete_bucket.py). To run this sample:
+
+
+`python storage_delete_bucket.py `
+
+-----
+### Delete Bucket Notification
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_delete_bucket_notification.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_delete_bucket_notification.py). To run this sample:
+
+
+`python storage_delete_bucket_notification.py `
+
+-----
+### Delete File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_delete_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_delete_file.py). To run this sample:
+
+
+`python storage_delete_file.py `
+
+-----
+### Delete File Archived Generation
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_delete_file_archived_generation.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_delete_file_archived_generation.py). To run this sample:
+
+
+`python storage_delete_file_archived_generation.py `
+
+-----
+### Delete HMAC Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_delete_hmac_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_delete_hmac_key.py). To run this sample:
+
+
+`python storage_delete_hmac_key.py `
+
+-----
+### Disable Bucket Lifecycle Management
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_disable_bucket_lifecycle_management.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_disable_bucket_lifecycle_management.py). To run this sample:
+
+
+`python storage_disable_bucket_lifecycle_management.py `
+
+-----
+### Disable Default Event Based Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_disable_default_event_based_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_disable_default_event_based_hold.py). To run this sample:
+
+
+`python storage_disable_default_event_based_hold.py `
+
+-----
+### Disable Requester Pays
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_disable_requester_pays.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_disable_requester_pays.py). To run this sample:
+
+
+`python storage_disable_requester_pays.py `
+
+-----
+### Disable Uniform Bucket Level Access
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_disable_uniform_bucket_level_access.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_disable_uniform_bucket_level_access.py). To run this sample:
+
+
+`python storage_disable_uniform_bucket_level_access.py `
+
+-----
+### Disable Versioning
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_disable_versioning.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_disable_versioning.py). To run this sample:
+
+
+`python storage_disable_versioning.py `
+
+-----
+### Download Encrypted File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_download_encrypted_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_download_encrypted_file.py). To run this sample:
+
+
+`python storage_download_encrypted_file.py <>BASE64_ENCRYPTION_KEY`
+
+-----
+### Download File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_download_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_download_file.py). To run this sample:
+
+
+`python storage_download_file.py `
+
+-----
+### Download File Requester Pays
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_download_file_requester_pays.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_download_file_requester_pays.py). To run this sample:
+
+
+`python storage_download_file_requester_pays.py `
+
+-----
+### Download Public File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_download_public_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_download_public_file.py). To run this sample:
+
+
+`python storage_download_public_file.py `
+
+-----
+### Enable Bucket Lifecycle Management
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_enable_bucket_lifecycle_management.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_enable_bucket_lifecycle_management.py). To run this sample:
+
+
+`python storage_enable_bucket_lifecycle_management.py `
+
+-----
+### Enable Default Event Based Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_enable_default_event_based_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_enable_default_event_based_hold.py). To run this sample:
+
+
+`python storage_enable_default_event_based_hold.py `
+
+-----
+### Enable Requester Pays
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_enable_requester_pays.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_enable_requester_pays.py). To run this sample:
+
+
+`python storage_enable_requester_pays.py `
+
+-----
+### Enable Uniform Bucket Level Access
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_enable_uniform_bucket_level_access.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_enable_uniform_bucket_level_access.py). To run this sample:
+
+
+`python storage_enable_uniform_bucket_level_access.py `
+
+-----
+### Enable Versioning
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_enable_versioning.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_enable_versioning.py). To run this sample:
+
+
+`python storage_enable_versioning.py `
+
+-----
+### FileIO Write-Read
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_fileio_write_read.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_fileio_write_read.py). To run this sample:
+
+
+`python storage_fileio_write_read.py `
+
+-----
+### FileIO Pandas
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_fileio_pandas.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_fileio_pandas.py). To run this sample:
+
+
+`python storage_fileio_pandas.py `
+
+-----
+### Generate Encryption Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_generate_encryption_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_generate_encryption_key.py). To run this sample:
+
+
+`python storage_generate_encryption_key.py`
+
+-----
+### Generate Signed Post Policy V4
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_generate_signed_post_policy_v4.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_generate_signed_post_policy_v4.py). To run this sample:
+
+
+`python storage_generate_signed_post_policy_v4.py `
+
+-----
+### Generate Signed Url V2
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_generate_signed_url_v2.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_generate_signed_url_v2.py). To run this sample:
+
+
+`python storage_generate_signed_url_v2.py `
+
+-----
+### Generate Signed Url V4
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_generate_signed_url_v4.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_generate_signed_url_v4.py). To run this sample:
+
+
+`python storage_generate_signed_url_v4.py `
+
+-----
+### Generate Upload Signed Url V4
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_generate_upload_signed_url_v4.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_generate_upload_signed_url_v4.py). To run this sample:
+
+
+`python storage_generate_upload_signed_url_v4.py `
+
+-----
+### Get Bucket Labels
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_bucket_labels.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_bucket_labels.py). To run this sample:
+
+
+`python storage_get_bucket_labels.py `
+
+-----
+### Get Bucket Metadata
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_bucket_metadata.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_bucket_metadata.py). To run this sample:
+
+
+`python storage_get_bucket_metadata.py `
+
+-----
+### Get Default Event Based Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_default_event_based_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_default_event_based_hold.py). To run this sample:
+
+
+`python storage_get_default_event_based_hold.py `
+
+-----
+### Get HMAC Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_hmac_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_hmac_key.py). To run this sample:
+
+
+`python storage_get_hmac_key.py `
+
+-----
+### Get Metadata
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_metadata.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_metadata.py). To run this sample:
+
+
+`python storage_get_metadata.py `
+
+-----
+### Get Public Access Prevention
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_public_access_prevention.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_public_access_prevention.py). To run this sample:
+
+
+`python storage_get_public_access_prevention.py `
+
+-----
+### Get Requester Pays Status
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_requester_pays_status.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_requester_pays_status.py). To run this sample:
+
+
+`python storage_get_requester_pays_status.py `
+
+-----
+### Get Retention Policy
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_retention_policy.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_retention_policy.py). To run this sample:
+
+
+`python storage_get_retention_policy.py `
+
+-----
+### Get Service Account
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_service_account.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_service_account.py). To run this sample:
+
+
+`python storage_get_service_account.py`
+
+-----
+### Get Uniform Bucket Level Access
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_get_uniform_bucket_level_access.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_get_uniform_bucket_level_access.py). To run this sample:
+
+
+`python storage_get_uniform_bucket_level_access.py `
+
+-----
+### List Buckets
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_list_buckets.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_list_buckets.py). To run this sample:
+
+
+`python storage_list_buckets.py`
+
+-----
+### List Bucket Notifications
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_list_bucket_notifications.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_list_bucket_notifications.py). To run this sample:
+
+
+`python storage_list_bucket_notifications.py `
+
+-----
+### List File Archived Generations
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_list_file_archived_generations.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_list_file_archived_generations.py). To run this sample:
+
+
+`python storage_list_file_archived_generations.py `
+
+-----
+### List Files
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_list_files.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_list_files.py). To run this sample:
+
+
+`python storage_list_files.py `
+
+-----
+### List Files With Prefix
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_list_files_with_prefix.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_list_files_with_prefix.py). To run this sample:
+
+
+`python storage_list_files_with_prefix.py `
+
+-----
+### List HMAC Keys
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_list_hmac_keys.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_list_hmac_keys.py). To run this sample:
+
+
+`python storage_list_hmac_keys.py `
+
+-----
+### Lock Retention Policy
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_lock_retention_policy.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_lock_retention_policy.py). To run this sample:
+
+
+`python storage_lock_retention_policy.py `
+
+-----
+### Make Public
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_make_public.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_make_public.py). To run this sample:
+
+
+`python storage_make_public.py `
+
+-----
+### Move File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_move_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_move_file.py). To run this sample:
+
+
+`python storage_move_file.py `
+
+-----
+### Object CSEK To CMEK
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_object_csek_to_cmek.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_object_csek_to_cmek.py). To run this sample:
+
+
+`python storage_object_csek_to_cmek.py `
+
+-----
+### Object Get KMS Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_object_get_kms_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_object_get_kms_key.py). To run this sample:
+
+
+`python storage_object_get_kms_key.py `
+
+-----
+### Print Bucket ACL
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_print_bucket_acl.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_print_bucket_acl.py). To run this sample:
+
+
+`python storage_print_bucket_acl.py `
+
+-----
+### Print Bucket ACL For User
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_print_bucket_acl_for_user.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_print_bucket_acl_for_user.py). To run this sample:
+
+
+`python storage_print_bucket_acl_for_user.py `
+
+-----
+### Print File ACL
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_print_file_acl.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_print_file_acl.py). To run this sample:
+
+
+`python storage_print_file_acl.py `
+
+-----
+### Print File ACL For User
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_print_file_acl_for_user.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_print_file_acl_for_user.py). To run this sample:
+
+
+`python storage_print_file_acl_for_user.py `
+
+-----
+### Print PubSub Bucket Notification
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_print_pubsub_bucket_notification.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_print_pubsub_bucket_notification.py). To run this sample:
+
+
+`python storage_print_pubsub_bucket_notification.py `
+
+-----
+### Release Event Based Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_release_event_based_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_release_event_based_hold.py). To run this sample:
+
+
+`python storage_release_event_based_hold.py `
+
+-----
+### Release Temporary Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_release_temporary_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_release_temporary_hold.py). To run this sample:
+
+
+`python storage_release_temporary_hold.py `
+
+-----
+### Remove Bucket Conditional IAM Binding
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_bucket_conditional_iam_binding.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_bucket_conditional_iam_binding.py). To run this sample:
+
+
+`python storage_remove_bucket_conditional_iam_binding.py `
+
+-----
+### Remove Bucket Default Owner
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_bucket_default_owner.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_bucket_default_owner.py). To run this sample:
+
+
+`python storage_remove_bucket_default_owner.py `
+
+-----
+### Remove Bucket IAM Member
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_bucket_iam_member.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_bucket_iam_member.py). To run this sample:
+
+
+`python storage_remove_bucket_iam_member.py `
+
+-----
+### Remove Bucket Label
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_bucket_label.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_bucket_label.py). To run this sample:
+
+
+`python storage_remove_bucket_label.py `
+
+-----
+### Remove Bucket Owner
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_bucket_owner.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_bucket_owner.py). To run this sample:
+
+
+`python storage_remove_bucket_owner.py `
+
+-----
+### Remove CORS Configuration
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_cors_configuration.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_cors_configuration.py). To run this sample:
+
+
+`python storage_remove_cors_configuration.py `
+
+-----
+### Remove File Owner
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_file_owner.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_file_owner.py). To run this sample:
+
+
+`python storage_remove_file_owner.py `
+
+-----
+### Remove Retention Policy
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_remove_retention_policy.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_remove_retention_policy.py). To run this sample:
+
+
+`python storage_remove_retention_policy.py `
+
+-----
+### Rename File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_rename_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_rename_file.py). To run this sample:
+
+
+`python storage_rename_file.py `
+
+-----
+### Rotate Encryption Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_rotate_encryption_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_rotate_encryption_key.py). To run this sample:
+
+
+`python storage_rotate_encryption_key.py `
+
+-----
+### Set Bucket Default KMS Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_bucket_default_kms_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_bucket_default_kms_key.py). To run this sample:
+
+
+`python storage_set_bucket_default_kms_key.py `
+
+-----
+### Set Bucket Public IAM
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_bucket_public_iam.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_bucket_public_iam.py). To run this sample:
+
+
+`python storage_set_bucket_public_iam.py `
+
+-----
+### Set Event Based Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_event_based_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_event_based_hold.py). To run this sample:
+
+
+`python storage_set_event_based_hold.py `
+
+-----
+### Set Metadata
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_metadata.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_metadata.py). To run this sample:
+
+
+`python storage_set_metadata.py `
+
+-----
+### Set Public Access Prevention Enforced
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_public_access_prevention_enforced.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_public_access_prevention_enforced.py). To run this sample:
+
+
+`python storage_set_public_access_prevention_enforced.py `
+
+-----
+### Set Public Access Prevention Inherited
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_public_access_prevention_inherited.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_public_access_prevention_inherited.py). To run this sample:
+
+
+`python storage_set_public_access_prevention_inherited.py `
+
+-----
+### Set Public Access Prevention Unspecified
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_public_access_prevention_unspecified.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_public_access_prevention_unspecified.py). To run this sample:
+
+
+`python storage_set_public_access_prevention_unspecified.py `
+
+-----
+### Set Retention Policy
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_retention_policy.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_retention_policy.py). To run this sample:
+
+
+`python storage_set_retention_policy.py `
+
+-----
+### Set Temporary Hold
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_set_temporary_hold.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_set_temporary_hold.py). To run this sample:
+
+
+`python storage_set_temporary_hold.py `
+
+-----
+### Upload Encrypted File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_upload_encrypted_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_upload_encrypted_file.py). To run this sample:
+
+
+`python storage_upload_encrypted_file.py `
+
+-----
+### Upload File
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_upload_file.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_upload_file.py). To run this sample:
+
+
+`python storage_upload_file.py `
+
+-----
+### Upload With KMS Key
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_upload_with_kms_key.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_upload_with_kms_key.py). To run this sample:
+
+
+`python storage_upload_with_kms_key.py `
+
+-----
+### View Bucket IAM Members
+[![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/snippets/storage_view_bucket_iam_members.py,samples/README.md)
+
+View the [source code](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_view_bucket_iam_members.py). To run this sample:
+
+
+`python storage_view_bucket_iam_members.py `
+
+-----
+
+## Running tests locally
+
+Before running the tests, make sure you've followed the steps outlined in
+[Setup](#setup).
+
+### Install nox
+```
+pip install nox
+```
+
+### Set environment variables
+
+You can run tests locally using your own gcs project or with a valid service account in project `python-docs-samples-tests`. This outlines the workflow of running tests locally using your own gcs project.
+
+Refer to [`noxfile_config.py`](https://github.com/googleapis/python-storage/blob/main/samples/snippets/noxfile_config.py) and [a list of environment variables](https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/testing/test-env.tmpl.sh) that can be set manually. Not every test needs all of these variables.
+The common environment variables used in the storage samples include:
+
+ export GOOGLE_CLOUD_PROJECT=[your-project-name]
+ export MAIN_GOOGLE_CLOUD_PROJECT=[your-project-name]
+ export BUILD_SPECIFIC_GCLOUD_PROJECT=[your-project-name]
+ export HMAC_KEY_TEST_SERVICE_ACCOUNT=[your-service-account]
+ export CLOUD_KMS_KEY=[your-kms-key]
+ export GOOGLE_APPLICATION_CREDENTIALS=[your-credentials]
+
+See [Other Resources](#other-resources) on how to create credentials, keys, and secrets
+
+### Run tests with nox
+```
+nox -s lint
+nox -s py-3.7 -- snippets_test.py
+nox -s py-3.7 -- snippets_test.py::test_list_blobs
+```
+
+### Special test configurations
+There are restrictions on the testing projects used in Kokoro. For instance,
+we change the service account based on different test sessions to avoid
+hitting the maximum limit of HMAC keys on a single service account.
+Another example is `requester_pays_test.py` needs to use a different Storage bucket, and looks for an environment variable `REQUESTER_PAYS_TEST_BUCKET`.
+Please refer to [`noxfile_config.py`](https://github.com/googleapis/python-storage/blob/main/samples/snippets/noxfile_config.py) , [kokoro configs](https://github.com/googleapis/python-storage/tree/main/.kokoro/samples), and test files to see if there are special test configurations required.
+
+
+### Other Resources
+* [Create Cloud KMS Keys](https://cloud.google.com/kms/docs/creating-keys)
+* [Create HMAC Keys](https://cloud.google.com/storage/docs/authentication/managing-hmackeys)
+* [Create Service Accounts](https://cloud.google.com/docs/authentication/getting-started#creating_a_service_account)
+
+[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png
+[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-storage&page=editor&open_in_editor=samples/README.md
+[product-docs]: https://cloud.google.com/storage
\ No newline at end of file
diff --git a/samples/snippets/acl_test.py b/samples/snippets/acl_test.py
new file mode 100644
index 000000000..91856d816
--- /dev/null
+++ b/samples/snippets/acl_test.py
@@ -0,0 +1,168 @@
+# Copyright 2016 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import uuid
+
+import backoff
+from google.api_core.exceptions import GoogleAPIError
+from google.cloud import storage
+import pytest
+
+import storage_add_bucket_default_owner
+import storage_add_bucket_owner
+import storage_add_file_owner
+import storage_print_bucket_acl
+import storage_print_bucket_acl_for_user
+import storage_print_file_acl
+import storage_print_file_acl_for_user
+import storage_remove_bucket_default_owner
+import storage_remove_bucket_owner
+import storage_remove_file_owner
+
+# Typically we'd use a @example.com address, but GCS requires a real Google
+# account. Retrieve a service account email with storage admin permissions.
+TEST_EMAIL = "py38-storage-test" "@python-docs-samples-tests.iam.gserviceaccount.com"
+
+
+@pytest.fixture(scope="module")
+def test_bucket():
+ """Yields a bucket that is deleted after the test completes."""
+
+ # The new projects have uniform bucket-level access and our tests don't
+ # pass with those buckets. We need to use the old main project for now.
+ original_value = os.environ["GOOGLE_CLOUD_PROJECT"]
+ os.environ["GOOGLE_CLOUD_PROJECT"] = os.environ["MAIN_GOOGLE_CLOUD_PROJECT"]
+ bucket = None
+ while bucket is None or bucket.exists():
+ bucket_name = "acl-test-{}".format(uuid.uuid4())
+ bucket = storage.Client().bucket(bucket_name)
+ bucket.create()
+ yield bucket
+ bucket.delete(force=True)
+ # Set the value back.
+ os.environ["GOOGLE_CLOUD_PROJECT"] = original_value
+
+
+@pytest.fixture
+def test_blob(test_bucket):
+ """Yields a blob that is deleted after the test completes."""
+ bucket = test_bucket
+ blob = bucket.blob("storage_acl_test_sigil-{}".format(uuid.uuid4()))
+ blob.upload_from_string("Hello, is it me you're looking for?")
+ yield blob
+
+
+def test_print_bucket_acl(test_bucket, capsys):
+ storage_print_bucket_acl.print_bucket_acl(test_bucket.name)
+ out, _ = capsys.readouterr()
+ assert out
+
+
+def test_print_bucket_acl_for_user(test_bucket, capsys):
+ test_bucket.acl.user(TEST_EMAIL).grant_owner()
+ test_bucket.acl.save()
+
+ storage_print_bucket_acl_for_user.print_bucket_acl_for_user(
+ test_bucket.name, TEST_EMAIL
+ )
+
+ out, _ = capsys.readouterr()
+ assert "OWNER" in out
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_add_bucket_owner(test_bucket):
+ storage_add_bucket_owner.add_bucket_owner(test_bucket.name, TEST_EMAIL)
+
+ test_bucket.acl.reload()
+ assert "OWNER" in test_bucket.acl.user(TEST_EMAIL).get_roles()
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_remove_bucket_owner(test_bucket):
+ test_bucket.acl.user(TEST_EMAIL).grant_owner()
+ test_bucket.acl.save()
+
+ storage_remove_bucket_owner.remove_bucket_owner(test_bucket.name, TEST_EMAIL)
+
+ test_bucket.acl.reload()
+ assert "OWNER" not in test_bucket.acl.user(TEST_EMAIL).get_roles()
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_add_bucket_default_owner(test_bucket):
+ storage_add_bucket_default_owner.add_bucket_default_owner(
+ test_bucket.name, TEST_EMAIL
+ )
+
+ test_bucket.default_object_acl.reload()
+ roles = test_bucket.default_object_acl.user(TEST_EMAIL).get_roles()
+ assert "OWNER" in roles
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_remove_bucket_default_owner(test_bucket):
+ test_bucket.acl.user(TEST_EMAIL).grant_owner()
+ test_bucket.acl.save()
+
+ storage_remove_bucket_default_owner.remove_bucket_default_owner(
+ test_bucket.name, TEST_EMAIL
+ )
+
+ test_bucket.default_object_acl.reload()
+ roles = test_bucket.default_object_acl.user(TEST_EMAIL).get_roles()
+ assert "OWNER" not in roles
+
+
+def test_print_blob_acl(test_blob, capsys):
+ storage_print_file_acl.print_blob_acl(test_blob.bucket.name, test_blob.name)
+ out, _ = capsys.readouterr()
+ assert out
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_print_blob_acl_for_user(test_blob, capsys):
+ test_blob.acl.user(TEST_EMAIL).grant_owner()
+ test_blob.acl.save()
+
+ storage_print_file_acl_for_user.print_blob_acl_for_user(
+ test_blob.bucket.name, test_blob.name, TEST_EMAIL
+ )
+
+ out, _ = capsys.readouterr()
+ assert "OWNER" in out
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_add_blob_owner(test_blob):
+ storage_add_file_owner.add_blob_owner(
+ test_blob.bucket.name, test_blob.name, TEST_EMAIL
+ )
+
+ test_blob.acl.reload()
+ assert "OWNER" in test_blob.acl.user(TEST_EMAIL).get_roles()
+
+
+@backoff.on_exception(backoff.expo, GoogleAPIError, max_time=60)
+def test_remove_blob_owner(test_blob):
+ test_blob.acl.user(TEST_EMAIL).grant_owner()
+ test_blob.acl.save()
+
+ storage_remove_file_owner.remove_blob_owner(
+ test_blob.bucket.name, test_blob.name, TEST_EMAIL
+ )
+
+ test_blob.acl.reload()
+ assert "OWNER" not in test_blob.acl.user(TEST_EMAIL).get_roles()
diff --git a/samples/snippets/bucket_lock_test.py b/samples/snippets/bucket_lock_test.py
new file mode 100644
index 000000000..67d4ec685
--- /dev/null
+++ b/samples/snippets/bucket_lock_test.py
@@ -0,0 +1,176 @@
+# Copyright 2018 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+import uuid
+
+from google.cloud import storage
+import pytest
+
+import storage_disable_default_event_based_hold
+import storage_enable_default_event_based_hold
+import storage_get_default_event_based_hold
+import storage_get_retention_policy
+import storage_lock_retention_policy
+import storage_release_event_based_hold
+import storage_release_temporary_hold
+import storage_remove_retention_policy
+import storage_set_event_based_hold
+import storage_set_retention_policy
+import storage_set_temporary_hold
+
+
+BLOB_NAME = "storage_snippets_test_sigil"
+BLOB_CONTENT = "Hello, is it me you're looking for?"
+# Retention policy for 5 seconds
+RETENTION_POLICY = 5
+
+
+@pytest.fixture
+def bucket():
+ """Yields a bucket that is deleted after the test completes."""
+ bucket = None
+ while bucket is None or bucket.exists():
+ bucket_name = "bucket-lock-{}".format(uuid.uuid4())
+ bucket = storage.Client().bucket(bucket_name)
+ bucket.create()
+ yield bucket
+ bucket.delete(force=True)
+
+
+def test_retention_policy_no_lock(bucket, capsys):
+ storage_set_retention_policy.set_retention_policy(
+ bucket.name, RETENTION_POLICY
+ )
+ bucket.reload()
+
+ assert bucket.retention_period is RETENTION_POLICY
+ assert bucket.retention_policy_effective_time is not None
+ assert bucket.retention_policy_locked is None
+
+ storage_get_retention_policy.get_retention_policy(bucket.name)
+ out, _ = capsys.readouterr()
+ assert "Retention Policy for {}".format(bucket.name) in out
+ assert "Retention Period: 5" in out
+ assert "Effective Time: " in out
+ assert "Retention Policy is locked" not in out
+
+ blob = bucket.blob(BLOB_NAME)
+ blob.upload_from_string(BLOB_CONTENT)
+
+ assert blob.retention_expiration_time is not None
+
+ storage_remove_retention_policy.remove_retention_policy(bucket.name)
+ bucket.reload()
+ assert bucket.retention_period is None
+
+ time.sleep(RETENTION_POLICY)
+
+
+def test_retention_policy_lock(bucket, capsys):
+ storage_set_retention_policy.set_retention_policy(
+ bucket.name, RETENTION_POLICY
+ )
+ bucket.reload()
+ assert bucket.retention_policy_locked is None
+
+ storage_lock_retention_policy.lock_retention_policy(bucket.name)
+ bucket.reload()
+ assert bucket.retention_policy_locked is True
+
+ storage_get_retention_policy.get_retention_policy(bucket.name)
+ out, _ = capsys.readouterr()
+ assert "Retention Policy is locked" in out
+
+
+def test_enable_disable_bucket_default_event_based_hold(bucket, capsys):
+ storage_get_default_event_based_hold.get_default_event_based_hold(
+ bucket.name
+ )
+ out, _ = capsys.readouterr()
+ assert (
+ "Default event-based hold is not enabled for {}".format(bucket.name)
+ in out
+ )
+ assert (
+ "Default event-based hold is enabled for {}".format(bucket.name)
+ not in out
+ )
+
+ storage_enable_default_event_based_hold.enable_default_event_based_hold(
+ bucket.name
+ )
+ bucket.reload()
+
+ assert bucket.default_event_based_hold is True
+
+ storage_get_default_event_based_hold.get_default_event_based_hold(
+ bucket.name
+ )
+ out, _ = capsys.readouterr()
+ assert (
+ "Default event-based hold is enabled for {}".format(bucket.name) in out
+ )
+
+ # Changes to the bucket will be readable immediately after writing,
+ # but configuration changes may take time to propagate.
+ time.sleep(10)
+
+ blob = bucket.blob(BLOB_NAME)
+ blob.upload_from_string(BLOB_CONTENT)
+ assert blob.event_based_hold is True
+
+ storage_release_event_based_hold.release_event_based_hold(
+ bucket.name, blob.name
+ )
+ blob.reload()
+ assert blob.event_based_hold is False
+
+ storage_disable_default_event_based_hold.disable_default_event_based_hold(
+ bucket.name
+ )
+ bucket.reload()
+ assert bucket.default_event_based_hold is False
+
+
+def test_enable_disable_temporary_hold(bucket):
+ blob = bucket.blob(BLOB_NAME)
+ blob.upload_from_string(BLOB_CONTENT)
+ assert blob.temporary_hold is None
+
+ storage_set_temporary_hold.set_temporary_hold(bucket.name, blob.name)
+ blob.reload()
+ assert blob.temporary_hold is True
+
+ storage_release_temporary_hold.release_temporary_hold(
+ bucket.name, blob.name
+ )
+ blob.reload()
+ assert blob.temporary_hold is False
+
+
+def test_enable_disable_event_based_hold(bucket):
+ blob = bucket.blob(BLOB_NAME)
+ blob.upload_from_string(BLOB_CONTENT)
+ assert blob.event_based_hold is None
+
+ storage_set_event_based_hold.set_event_based_hold(bucket.name, blob.name)
+ blob.reload()
+ assert blob.event_based_hold is True
+
+ storage_release_event_based_hold.release_event_based_hold(
+ bucket.name, blob.name
+ )
+ blob.reload()
+ assert blob.event_based_hold is False
diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py
new file mode 100644
index 000000000..b0db57561
--- /dev/null
+++ b/samples/snippets/conftest.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import time
+import uuid
+
+from google.cloud import storage
+import pytest
+
+
+@pytest.fixture(scope="function")
+def bucket():
+ """Yields a bucket that is deleted after the test completes."""
+ # The new projects enforces uniform bucket level access, so
+ # we need to use the old main project for now.
+ original_value = os.environ['GOOGLE_CLOUD_PROJECT']
+ os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
+ bucket = None
+ while bucket is None or bucket.exists():
+ bucket_name = f"uniform-bucket-level-access-{uuid.uuid4().hex}"
+ bucket = storage.Client().bucket(bucket_name)
+ bucket.create()
+ yield bucket
+ time.sleep(3)
+ bucket.delete(force=True)
+ # Set the value back.
+ os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
diff --git a/samples/snippets/encryption_test.py b/samples/snippets/encryption_test.py
new file mode 100644
index 000000000..6c2377e0f
--- /dev/null
+++ b/samples/snippets/encryption_test.py
@@ -0,0 +1,125 @@
+# Copyright 2016 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import base64
+import os
+import tempfile
+import uuid
+
+from google.api_core.exceptions import NotFound
+from google.cloud import storage
+from google.cloud.storage import Blob
+import pytest
+
+import storage_download_encrypted_file
+import storage_generate_encryption_key
+import storage_object_csek_to_cmek
+import storage_rotate_encryption_key
+import storage_upload_encrypted_file
+
+BUCKET = os.environ["CLOUD_STORAGE_BUCKET"]
+KMS_KEY = os.environ["CLOUD_KMS_KEY"]
+
+TEST_ENCRYPTION_KEY = "brtJUWneL92g5q0N2gyDSnlPSYAiIVZ/cWgjyZNeMy0="
+TEST_ENCRYPTION_KEY_DECODED = base64.b64decode(TEST_ENCRYPTION_KEY)
+
+TEST_ENCRYPTION_KEY_2 = "o4OD7SWCaPjfeEGhAY+YCgMdY9UW+OJ8mvfWD9lNtO4="
+TEST_ENCRYPTION_KEY_2_DECODED = base64.b64decode(TEST_ENCRYPTION_KEY_2)
+
+
+def test_generate_encryption_key(capsys):
+ storage_generate_encryption_key.generate_encryption_key()
+ out, _ = capsys.readouterr()
+ encoded_key = out.split(":", 1).pop().strip()
+ key = base64.b64decode(encoded_key)
+ assert len(key) == 32, "Returned key should be 32 bytes"
+
+
+def test_upload_encrypted_blob():
+ with tempfile.NamedTemporaryFile() as source_file:
+ source_file.write(b"test")
+
+ storage_upload_encrypted_file.upload_encrypted_blob(
+ BUCKET,
+ source_file.name,
+ "test_encrypted_upload_blob",
+ TEST_ENCRYPTION_KEY,
+ )
+
+
+@pytest.fixture(scope="module")
+def test_blob():
+ """Provides a pre-existing blob in the test bucket."""
+ bucket = storage.Client().bucket(BUCKET)
+ blob_name = "test_blob_{}".format(uuid.uuid4().hex)
+ blob = Blob(
+ blob_name,
+ bucket,
+ encryption_key=TEST_ENCRYPTION_KEY_DECODED,
+ )
+ content = "Hello, is it me you're looking for?"
+ blob.upload_from_string(content)
+
+ yield blob.name, content
+
+ # To delete an encrypted blob, you have to provide the same key
+ # used for the blob. When you provide a wrong key, you'll get
+ # NotFound.
+ try:
+ # Clean up for the case that the rotation didn't occur.
+ blob.delete()
+ except NotFound as e:
+ # For the case that the rotation succeeded.
+ print("Ignoring 404, detail: {}".format(e))
+ blob = Blob(
+ blob_name,
+ bucket,
+ encryption_key=TEST_ENCRYPTION_KEY_2_DECODED
+ )
+ blob.delete()
+
+
+def test_download_blob(test_blob):
+ test_blob_name, test_blob_content = test_blob
+ with tempfile.NamedTemporaryFile() as dest_file:
+ storage_download_encrypted_file.download_encrypted_blob(
+ BUCKET, test_blob_name, dest_file.name, TEST_ENCRYPTION_KEY
+ )
+
+ downloaded_content = dest_file.read().decode("utf-8")
+ assert downloaded_content == test_blob_content
+
+
+def test_rotate_encryption_key(test_blob):
+ test_blob_name, test_blob_content = test_blob
+ storage_rotate_encryption_key.rotate_encryption_key(
+ BUCKET, test_blob_name, TEST_ENCRYPTION_KEY, TEST_ENCRYPTION_KEY_2
+ )
+
+ with tempfile.NamedTemporaryFile() as dest_file:
+ storage_download_encrypted_file.download_encrypted_blob(
+ BUCKET, test_blob_name, dest_file.name, TEST_ENCRYPTION_KEY_2
+ )
+
+ downloaded_content = dest_file.read().decode("utf-8")
+ assert downloaded_content == test_blob_content
+
+
+def test_object_csek_to_cmek(test_blob):
+ test_blob_name, test_blob_content = test_blob
+ cmek_blob = storage_object_csek_to_cmek.object_csek_to_cmek(
+ BUCKET, test_blob_name, TEST_ENCRYPTION_KEY_2, KMS_KEY
+ )
+
+ assert cmek_blob.download_as_string(), test_blob_content
diff --git a/samples/snippets/fileio_test.py b/samples/snippets/fileio_test.py
new file mode 100644
index 000000000..cf98ce1ab
--- /dev/null
+++ b/samples/snippets/fileio_test.py
@@ -0,0 +1,35 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import uuid
+
+import storage_fileio_pandas
+import storage_fileio_write_read
+
+
+def test_fileio_write_read(bucket, capsys):
+ blob_name = "test-fileio-{}".format(uuid.uuid4())
+ storage_fileio_write_read.write_read(bucket.name, blob_name)
+ out, _ = capsys.readouterr()
+ assert "Hello world" in out
+
+
+def test_fileio_pandas(bucket, capsys):
+ blob_name = "test-fileio-{}".format(uuid.uuid4())
+ storage_fileio_pandas.pandas_write(bucket.name, blob_name)
+ out, _ = capsys.readouterr()
+ assert f"Wrote csv with pandas with name {blob_name} from bucket {bucket.name}." in out
+ storage_fileio_pandas.pandas_read(bucket.name, blob_name)
+ out, _ = capsys.readouterr()
+ assert f"Read csv with pandas with name {blob_name} from bucket {bucket.name}." in out
diff --git a/samples/snippets/hmac_samples_test.py b/samples/snippets/hmac_samples_test.py
new file mode 100644
index 000000000..60eba2401
--- /dev/null
+++ b/samples/snippets/hmac_samples_test.py
@@ -0,0 +1,121 @@
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Tests for hmac.py. Requires GOOGLE_CLOUD_PROJECT (valid project) and
+HMAC_KEY_TEST_SERVICE_ACCOUNT (valid service account email) env variables to be
+set in order to run.
+"""
+
+
+import os
+
+import google.api_core.exceptions
+from google.cloud import storage
+import pytest
+
+import storage_activate_hmac_key
+import storage_create_hmac_key
+import storage_deactivate_hmac_key
+import storage_delete_hmac_key
+import storage_get_hmac_key
+import storage_list_hmac_keys
+
+# We are reaching maximum number of HMAC keys on the service account.
+# We change the service account based on the value of
+# RUN_TESTS_SESSION in noxfile_config.py.
+# The reason we can not use multiple project is that our new projects
+# are enforced to have
+# 'constraints/iam.disableServiceAccountKeyCreation' policy.
+
+PROJECT_ID = os.environ["MAIN_GOOGLE_CLOUD_PROJECT"]
+SERVICE_ACCOUNT_EMAIL = os.environ["HMAC_KEY_TEST_SERVICE_ACCOUNT"]
+STORAGE_CLIENT = storage.Client(project=PROJECT_ID)
+
+
+@pytest.fixture(scope="module")
+def new_hmac_key():
+ """
+ Fixture to create a new HMAC key, and to guarantee all keys are deleted at
+ the end of the module.
+
+ NOTE: Due to the module scope, test order in this file is significant
+ """
+ hmac_key, secret = STORAGE_CLIENT.create_hmac_key(
+ service_account_email=SERVICE_ACCOUNT_EMAIL, project_id=PROJECT_ID
+ )
+ yield hmac_key
+ # Re-fetch the key metadata in case state has changed during the test.
+ hmac_key = STORAGE_CLIENT.get_hmac_key_metadata(
+ hmac_key.access_id, project_id=PROJECT_ID
+ )
+ if hmac_key.state == "DELETED":
+ return
+ if not hmac_key.state == "INACTIVE":
+ hmac_key.state = "INACTIVE"
+ hmac_key.update()
+ hmac_key.delete()
+
+
+def test_list_keys(capsys, new_hmac_key):
+ hmac_keys = storage_list_hmac_keys.list_keys(PROJECT_ID)
+ assert "HMAC Keys:" in capsys.readouterr().out
+ assert hmac_keys.num_results >= 1
+
+
+def test_create_key(capsys):
+ hmac_key = storage_create_hmac_key.create_key(
+ PROJECT_ID, SERVICE_ACCOUNT_EMAIL
+ )
+ hmac_key.state = "INACTIVE"
+ hmac_key.update()
+ hmac_key.delete()
+ assert "Key ID:" in capsys.readouterr().out
+ assert hmac_key.access_id
+
+
+def test_get_key(capsys, new_hmac_key):
+ hmac_key = storage_get_hmac_key.get_key(new_hmac_key.access_id, PROJECT_ID)
+ assert "HMAC key metadata" in capsys.readouterr().out
+ assert hmac_key.access_id == new_hmac_key.access_id
+
+
+def test_activate_key(capsys, new_hmac_key):
+ new_hmac_key.state = "INACTIVE"
+ new_hmac_key.update()
+ hmac_key = storage_activate_hmac_key.activate_key(
+ new_hmac_key.access_id, PROJECT_ID
+ )
+ assert "State: ACTIVE" in capsys.readouterr().out
+ assert hmac_key.state == "ACTIVE"
+
+
+def test_deactivate_key(capsys, new_hmac_key):
+ hmac_key = storage_deactivate_hmac_key.deactivate_key(
+ new_hmac_key.access_id, PROJECT_ID
+ )
+ assert "State: INACTIVE" in capsys.readouterr().out
+ assert hmac_key.state == "INACTIVE"
+
+
+def test_delete_key(capsys, new_hmac_key):
+ # Due to reuse of the HMAC key for each test function, the previous
+ # test has deactivated the key already.
+ try:
+ new_hmac_key.state = "INACTIVE"
+ new_hmac_key.update()
+ except google.api_core.exceptions.BadRequest:
+ pass
+
+ storage_delete_hmac_key.delete_key(new_hmac_key.access_id, PROJECT_ID)
+ assert "The key is deleted" in capsys.readouterr().out
diff --git a/samples/snippets/iam_test.py b/samples/snippets/iam_test.py
new file mode 100644
index 000000000..edeb8427d
--- /dev/null
+++ b/samples/snippets/iam_test.py
@@ -0,0 +1,149 @@
+# Copyright 2017 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+import time
+import uuid
+
+from google.cloud import storage
+import pytest
+
+import storage_add_bucket_conditional_iam_binding
+import storage_add_bucket_iam_member
+import storage_remove_bucket_conditional_iam_binding
+import storage_remove_bucket_iam_member
+import storage_set_bucket_public_iam
+import storage_view_bucket_iam_members
+
+MEMBER = "group:dpebot@google.com"
+ROLE = "roles/storage.legacyBucketReader"
+
+CONDITION_TITLE = "match-prefix"
+CONDITION_DESCRIPTION = "Applies to objects matching a prefix"
+CONDITION_EXPRESSION = (
+ 'resource.name.startsWith("projects/_/buckets/bucket-name/objects/prefix-a-")'
+)
+
+
+@pytest.fixture(scope="module")
+def bucket():
+ bucket = None
+ while bucket is None or bucket.exists():
+ storage_client = storage.Client()
+ bucket_name = "test-iam-{}".format(uuid.uuid4())
+ bucket = storage_client.bucket(bucket_name)
+ bucket.iam_configuration.uniform_bucket_level_access_enabled = True
+ storage_client.create_bucket(bucket)
+ yield bucket
+ time.sleep(3)
+ bucket.delete(force=True)
+
+
+@pytest.fixture(scope="function")
+def public_bucket():
+ # The new projects don't allow to make a bucket available to public, so
+ # we need to use the old main project for now.
+ original_value = os.environ['GOOGLE_CLOUD_PROJECT']
+ os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
+ bucket = None
+ while bucket is None or bucket.exists():
+ storage_client = storage.Client()
+ bucket_name = "test-iam-{}".format(uuid.uuid4())
+ bucket = storage_client.bucket(bucket_name)
+ bucket.iam_configuration.uniform_bucket_level_access_enabled = True
+ storage_client.create_bucket(bucket)
+ yield bucket
+ time.sleep(3)
+ bucket.delete(force=True)
+ # Set the value back.
+ os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
+
+
+def test_view_bucket_iam_members(capsys, bucket):
+ storage_view_bucket_iam_members.view_bucket_iam_members(bucket.name)
+ assert re.match("Role: .*, Members: .*", capsys.readouterr().out)
+
+
+def test_add_bucket_iam_member(bucket):
+ storage_add_bucket_iam_member.add_bucket_iam_member(bucket.name, ROLE, MEMBER)
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+ assert any(
+ binding["role"] == ROLE and MEMBER in binding["members"]
+ for binding in policy.bindings
+ )
+
+
+def test_add_bucket_conditional_iam_binding(bucket):
+ storage_add_bucket_conditional_iam_binding.add_bucket_conditional_iam_binding(
+ bucket.name,
+ ROLE,
+ CONDITION_TITLE,
+ CONDITION_DESCRIPTION,
+ CONDITION_EXPRESSION,
+ {MEMBER},
+ )
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+ assert any(
+ binding["role"] == ROLE
+ and binding["members"] == {MEMBER}
+ and binding["condition"]
+ == {
+ "title": CONDITION_TITLE,
+ "description": CONDITION_DESCRIPTION,
+ "expression": CONDITION_EXPRESSION,
+ }
+ for binding in policy.bindings
+ )
+
+
+def test_remove_bucket_iam_member(public_bucket):
+ storage_remove_bucket_iam_member.remove_bucket_iam_member(
+ public_bucket.name, ROLE, MEMBER)
+
+ policy = public_bucket.get_iam_policy(requested_policy_version=3)
+ assert not any(
+ binding["role"] == ROLE and MEMBER in binding["members"]
+ for binding in policy.bindings
+ )
+
+
+def test_remove_bucket_conditional_iam_binding(bucket):
+ storage_remove_bucket_conditional_iam_binding.remove_bucket_conditional_iam_binding(
+ bucket.name, ROLE, CONDITION_TITLE, CONDITION_DESCRIPTION, CONDITION_EXPRESSION
+ )
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+ condition = {
+ "title": CONDITION_TITLE,
+ "description": CONDITION_DESCRIPTION,
+ "expression": CONDITION_EXPRESSION,
+ }
+ assert not any(
+ (binding["role"] == ROLE and binding.get("condition") == condition)
+ for binding in policy.bindings
+ )
+
+
+def test_set_bucket_public_iam(public_bucket):
+ # The test project has org policy restricting identities by domain.
+ # Testing "domain:google.com" instead of "allUsers"
+ storage_set_bucket_public_iam.set_bucket_public_iam(public_bucket.name, ["domain:google.com"])
+ policy = public_bucket.get_iam_policy(requested_policy_version=3)
+
+ assert any(
+ binding["role"] == "roles/storage.objectViewer"
+ and "domain:google.com" in binding["members"]
+ for binding in policy.bindings
+ )
diff --git a/samples/snippets/notification_polling.py b/samples/snippets/notification_polling.py
new file mode 100644
index 000000000..3182db6da
--- /dev/null
+++ b/samples/snippets/notification_polling.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+
+# Copyright 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This application demonstrates how to poll for GCS notifications from a
+Cloud Pub/Sub subscription, parse the incoming message, and acknowledge the
+successful processing of the message.
+
+This application will work with any subscription configured for pull rather
+than push notifications. If you do not already have notifications configured,
+you may consult the docs at
+https://cloud.google.com/storage/docs/reporting-changes or follow the steps
+below:
+
+1. First, follow the common setup steps for these snippets, specically
+ configuring auth and installing dependencies. See the README's "Setup"
+ section.
+
+2. Activate the Google Cloud Pub/Sub API, if you have not already done so.
+ https://console.cloud.google.com/flows/enableapi?apiid=pubsub
+
+3. Create a Google Cloud Storage bucket:
+ $ gsutil mb gs://testbucket
+
+4. Create a Cloud Pub/Sub topic and publish bucket notifications there:
+ $ gsutil notification create -f json -t testtopic gs://testbucket
+
+5. Create a subscription for your new topic:
+ $ gcloud beta pubsub subscriptions create testsubscription --topic=testtopic
+
+6. Run this program:
+ $ python notification_polling.py my-project-id testsubscription
+
+7. While the program is running, upload and delete some files in the testbucket
+ bucket (you could use the console or gsutil) and watch as changes scroll by
+ in the app.
+"""
+
+import argparse
+import json
+import time
+
+from google.cloud import pubsub_v1
+
+
+def summarize(message):
+ data = message.data.decode("utf-8")
+ attributes = message.attributes
+
+ event_type = attributes["eventType"]
+ bucket_id = attributes["bucketId"]
+ object_id = attributes["objectId"]
+ generation = attributes["objectGeneration"]
+ description = (
+ "\tEvent type: {event_type}\n"
+ "\tBucket ID: {bucket_id}\n"
+ "\tObject ID: {object_id}\n"
+ "\tGeneration: {generation}\n"
+ ).format(
+ event_type=event_type,
+ bucket_id=bucket_id,
+ object_id=object_id,
+ generation=generation,
+ )
+
+ if "overwroteGeneration" in attributes:
+ description += "\tOverwrote generation: %s\n" % (
+ attributes["overwroteGeneration"]
+ )
+ if "overwrittenByGeneration" in attributes:
+ description += "\tOverwritten by generation: %s\n" % (
+ attributes["overwrittenByGeneration"]
+ )
+
+ payload_format = attributes["payloadFormat"]
+ if payload_format == "JSON_API_V1":
+ object_metadata = json.loads(data)
+ size = object_metadata["size"]
+ content_type = object_metadata["contentType"]
+ metageneration = object_metadata["metageneration"]
+ description += (
+ "\tContent type: {content_type}\n"
+ "\tSize: {object_size}\n"
+ "\tMetageneration: {metageneration}\n"
+ ).format(
+ content_type=content_type,
+ object_size=size,
+ metageneration=metageneration,
+ )
+ return description
+
+
+def poll_notifications(project, subscription_name):
+ """Polls a Cloud Pub/Sub subscription for new GCS events for display."""
+ subscriber = pubsub_v1.SubscriberClient()
+ subscription_path = subscriber.subscription_path(
+ project, subscription_name
+ )
+
+ def callback(message):
+ print("Received message:\n{}".format(summarize(message)))
+ message.ack()
+
+ subscriber.subscribe(subscription_path, callback=callback)
+
+ # The subscriber is non-blocking, so we must keep the main thread from
+ # exiting to allow it to process messages in the background.
+ print("Listening for messages on {}".format(subscription_path))
+ while True:
+ time.sleep(60)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+ parser.add_argument(
+ "project", help="The ID of the project that owns the subscription"
+ )
+ parser.add_argument(
+ "subscription", help="The ID of the Pub/Sub subscription"
+ )
+ args = parser.parse_args()
+ poll_notifications(args.project, args.subscription)
diff --git a/samples/snippets/notification_polling_test.py b/samples/snippets/notification_polling_test.py
new file mode 100644
index 000000000..dfb241b84
--- /dev/null
+++ b/samples/snippets/notification_polling_test.py
@@ -0,0 +1,55 @@
+# Copyright 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from google.cloud.pubsub_v1.subscriber.message import Message
+import mock
+
+from notification_polling import summarize
+
+
+MESSAGE_ID = 12345
+
+
+def test_parse_json_message():
+ attributes = {
+ "eventType": "OBJECT_FINALIZE",
+ "bucketId": "mybucket",
+ "objectId": "myobject",
+ "objectGeneration": 1234567,
+ "resource": "projects/_/buckets/mybucket/objects/myobject#1234567",
+ "notificationConfig": (
+ "projects/_/buckets/mybucket/" "notificationConfigs/5"
+ ),
+ "payloadFormat": "JSON_API_V1",
+ }
+ data = (
+ b"{"
+ b' "size": 12345,'
+ b' "contentType": "text/html",'
+ b' "metageneration": 1'
+ b"}"
+ )
+ message = Message(
+ mock.Mock(data=data, attributes=attributes, publish_time=mock.Mock(seconds=0.0, nanos=0.0)), MESSAGE_ID, delivery_attempt=0, request_queue=mock.Mock()
+ )
+ assert summarize(message) == (
+ "\tEvent type: OBJECT_FINALIZE\n"
+ "\tBucket ID: mybucket\n"
+ "\tObject ID: myobject\n"
+ "\tGeneration: 1234567\n"
+ "\tContent type: text/html\n"
+ "\tSize: 12345\n"
+ "\tMetageneration: 1\n"
+ )
diff --git a/samples/snippets/notification_test.py b/samples/snippets/notification_test.py
new file mode 100644
index 000000000..13553c844
--- /dev/null
+++ b/samples/snippets/notification_test.py
@@ -0,0 +1,120 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import uuid
+
+from google.api_core.exceptions import NotFound
+from google.cloud import storage
+
+import pytest
+
+import storage_create_bucket_notifications
+import storage_delete_bucket_notification
+import storage_list_bucket_notifications
+import storage_print_pubsub_bucket_notification
+
+_topic_name = f"notification-{uuid.uuid4()}"
+
+
+@pytest.fixture(scope="module")
+def storage_client():
+ return storage.Client()
+
+
+@pytest.fixture(scope="module")
+def publisher_client():
+ try:
+ from google.cloud.pubsub_v1 import PublisherClient
+ except ImportError:
+ pytest.skip("Cannot import pubsub")
+
+ return PublisherClient()
+
+
+@pytest.fixture(scope="module")
+def _notification_topic(storage_client, publisher_client):
+ topic_path = publisher_client.topic_path(storage_client.project, _topic_name)
+ try:
+ topic = publisher_client.get_topic(request={"topic": topic_path})
+ except NotFound:
+ topic = publisher_client.create_topic(request={"name": topic_path})
+
+ policy = publisher_client.get_iam_policy(request={"resource": topic_path})
+ binding = policy.bindings.add()
+ binding.role = "roles/pubsub.publisher"
+ binding.members.append(
+ "serviceAccount:{}".format(storage_client.get_service_account_email())
+ )
+ publisher_client.set_iam_policy(request={"resource": topic_path, "policy": policy})
+
+ yield topic
+
+ try:
+ publisher_client.delete_topic(request={"topic": topic.name})
+ except NotFound:
+ pass
+
+
+@pytest.fixture(scope="module")
+def bucket_w_notification(storage_client, _notification_topic):
+ """Yields a bucket with notification that is deleted after the tests complete."""
+ bucket = None
+ while bucket is None or bucket.exists():
+ bucket_name = f"notification-test-{uuid.uuid4()}"
+ bucket = storage_client.bucket(bucket_name)
+ bucket.create()
+
+ notification = bucket.notification(topic_name=_topic_name)
+ notification.create()
+
+ yield bucket
+
+ bucket.delete(force=True)
+
+
+def test_list_bucket_notifications(bucket_w_notification, capsys):
+ storage_list_bucket_notifications.list_bucket_notifications(bucket_w_notification.name)
+ out, _ = capsys.readouterr()
+ assert "Notification ID" in out
+
+
+def test_print_pubsub_bucket_notification(bucket_w_notification, capsys):
+ notification_id = 1
+ storage_print_pubsub_bucket_notification.print_pubsub_bucket_notification(bucket_w_notification.name, notification_id)
+ out, _ = capsys.readouterr()
+ assert "Notification ID: 1" in out
+
+
+def test_create_bucket_notifications(bucket_w_notification, capsys):
+ # test only bucket notification ID 1 was created in the fixture
+ assert bucket_w_notification.notification(notification_id=1).exists() is True
+ assert bucket_w_notification.notification(notification_id=2).exists() is False
+
+ storage_create_bucket_notifications.create_bucket_notifications(bucket_w_notification.name, _topic_name)
+ out, _ = capsys.readouterr()
+ assert "Successfully created notification" in out
+ # test succesfully creates new bucket notification with ID 2
+ assert bucket_w_notification.notification(notification_id=2).exists() is True
+
+
+def test_delete_bucket_notification(bucket_w_notification, capsys):
+ # test bucket notification ID 1 was created in the fixture
+ notification_id = 1
+ assert bucket_w_notification.notification(notification_id=notification_id).exists() is True
+
+ storage_delete_bucket_notification.delete_bucket_notification(bucket_w_notification.name, notification_id)
+ out, _ = capsys.readouterr()
+ assert "Successfully deleted notification" in out
+ assert bucket_w_notification.notification(notification_id=notification_id).exists() is False
diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py
new file mode 100644
index 000000000..93a9122cc
--- /dev/null
+++ b/samples/snippets/noxfile.py
@@ -0,0 +1,270 @@
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+
+import os
+from pathlib import Path
+import sys
+from typing import Callable, Dict, List, Optional
+
+import nox
+
+
+# WARNING - WARNING - WARNING - WARNING - WARNING
+# WARNING - WARNING - WARNING - WARNING - WARNING
+# DO NOT EDIT THIS FILE EVER!
+# WARNING - WARNING - WARNING - WARNING - WARNING
+# WARNING - WARNING - WARNING - WARNING - WARNING
+
+BLACK_VERSION = "black==19.10b0"
+
+# Copy `noxfile_config.py` to your directory and modify it instead.
+
+# `TEST_CONFIG` dict is a configuration hook that allows users to
+# modify the test configurations. The values here should be in sync
+# with `noxfile_config.py`. Users will copy `noxfile_config.py` into
+# their directory and modify it.
+
+TEST_CONFIG = {
+ # You can opt out from the test for specific Python versions.
+ "ignored_versions": [],
+ # Old samples are opted out of enforcing Python type hints
+ # All new samples should feature them
+ "enforce_type_hints": False,
+ # An envvar key for determining the project id to use. Change it
+ # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
+ # build specific Cloud project. You can also use your own string
+ # to use your own Cloud project.
+ "gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
+ # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
+ # If you need to use a specific version of pip,
+ # change pip_version_override to the string representation
+ # of the version number, for example, "20.2.4"
+ "pip_version_override": None,
+ # A dictionary you want to inject into your test. Don't put any
+ # secrets here. These values will override predefined values.
+ "envs": {},
+}
+
+
+try:
+ # Ensure we can import noxfile_config in the project's directory.
+ sys.path.append(".")
+ from noxfile_config import TEST_CONFIG_OVERRIDE
+except ImportError as e:
+ print("No user noxfile_config found: detail: {}".format(e))
+ TEST_CONFIG_OVERRIDE = {}
+
+# Update the TEST_CONFIG with the user supplied values.
+TEST_CONFIG.update(TEST_CONFIG_OVERRIDE)
+
+
+def get_pytest_env_vars() -> Dict[str, str]:
+ """Returns a dict for pytest invocation."""
+ ret = {}
+
+ # Override the GCLOUD_PROJECT and the alias.
+ env_key = TEST_CONFIG["gcloud_project_env"]
+ # This should error out if not set.
+ ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key]
+
+ # Apply user supplied envs.
+ ret.update(TEST_CONFIG["envs"])
+ return ret
+
+
+# DO NOT EDIT - automatically generated.
+# All versions used to test samples.
+ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"]
+
+# Any default versions that should be ignored.
+IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"]
+
+TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS])
+
+INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in (
+ "True",
+ "true",
+)
+
+# Error if a python version is missing
+nox.options.error_on_missing_interpreters = True
+
+#
+# Style Checks
+#
+
+
+def _determine_local_import_names(start_dir: str) -> List[str]:
+ """Determines all import names that should be considered "local".
+
+ This is used when running the linter to insure that import order is
+ properly checked.
+ """
+ file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)]
+ return [
+ basename
+ for basename, extension in file_ext_pairs
+ if extension == ".py"
+ or os.path.isdir(os.path.join(start_dir, basename))
+ and basename not in ("__pycache__")
+ ]
+
+
+# Linting with flake8.
+#
+# We ignore the following rules:
+# E203: whitespace before ‘:’
+# E266: too many leading ‘#’ for block comment
+# E501: line too long
+# I202: Additional newline in a section of imports
+#
+# We also need to specify the rules which are ignored by default:
+# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121']
+FLAKE8_COMMON_ARGS = [
+ "--show-source",
+ "--builtin=gettext",
+ "--max-complexity=20",
+ "--import-order-style=google",
+ "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py",
+ "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202",
+ "--max-line-length=88",
+]
+
+
+@nox.session
+def lint(session: nox.sessions.Session) -> None:
+ if not TEST_CONFIG["enforce_type_hints"]:
+ session.install("flake8", "flake8-import-order")
+ else:
+ session.install("flake8", "flake8-import-order", "flake8-annotations")
+
+ local_names = _determine_local_import_names(".")
+ args = FLAKE8_COMMON_ARGS + [
+ "--application-import-names",
+ ",".join(local_names),
+ ".",
+ ]
+ session.run("flake8", *args)
+
+
+#
+# Black
+#
+
+
+@nox.session
+def blacken(session: nox.sessions.Session) -> None:
+ session.install(BLACK_VERSION)
+ python_files = [path for path in os.listdir(".") if path.endswith(".py")]
+
+ session.run("black", *python_files)
+
+
+#
+# Sample Tests
+#
+
+
+PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"]
+
+
+def _session_tests(
+ session: nox.sessions.Session, post_install: Callable = None
+) -> None:
+ if TEST_CONFIG["pip_version_override"]:
+ pip_version = TEST_CONFIG["pip_version_override"]
+ session.install(f"pip=={pip_version}")
+ """Runs py.test for a particular project."""
+ if os.path.exists("requirements.txt"):
+ if os.path.exists("constraints.txt"):
+ session.install("-r", "requirements.txt", "-c", "constraints.txt")
+ else:
+ session.install("-r", "requirements.txt")
+
+ if os.path.exists("requirements-test.txt"):
+ if os.path.exists("constraints-test.txt"):
+ session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt")
+ else:
+ session.install("-r", "requirements-test.txt")
+
+ if INSTALL_LIBRARY_FROM_SOURCE:
+ session.install("-e", _get_repo_root())
+
+ if post_install:
+ post_install(session)
+
+ session.run(
+ "pytest",
+ *(PYTEST_COMMON_ARGS + session.posargs),
+ # Pytest will return 5 when no tests are collected. This can happen
+ # on travis where slow and flaky tests are excluded.
+ # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html
+ success_codes=[0, 5],
+ env=get_pytest_env_vars(),
+ )
+
+
+@nox.session(python=ALL_VERSIONS)
+def py(session: nox.sessions.Session) -> None:
+ """Runs py.test for a sample using the specified version of Python."""
+ if session.python in TESTED_VERSIONS:
+ _session_tests(session)
+ else:
+ session.skip(
+ "SKIPPED: {} tests are disabled for this sample.".format(session.python)
+ )
+
+
+#
+# Readmegen
+#
+
+
+def _get_repo_root() -> Optional[str]:
+ """ Returns the root folder of the project. """
+ # Get root of this repository. Assume we don't have directories nested deeper than 10 items.
+ p = Path(os.getcwd())
+ for i in range(10):
+ if p is None:
+ break
+ if Path(p / ".git").exists():
+ return str(p)
+ # .git is not available in repos cloned via Cloud Build
+ # setup.py is always in the library's root, so use that instead
+ # https://github.com/googleapis/synthtool/issues/792
+ if Path(p / "setup.py").exists():
+ return str(p)
+ p = p.parent
+ raise Exception("Unable to detect repository root.")
+
+
+GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")])
+
+
+@nox.session
+@nox.parametrize("path", GENERATED_READMES)
+def readmegen(session: nox.sessions.Session, path: str) -> None:
+ """(Re-)generates the readme for a sample."""
+ session.install("jinja2", "pyyaml")
+ dir_ = os.path.dirname(path)
+
+ if os.path.exists(os.path.join(dir_, "requirements.txt")):
+ session.install("-r", os.path.join(dir_, "requirements.txt"))
+
+ in_file = os.path.join(dir_, "README.rst.in")
+ session.run(
+ "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file
+ )
diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py
new file mode 100644
index 000000000..463da97de
--- /dev/null
+++ b/samples/snippets/noxfile_config.py
@@ -0,0 +1,96 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Default TEST_CONFIG_OVERRIDE for python repos.
+
+# You can copy this file into your directory, then it will be imported from
+# the noxfile.py.
+
+# The source of truth:
+# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py
+
+import os
+
+
+# We are reaching maximum number of HMAC keys on the service account.
+# We change the service account based on the value of
+# RUN_TESTS_SESSION. The reason we can not use multiple project is
+# that our new projects are enforced to have
+# 'constraints/iam.disableServiceAccountKeyCreation' policy.
+def get_service_account_email():
+ session = os.environ.get('RUN_TESTS_SESSION')
+ if session == 'py-3.6':
+ return ('py36-storage-test@'
+ 'python-docs-samples-tests.iam.gserviceaccount.com')
+ if session == 'py-3.7':
+ return ('py37-storage-test@'
+ 'python-docs-samples-tests.iam.gserviceaccount.com')
+ if session == 'py-3.8':
+ return ('py38-storage-test@'
+ 'python-docs-samples-tests.iam.gserviceaccount.com')
+ if session == 'py-3.9':
+ return ('py39-storage-test@'
+ 'python-docs-samples-tests.iam.gserviceaccount.com')
+ if session == 'py-3.10':
+ return ('py310-storage-test@'
+ 'python-docs-samples-tests.iam.gserviceaccount.com')
+ return os.environ['HMAC_KEY_TEST_SERVICE_ACCOUNT']
+
+
+# We change the value of CLOUD_KMS_KEY based on the value of
+# RUN_TESTS_SESSION.
+def get_cloud_kms_key():
+ session = os.environ.get('RUN_TESTS_SESSION')
+ if session == 'py-3.6':
+ return ('projects/python-docs-samples-tests-py36/locations/us/'
+ 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
+ if session == 'py-3.7':
+ return ('projects/python-docs-samples-tests-py37/locations/us/'
+ 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
+ if session == 'py-3.8':
+ return ('projects/python-docs-samples-tests-py38/locations/us/'
+ 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
+ if session == 'py-3.9':
+ return ('projects/python-docs-samples-tests-py39/locations/us/'
+ 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
+ if session == 'py-3.10':
+ return ('projects/python-docs-samples-tests-310/locations/us/'
+ 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
+ return os.environ['CLOUD_KMS_KEY']
+
+
+TEST_CONFIG_OVERRIDE = {
+ # You can opt out from the test for specific Python versions.
+ 'ignored_versions': ["2.7"],
+
+ # An envvar key for determining the project id to use. Change it
+ # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
+ # build specific Cloud project. You can also use your own string
+ # to use your own Cloud project.
+ # 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT',
+ 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
+
+ # A dictionary you want to inject into your test. Don't put any
+ # secrets here. These values will override predefined values.
+ 'envs': {
+ 'HMAC_KEY_TEST_SERVICE_ACCOUNT': get_service_account_email(),
+ 'CLOUD_KMS_KEY': get_cloud_kms_key(),
+ # Some tests can not use multiple projects because of several reasons:
+ # 1. The new projects is enforced to have the
+ # 'constraints/iam.disableServiceAccountKeyCreation' policy.
+ # 2. The new projects buckets need to have universal permission model.
+ # For those tests, we'll use the original project.
+ 'MAIN_GOOGLE_CLOUD_PROJECT': 'python-docs-samples-tests'
+ },
+}
diff --git a/samples/snippets/public_access_prevention_test.py b/samples/snippets/public_access_prevention_test.py
new file mode 100644
index 000000000..40d3924b2
--- /dev/null
+++ b/samples/snippets/public_access_prevention_test.py
@@ -0,0 +1,50 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+import storage_get_public_access_prevention
+import storage_set_public_access_prevention_enforced
+import storage_set_public_access_prevention_inherited
+import storage_set_public_access_prevention_unspecified
+
+
+@pytest.mark.skip(reason="Inconsistent due to unspecified->inherited change")
+def test_get_public_access_prevention(bucket, capsys):
+ short_name = storage_get_public_access_prevention
+ short_name.get_public_access_prevention(bucket.name)
+ out, _ = capsys.readouterr()
+ assert f"Public access prevention is inherited for {bucket.name}." in out
+
+
+def test_set_public_access_prevention_enforced(bucket, capsys):
+ short_name = storage_set_public_access_prevention_enforced
+ short_name.set_public_access_prevention_enforced(bucket.name)
+ out, _ = capsys.readouterr()
+ assert f"Public access prevention is set to enforced for {bucket.name}." in out
+
+
+@pytest.mark.skip(reason="Inconsistent due to unspecified->inherited change")
+def test_set_public_access_prevention_unspecified(bucket, capsys):
+ short_name = storage_set_public_access_prevention_unspecified
+ short_name.set_public_access_prevention_unspecified(bucket.name)
+ out, _ = capsys.readouterr()
+ assert f"Public access prevention is 'unspecified' for {bucket.name}." in out
+
+
+def test_set_public_access_prevention_inherited(bucket, capsys):
+ short_name = storage_set_public_access_prevention_inherited
+ short_name.set_public_access_prevention_inherited(bucket.name)
+ out, _ = capsys.readouterr()
+ assert f"Public access prevention is 'inherited' for {bucket.name}." in out
diff --git a/samples/snippets/quickstart.py b/samples/snippets/quickstart.py
new file mode 100644
index 000000000..578e50753
--- /dev/null
+++ b/samples/snippets/quickstart.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def run_quickstart():
+ # [START storage_quickstart]
+ # Imports the Google Cloud client library
+ from google.cloud import storage
+
+ # Instantiates a client
+ storage_client = storage.Client()
+
+ # The name for the new bucket
+ bucket_name = "my-new-bucket"
+
+ # Creates the new bucket
+ bucket = storage_client.create_bucket(bucket_name)
+
+ print("Bucket {} created.".format(bucket.name))
+ # [END storage_quickstart]
+
+
+if __name__ == "__main__":
+ run_quickstart()
diff --git a/samples/snippets/quickstart_test.py b/samples/snippets/quickstart_test.py
new file mode 100644
index 000000000..f6e06ad93
--- /dev/null
+++ b/samples/snippets/quickstart_test.py
@@ -0,0 +1,28 @@
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import mock
+
+import quickstart
+
+
+@mock.patch("google.cloud.storage.client.Client.create_bucket")
+def test_quickstart(create_bucket_mock, capsys):
+ # Unlike other quickstart tests, this one mocks out the creation
+ # because buckets are expensive, globally-namespaced object.
+ create_bucket_mock.return_value = mock.sentinel.bucket
+
+ quickstart.run_quickstart()
+
+ create_bucket_mock.assert_called_with("my-new-bucket")
diff --git a/samples/snippets/requester_pays_test.py b/samples/snippets/requester_pays_test.py
new file mode 100644
index 000000000..9a178edb0
--- /dev/null
+++ b/samples/snippets/requester_pays_test.py
@@ -0,0 +1,67 @@
+# Copyright 2017 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import tempfile
+
+from google.cloud import storage
+import pytest
+
+import storage_disable_requester_pays
+import storage_download_file_requester_pays
+import storage_enable_requester_pays
+import storage_get_requester_pays_status
+
+
+# We use a different bucket from other tests.
+# The service account for the test needs to have Billing Project Manager role
+# in order to make changes on buckets with requester pays enabled.
+BUCKET = os.environ["REQUESTER_PAYS_TEST_BUCKET"]
+PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"]
+
+
+def test_enable_requester_pays(capsys):
+ storage_enable_requester_pays.enable_requester_pays(BUCKET)
+ out, _ = capsys.readouterr()
+ assert "Requester Pays has been enabled for {}".format(BUCKET) in out
+
+
+def test_disable_requester_pays(capsys):
+ storage_disable_requester_pays.disable_requester_pays(BUCKET)
+ out, _ = capsys.readouterr()
+ assert "Requester Pays has been disabled for {}".format(BUCKET) in out
+
+
+def test_get_requester_pays_status(capsys):
+ storage_get_requester_pays_status.get_requester_pays_status(BUCKET)
+ out, _ = capsys.readouterr()
+ assert "Requester Pays is disabled for {}".format(BUCKET) in out
+
+
+@pytest.fixture
+def test_blob():
+ """Provides a pre-existing blob in the test bucket."""
+ bucket = storage.Client().bucket(BUCKET)
+ blob = bucket.blob("storage_snippets_test_sigil")
+ blob.upload_from_string("Hello, is it me you're looking for?")
+ return blob
+
+
+def test_download_file_requester_pays(test_blob, capsys):
+ with tempfile.NamedTemporaryFile() as dest_file:
+ storage_download_file_requester_pays.download_file_requester_pays(
+ BUCKET, PROJECT, test_blob.name, dest_file.name
+ )
+
+ assert dest_file.read()
diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt
new file mode 100644
index 000000000..0a7557580
--- /dev/null
+++ b/samples/snippets/requirements-test.txt
@@ -0,0 +1,3 @@
+pytest==6.2.5
+mock==4.0.3
+backoff==1.11.1
\ No newline at end of file
diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt
new file mode 100644
index 000000000..addda1960
--- /dev/null
+++ b/samples/snippets/requirements.txt
@@ -0,0 +1,4 @@
+google-cloud-pubsub==2.9.0
+google-cloud-storage==1.42.3
+pandas==1.3.4; python_version > '3.6'
+pandas==1.1.5; python_version < '3.7'
diff --git a/samples/snippets/snippets_test.py b/samples/snippets/snippets_test.py
new file mode 100644
index 000000000..dd8e6aeaf
--- /dev/null
+++ b/samples/snippets/snippets_test.py
@@ -0,0 +1,511 @@
+# Copyright 2016 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import tempfile
+import time
+import uuid
+
+from google.cloud import storage
+import google.cloud.exceptions
+import pytest
+import requests
+
+import storage_add_bucket_label
+import storage_bucket_delete_default_kms_key
+import storage_change_default_storage_class
+import storage_change_file_storage_class
+import storage_compose_file
+import storage_configure_retries
+import storage_copy_file
+import storage_copy_file_archived_generation
+import storage_cors_configuration
+import storage_create_bucket_class_location
+import storage_define_bucket_website_configuration
+import storage_delete_file
+import storage_delete_file_archived_generation
+import storage_disable_bucket_lifecycle_management
+import storage_disable_versioning
+import storage_download_file
+import storage_download_public_file
+import storage_enable_bucket_lifecycle_management
+import storage_enable_versioning
+import storage_generate_signed_post_policy_v4
+import storage_generate_signed_url_v2
+import storage_generate_signed_url_v4
+import storage_generate_upload_signed_url_v4
+import storage_get_bucket_labels
+import storage_get_bucket_metadata
+import storage_get_metadata
+import storage_get_service_account
+import storage_list_buckets
+import storage_list_file_archived_generations
+import storage_list_files
+import storage_list_files_with_prefix
+import storage_make_public
+import storage_move_file
+import storage_object_get_kms_key
+import storage_remove_bucket_label
+import storage_remove_cors_configuration
+import storage_rename_file
+import storage_set_bucket_default_kms_key
+import storage_set_metadata
+import storage_upload_file
+import storage_upload_with_kms_key
+
+KMS_KEY = os.environ["CLOUD_KMS_KEY"]
+
+
+def test_enable_default_kms_key(test_bucket):
+ storage_set_bucket_default_kms_key.enable_default_kms_key(
+ bucket_name=test_bucket.name, kms_key_name=KMS_KEY
+ )
+ time.sleep(2) # Let change propagate as needed
+ bucket = storage.Client().get_bucket(test_bucket.name)
+ assert bucket.default_kms_key_name.startswith(KMS_KEY)
+ bucket.default_kms_key_name = None
+ bucket.patch()
+
+
+def test_get_bucket_labels(test_bucket):
+ storage_get_bucket_labels.get_bucket_labels(test_bucket.name)
+
+
+def test_add_bucket_label(test_bucket, capsys):
+ storage_add_bucket_label.add_bucket_label(test_bucket.name)
+ out, _ = capsys.readouterr()
+ assert "example" in out
+
+
+def test_remove_bucket_label(test_bucket, capsys):
+ storage_add_bucket_label.add_bucket_label(test_bucket.name)
+ storage_remove_bucket_label.remove_bucket_label(test_bucket.name)
+ out, _ = capsys.readouterr()
+ assert "Removed labels" in out
+
+
+@pytest.fixture(scope="module")
+def test_bucket():
+ """Yields a bucket that is deleted after the test completes."""
+ bucket = None
+ while bucket is None or bucket.exists():
+ bucket_name = "storage-snippets-test-{}".format(uuid.uuid4())
+ bucket = storage.Client().bucket(bucket_name)
+ bucket.create()
+ yield bucket
+ bucket.delete(force=True)
+
+
+@pytest.fixture(scope="function")
+def test_public_bucket():
+ # The new projects don't allow to make a bucket available to public, so
+ # for some tests we need to use the old main project for now.
+ original_value = os.environ['GOOGLE_CLOUD_PROJECT']
+ os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
+ bucket = None
+ while bucket is None or bucket.exists():
+ storage_client = storage.Client()
+ bucket_name = "storage-snippets-test-{}".format(uuid.uuid4())
+ bucket = storage_client.bucket(bucket_name)
+ storage_client.create_bucket(bucket)
+ yield bucket
+ bucket.delete(force=True)
+ # Set the value back.
+ os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
+
+
+@pytest.fixture
+def test_blob(test_bucket):
+ """Yields a blob that is deleted after the test completes."""
+ bucket = test_bucket
+ blob = bucket.blob("storage_snippets_test_sigil-{}".format(uuid.uuid4()))
+ blob.upload_from_string("Hello, is it me you're looking for?")
+ yield blob
+
+
+@pytest.fixture(scope="function")
+def test_public_blob(test_public_bucket):
+ """Yields a blob that is deleted after the test completes."""
+ bucket = test_public_bucket
+ blob = bucket.blob("storage_snippets_test_sigil-{}".format(uuid.uuid4()))
+ blob.upload_from_string("Hello, is it me you're looking for?")
+ yield blob
+
+
+@pytest.fixture
+def test_bucket_create():
+ """Yields a bucket object that is deleted after the test completes."""
+ bucket = None
+ while bucket is None or bucket.exists():
+ bucket_name = "storage-snippets-test-{}".format(uuid.uuid4())
+ bucket = storage.Client().bucket(bucket_name)
+ yield bucket
+ bucket.delete(force=True)
+
+
+def test_list_buckets(test_bucket, capsys):
+ storage_list_buckets.list_buckets()
+ out, _ = capsys.readouterr()
+ assert test_bucket.name in out
+
+
+def test_list_blobs(test_blob, capsys):
+ storage_list_files.list_blobs(test_blob.bucket.name)
+ out, _ = capsys.readouterr()
+ assert test_blob.name in out
+
+
+def test_bucket_metadata(test_bucket, capsys):
+ storage_get_bucket_metadata.bucket_metadata(test_bucket.name)
+ out, _ = capsys.readouterr()
+ assert test_bucket.name in out
+
+
+def test_list_blobs_with_prefix(test_blob, capsys):
+ storage_list_files_with_prefix.list_blobs_with_prefix(
+ test_blob.bucket.name, prefix="storage_snippets"
+ )
+ out, _ = capsys.readouterr()
+ assert test_blob.name in out
+
+
+def test_upload_blob(test_bucket):
+ with tempfile.NamedTemporaryFile() as source_file:
+ source_file.write(b"test")
+
+ storage_upload_file.upload_blob(
+ test_bucket.name, source_file.name, "test_upload_blob"
+ )
+
+
+def test_upload_blob_with_kms(test_bucket):
+ with tempfile.NamedTemporaryFile() as source_file:
+ source_file.write(b"test")
+ storage_upload_with_kms_key.upload_blob_with_kms(
+ test_bucket.name, source_file.name, "test_upload_blob_encrypted", KMS_KEY
+ )
+ bucket = storage.Client().bucket(test_bucket.name)
+ kms_blob = bucket.get_blob("test_upload_blob_encrypted")
+ assert kms_blob.kms_key_name.startswith(KMS_KEY)
+
+
+def test_download_blob(test_blob):
+ with tempfile.NamedTemporaryFile() as dest_file:
+ storage_download_file.download_blob(
+ test_blob.bucket.name, test_blob.name, dest_file.name
+ )
+
+ assert dest_file.read()
+
+
+def test_blob_metadata(test_blob, capsys):
+ storage_get_metadata.blob_metadata(test_blob.bucket.name, test_blob.name)
+ out, _ = capsys.readouterr()
+ assert test_blob.name in out
+
+
+def test_set_blob_metadata(test_blob, capsys):
+ storage_set_metadata.set_blob_metadata(test_blob.bucket.name, test_blob.name)
+ out, _ = capsys.readouterr()
+ assert test_blob.name in out
+
+
+def test_delete_blob(test_blob):
+ storage_delete_file.delete_blob(test_blob.bucket.name, test_blob.name)
+
+
+def test_make_blob_public(test_public_blob):
+ storage_make_public.make_blob_public(
+ test_public_blob.bucket.name, test_public_blob.name)
+
+ r = requests.get(test_public_blob.public_url)
+ assert r.text == "Hello, is it me you're looking for?"
+
+
+def test_generate_signed_url(test_blob, capsys):
+ url = storage_generate_signed_url_v2.generate_signed_url(
+ test_blob.bucket.name, test_blob.name
+ )
+
+ r = requests.get(url)
+ assert r.text == "Hello, is it me you're looking for?"
+
+
+def test_generate_download_signed_url_v4(test_blob, capsys):
+ url = storage_generate_signed_url_v4.generate_download_signed_url_v4(
+ test_blob.bucket.name, test_blob.name
+ )
+
+ r = requests.get(url)
+ assert r.text == "Hello, is it me you're looking for?"
+
+
+def test_generate_upload_signed_url_v4(test_bucket, capsys):
+ blob_name = "storage_snippets_test_upload"
+ content = b"Uploaded via v4 signed url"
+ url = storage_generate_upload_signed_url_v4.generate_upload_signed_url_v4(
+ test_bucket.name, blob_name
+ )
+
+ requests.put(
+ url, data=content, headers={"content-type": "application/octet-stream"},
+ )
+
+ bucket = storage.Client().bucket(test_bucket.name)
+ blob = bucket.blob(blob_name)
+ assert blob.download_as_string() == content
+
+
+def test_generate_signed_policy_v4(test_bucket, capsys):
+ blob_name = "storage_snippets_test_form"
+ short_name = storage_generate_signed_post_policy_v4
+ form = short_name.generate_signed_post_policy_v4(test_bucket.name, blob_name)
+ assert "name='key' value='{}'".format(blob_name) in form
+ assert "name='x-goog-signature'" in form
+ assert "name='x-goog-date'" in form
+ assert "name='x-goog-credential'" in form
+ assert "name='x-goog-algorithm' value='GOOG4-RSA-SHA256'" in form
+ assert "name='policy'" in form
+ assert "name='x-goog-meta-test' value='data'" in form
+ assert "type='file' name='file'/>" in form
+
+
+def test_rename_blob(test_blob):
+ bucket = storage.Client().bucket(test_blob.bucket.name)
+
+ try:
+ bucket.delete_blob("test_rename_blob")
+ except google.cloud.exceptions.exceptions.NotFound:
+ print("test_rename_blob not found in bucket {}".format(bucket.name))
+
+ storage_rename_file.rename_blob(bucket.name, test_blob.name, "test_rename_blob")
+
+ assert bucket.get_blob("test_rename_blob") is not None
+ assert bucket.get_blob(test_blob.name) is None
+
+
+def test_move_blob(test_bucket_create, test_blob):
+ bucket = test_blob.bucket
+ storage.Client().create_bucket(test_bucket_create)
+
+ try:
+ test_bucket_create.delete_blob("test_move_blob")
+ except google.cloud.exceptions.NotFound:
+ print("test_move_blob not found in bucket {}".format(test_bucket_create.name))
+
+ storage_move_file.move_blob(
+ bucket.name, test_blob.name, test_bucket_create.name, "test_move_blob"
+ )
+
+ assert test_bucket_create.get_blob("test_move_blob") is not None
+ assert bucket.get_blob(test_blob.name) is None
+
+
+def test_copy_blob(test_blob):
+ bucket = storage.Client().bucket(test_blob.bucket.name)
+
+ try:
+ bucket.delete_blob("test_copy_blob")
+ except google.cloud.exceptions.NotFound:
+ pass
+
+ storage_copy_file.copy_blob(
+ bucket.name, test_blob.name, bucket.name, "test_copy_blob"
+ )
+
+ assert bucket.get_blob("test_copy_blob") is not None
+ assert bucket.get_blob(test_blob.name) is not None
+
+
+def test_versioning(test_bucket, capsys):
+ bucket = storage_enable_versioning.enable_versioning(test_bucket)
+ out, _ = capsys.readouterr()
+ assert "Versioning was enabled for bucket" in out
+ assert bucket.versioning_enabled is True
+
+ bucket = storage_disable_versioning.disable_versioning(test_bucket)
+ out, _ = capsys.readouterr()
+ assert "Versioning was disabled for bucket" in out
+ assert bucket.versioning_enabled is False
+
+
+def test_bucket_lifecycle_management(test_bucket, capsys):
+ bucket = storage_enable_bucket_lifecycle_management.enable_bucket_lifecycle_management(
+ test_bucket
+ )
+ out, _ = capsys.readouterr()
+ assert "[]" in out
+ assert "Lifecycle management is enable" in out
+ assert len(list(bucket.lifecycle_rules)) > 0
+
+ bucket = storage_disable_bucket_lifecycle_management.disable_bucket_lifecycle_management(
+ test_bucket
+ )
+ out, _ = capsys.readouterr()
+ assert "[]" in out
+ assert len(list(bucket.lifecycle_rules)) == 0
+
+
+def test_create_bucket_class_location(test_bucket_create):
+ bucket = storage_create_bucket_class_location.create_bucket_class_location(
+ test_bucket_create.name
+ )
+
+ assert bucket.location == "US"
+ assert bucket.storage_class == "COLDLINE"
+
+
+def test_bucket_delete_default_kms_key(test_bucket, capsys):
+ test_bucket.default_kms_key_name = KMS_KEY
+ test_bucket.patch()
+
+ assert test_bucket.default_kms_key_name == KMS_KEY
+
+ bucket = storage_bucket_delete_default_kms_key.bucket_delete_default_kms_key(
+ test_bucket.name
+ )
+
+ out, _ = capsys.readouterr()
+ assert bucket.default_kms_key_name is None
+ assert bucket.name in out
+
+
+def test_get_service_account(capsys):
+ storage_get_service_account.get_service_account()
+
+ out, _ = capsys.readouterr()
+
+ assert "@gs-project-accounts.iam.gserviceaccount.com" in out
+
+
+def test_download_public_file(test_public_blob):
+ storage_make_public.make_blob_public(
+ test_public_blob.bucket.name, test_public_blob.name)
+ with tempfile.NamedTemporaryFile() as dest_file:
+ storage_download_public_file.download_public_file(
+ test_public_blob.bucket.name, test_public_blob.name, dest_file.name
+ )
+
+ assert dest_file.read() == b"Hello, is it me you're looking for?"
+
+
+def test_define_bucket_website_configuration(test_bucket):
+ bucket = storage_define_bucket_website_configuration.define_bucket_website_configuration(
+ test_bucket.name, "index.html", "404.html"
+ )
+
+ website_val = {"mainPageSuffix": "index.html", "notFoundPage": "404.html"}
+
+ assert bucket._properties["website"] == website_val
+
+
+def test_object_get_kms_key(test_bucket):
+ with tempfile.NamedTemporaryFile() as source_file:
+ storage_upload_with_kms_key.upload_blob_with_kms(
+ test_bucket.name, source_file.name, "test_upload_blob_encrypted", KMS_KEY
+ )
+ kms_key = storage_object_get_kms_key.object_get_kms_key(
+ test_bucket.name, "test_upload_blob_encrypted"
+ )
+
+ assert kms_key.startswith(KMS_KEY)
+
+
+def test_storage_compose_file(test_bucket):
+ source_files = ["test_upload_blob_1", "test_upload_blob_2"]
+ 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
+ )
+ composed = destination.download_as_string()
+
+ assert composed.decode("utf-8") == source_files[0] + source_files[1]
+
+
+def test_cors_configuration(test_bucket, capsys):
+ bucket = storage_cors_configuration.cors_configuration(test_bucket)
+ out, _ = capsys.readouterr()
+ assert "Set CORS policies for bucket" in out
+ assert len(bucket.cors) > 0
+
+ bucket = storage_remove_cors_configuration.remove_cors_configuration(test_bucket)
+ out, _ = capsys.readouterr()
+ assert "Remove CORS policies for bucket" in out
+ assert len(bucket.cors) == 0
+
+
+def test_delete_blobs_archived_generation(test_blob, capsys):
+ storage_delete_file_archived_generation.delete_file_archived_generation(
+ test_blob.bucket.name, test_blob.name, test_blob.generation
+ )
+ out, _ = capsys.readouterr()
+ assert "blob " + test_blob.name + " was deleted" in out
+ blob = test_blob.bucket.get_blob(test_blob.name, generation=test_blob.generation)
+ assert blob is None
+
+
+def test_change_default_storage_class(test_bucket, capsys):
+ bucket = storage_change_default_storage_class.change_default_storage_class(
+ test_bucket
+ )
+ out, _ = capsys.readouterr()
+ assert "Default storage class for bucket" in out
+ assert bucket.storage_class == 'COLDLINE'
+
+
+def test_change_file_storage_class(test_blob, capsys):
+ blob = storage_change_file_storage_class.change_file_storage_class(
+ test_blob.bucket.name, test_blob.name
+ )
+ out, _ = capsys.readouterr()
+ assert "Blob {} in bucket {}". format(blob.name, blob.bucket.name) in out
+ assert blob.storage_class == 'NEARLINE'
+
+
+def test_copy_file_archived_generation(test_blob):
+ bucket = storage.Client().bucket(test_blob.bucket.name)
+
+ try:
+ bucket.delete_blob("test_copy_blob")
+ except google.cloud.exceptions.NotFound:
+ pass
+
+ storage_copy_file_archived_generation.copy_file_archived_generation(
+ bucket.name, test_blob.name, bucket.name, "test_copy_blob", test_blob.generation
+ )
+
+ assert bucket.get_blob("test_copy_blob") is not None
+ assert bucket.get_blob(test_blob.name) is not None
+
+
+def test_list_blobs_archived_generation(test_blob, capsys):
+ storage_list_file_archived_generations.list_file_archived_generations(
+ test_blob.bucket.name
+ )
+ out, _ = capsys.readouterr()
+ assert str(test_blob.generation) in out
+
+
+def test_storage_configure_retries(test_blob, capsys):
+ storage_configure_retries.configure_retries(test_blob.bucket.name, test_blob.name)
+
+ # This simply checks if the retry configurations were set and printed as intended.
+ out, _ = capsys.readouterr()
+ assert "The following library method is customized to be retried" in out
+ assert "_should_retry" in out
+ assert "initial=1.5, maximum=45.0, multiplier=1.2, deadline=500.0" in out
diff --git a/samples/snippets/storage_activate_hmac_key.py b/samples/snippets/storage_activate_hmac_key.py
new file mode 100644
index 000000000..e77cd8066
--- /dev/null
+++ b/samples/snippets/storage_activate_hmac_key.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_activate_hmac_key]
+from google.cloud import storage
+
+
+def activate_key(access_id, project_id):
+ """
+ Activate the HMAC key with the given access ID.
+ """
+ # project_id = "Your Google Cloud project ID"
+ # access_id = "ID of an inactive HMAC key"
+
+ storage_client = storage.Client(project=project_id)
+
+ hmac_key = storage_client.get_hmac_key_metadata(
+ access_id, project_id=project_id
+ )
+ hmac_key.state = "ACTIVE"
+ hmac_key.update()
+
+ print("The HMAC key metadata is:")
+ print("Service Account Email: {}".format(hmac_key.service_account_email))
+ print("Key ID: {}".format(hmac_key.id))
+ print("Access ID: {}".format(hmac_key.access_id))
+ print("Project ID: {}".format(hmac_key.project))
+ print("State: {}".format(hmac_key.state))
+ print("Created At: {}".format(hmac_key.time_created))
+ print("Updated At: {}".format(hmac_key.updated))
+ print("Etag: {}".format(hmac_key.etag))
+ return hmac_key
+
+
+# [END storage_activate_hmac_key]
+
+if __name__ == "__main__":
+ activate_key(access_id=sys.argv[1], project_id=sys.argv[2])
diff --git a/samples/snippets/storage_add_bucket_conditional_iam_binding.py b/samples/snippets/storage_add_bucket_conditional_iam_binding.py
new file mode 100644
index 000000000..ddc0fc028
--- /dev/null
+++ b/samples/snippets/storage_add_bucket_conditional_iam_binding.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_add_bucket_conditional_iam_binding]
+from google.cloud import storage
+
+
+def add_bucket_conditional_iam_binding(
+ bucket_name, role, title, description, expression, members
+):
+ """Add a conditional IAM binding to a bucket's IAM policy."""
+ # bucket_name = "your-bucket-name"
+ # role = "IAM role, e.g. roles/storage.objectViewer"
+ # members = {"IAM identity, e.g. user: name@example.com}"
+ # title = "Condition title."
+ # description = "Condition description."
+ # expression = "Condition expression."
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+
+ # Set the policy's version to 3 to use condition in bindings.
+ policy.version = 3
+
+ policy.bindings.append(
+ {
+ "role": role,
+ "members": members,
+ "condition": {
+ "title": title,
+ "description": description,
+ "expression": expression,
+ },
+ }
+ )
+
+ bucket.set_iam_policy(policy)
+
+ print("Added the following member(s) with role {} to {}:".format(role, bucket_name))
+
+ for member in members:
+ print(" {}".format(member))
+
+ print("with condition:")
+ print(" Title: {}".format(title))
+ print(" Description: {}".format(description))
+ print(" Expression: {}".format(expression))
+
+
+# [END storage_add_bucket_conditional_iam_binding]
+
+
+if __name__ == "__main__":
+ add_bucket_conditional_iam_binding(
+ bucket_name=sys.argv[1],
+ role=sys.argv[2],
+ title=sys.argv[3],
+ description=sys.argv[4],
+ expression=sys.argv[5],
+ members=set(sys.argv[6::]),
+ )
diff --git a/samples/snippets/storage_add_bucket_default_owner.py b/samples/snippets/storage_add_bucket_default_owner.py
new file mode 100644
index 000000000..932b1328f
--- /dev/null
+++ b/samples/snippets/storage_add_bucket_default_owner.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_add_bucket_default_owner]
+from google.cloud import storage
+
+
+def add_bucket_default_owner(bucket_name, user_email):
+ """Adds a user as an owner in the given bucket's default object access
+ control list."""
+ # bucket_name = "your-bucket-name"
+ # user_email = "name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ bucket.acl.reload()
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # grant access to different types of entities. You can also use
+ # `grant_read` or `grant_write` to grant different roles.
+ bucket.default_object_acl.user(user_email).grant_owner()
+ bucket.default_object_acl.save()
+
+ print(
+ "Added user {} as an owner in the default acl on bucket {}.".format(
+ user_email, bucket_name
+ )
+ )
+
+
+# [END storage_add_bucket_default_owner]
+
+if __name__ == "__main__":
+ add_bucket_default_owner(bucket_name=sys.argv[1], user_email=sys.argv[2])
diff --git a/samples/snippets/storage_add_bucket_iam_member.py b/samples/snippets/storage_add_bucket_iam_member.py
new file mode 100644
index 000000000..727f18483
--- /dev/null
+++ b/samples/snippets/storage_add_bucket_iam_member.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_add_bucket_iam_member]
+from google.cloud import storage
+
+
+def add_bucket_iam_member(bucket_name, role, member):
+ """Add a new member to an IAM Policy"""
+ # bucket_name = "your-bucket-name"
+ # role = "IAM role, e.g., roles/storage.objectViewer"
+ # member = "IAM identity, e.g., user: name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+
+ policy.bindings.append({"role": role, "members": {member}})
+
+ bucket.set_iam_policy(policy)
+
+ print("Added {} with role {} to {}.".format(member, role, bucket_name))
+
+
+# [END storage_add_bucket_iam_member]
+
+
+if __name__ == "__main__":
+ add_bucket_iam_member(bucket_name=sys.argv[1], role=sys.argv[2], member=sys.argv[3])
diff --git a/samples/snippets/storage_add_bucket_label.py b/samples/snippets/storage_add_bucket_label.py
new file mode 100644
index 000000000..8ae8fe1f4
--- /dev/null
+++ b/samples/snippets/storage_add_bucket_label.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_add_bucket_label]
+import pprint
+# [END storage_add_bucket_label]
+import sys
+# [START storage_add_bucket_label]
+
+from google.cloud import storage
+
+
+def add_bucket_label(bucket_name):
+ """Add a label to a bucket."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ labels = bucket.labels
+ labels["example"] = "label"
+ bucket.labels = labels
+ bucket.patch()
+
+ print("Updated labels on {}.".format(bucket.name))
+ pprint.pprint(bucket.labels)
+
+
+# [END storage_add_bucket_label]
+
+if __name__ == "__main__":
+ add_bucket_label(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_add_bucket_owner.py b/samples/snippets/storage_add_bucket_owner.py
new file mode 100644
index 000000000..acdb60dc5
--- /dev/null
+++ b/samples/snippets/storage_add_bucket_owner.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_add_bucket_owner]
+from google.cloud import storage
+
+
+def add_bucket_owner(bucket_name, user_email):
+ """Adds a user as an owner on the given bucket."""
+ # bucket_name = "your-bucket-name"
+ # user_email = "name@example.com"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ bucket.acl.reload()
+
+ # You can also use `group()`, `domain()`, `all_authenticated()` and `all()`
+ # to grant access to different types of entities.
+ # You can also use `grant_read()` or `grant_write()` to grant different
+ # roles.
+ bucket.acl.user(user_email).grant_owner()
+ bucket.acl.save()
+
+ print(
+ "Added user {} as an owner on bucket {}.".format(
+ user_email, bucket_name
+ )
+ )
+
+
+# [END storage_add_bucket_owner]
+
+if __name__ == "__main__":
+ add_bucket_owner(bucket_name=sys.argv[1], user_email=sys.argv[2])
diff --git a/samples/snippets/storage_add_file_owner.py b/samples/snippets/storage_add_file_owner.py
new file mode 100644
index 000000000..9e9342590
--- /dev/null
+++ b/samples/snippets/storage_add_file_owner.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_add_file_owner]
+from google.cloud import storage
+
+
+def add_blob_owner(bucket_name, blob_name, user_email):
+ """Adds a user as an owner on the given blob."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+ # user_email = "name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ blob.acl.reload()
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # grant access to different types of entities. You can also use
+ # `grant_read` or `grant_write` to grant different roles.
+ blob.acl.user(user_email).grant_owner()
+ blob.acl.save()
+
+ print(
+ "Added user {} as an owner on blob {} in bucket {}.".format(
+ user_email, blob_name, bucket_name
+ )
+ )
+
+
+# [END storage_add_file_owner]
+
+if __name__ == "__main__":
+ add_blob_owner(
+ bucket_name=sys.argv[1], blob_name=sys.argv[2], user_email=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_bucket_delete_default_kms_key.py b/samples/snippets/storage_bucket_delete_default_kms_key.py
new file mode 100644
index 000000000..3df23767d
--- /dev/null
+++ b/samples/snippets/storage_bucket_delete_default_kms_key.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_bucket_delete_default_kms_key]
+from google.cloud import storage
+
+
+def bucket_delete_default_kms_key(bucket_name):
+ """Delete a default KMS key of bucket"""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.default_kms_key_name = None
+ bucket.patch()
+
+ print("Default KMS key was removed from {}".format(bucket.name))
+ return bucket
+
+
+# [END storage_bucket_delete_default_kms_key]
+
+if __name__ == "__main__":
+ bucket_delete_default_kms_key(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_change_default_storage_class.py b/samples/snippets/storage_change_default_storage_class.py
new file mode 100644
index 000000000..8a72719ba
--- /dev/null
+++ b/samples/snippets/storage_change_default_storage_class.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_change_default_storage_class]
+from google.cloud import storage
+from google.cloud.storage import constants
+
+
+def change_default_storage_class(bucket_name):
+ """Change the default storage class of the bucket"""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.storage_class = constants.COLDLINE_STORAGE_CLASS
+ bucket.patch()
+
+ print("Default storage class for bucket {} has been set to {}".format(bucket_name, bucket.storage_class))
+ return bucket
+
+
+# [END storage_change_default_storage_class]
+
+if __name__ == "__main__":
+ change_default_storage_class(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_change_file_storage_class.py b/samples/snippets/storage_change_file_storage_class.py
new file mode 100644
index 000000000..d5dda56a7
--- /dev/null
+++ b/samples/snippets/storage_change_file_storage_class.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_change_file_storage_class]
+from google.cloud import storage
+
+
+def change_file_storage_class(bucket_name, blob_name):
+ """Change the default storage class of the blob"""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ blob = bucket.get_blob(blob_name)
+ blob.update_storage_class("NEARLINE")
+
+ print(
+ "Blob {} in bucket {} had its storage class set to {}".format(
+ blob_name,
+ bucket_name,
+ blob.storage_class
+ )
+ )
+ return blob
+# [END storage_change_file_storage_class]
+
+
+if __name__ == "__main__":
+ change_file_storage_class(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_compose_file.py b/samples/snippets/storage_compose_file.py
new file mode 100644
index 000000000..2c1443f22
--- /dev/null
+++ b/samples/snippets/storage_compose_file.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_compose_file]
+from google.cloud import storage
+
+
+def compose_file(bucket_name, first_blob_name, second_blob_name, destination_blob_name):
+ """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"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ destination = bucket.blob(destination_blob_name)
+ destination.content_type = "text/plain"
+
+ # sources is a list of Blob instances, up to the max of 32 instances per request
+ sources = [bucket.get_blob(first_blob_name), bucket.get_blob(second_blob_name)]
+ destination.compose(sources)
+
+ 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
+
+
+# [END storage_compose_file]
+
+if __name__ == "__main__":
+ compose_file(
+ bucket_name=sys.argv[1],
+ first_blob_name=sys.argv[2],
+ second_blob_name=sys.argv[3],
+ destination_blob_name=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_configure_retries.py b/samples/snippets/storage_configure_retries.py
new file mode 100644
index 000000000..9543111b3
--- /dev/null
+++ b/samples/snippets/storage_configure_retries.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that configures retries on an operation call.
+This sample is used on this page:
+ https://cloud.google.com/storage/docs/retry-strategy
+For more information, see README.md.
+"""
+
+# [START storage_configure_retries]
+from google.cloud import storage
+from google.cloud.storage.retry import DEFAULT_RETRY
+
+
+def configure_retries(bucket_name, blob_name):
+ """Configures retries with customizations."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The ID of your GCS object
+ # blob_name = "your-object-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ # Customize retry with a deadline of 500 seconds (default=120 seconds).
+ modified_retry = DEFAULT_RETRY.with_deadline(500.0)
+ # Customize retry with an initial wait time of 1.5 (default=1.0).
+ # Customize retry with a wait time multiplier per iteration of 1.2 (default=2.0).
+ # Customize retry with a maximum wait time of 45.0 (default=60.0).
+ modified_retry = modified_retry.with_delay(initial=1.5, multiplier=1.2, maximum=45.0)
+
+ # blob.delete() uses DEFAULT_RETRY_IF_GENERATION_SPECIFIED by default.
+ # Override with modified_retry so the function retries even if the generation
+ # number is not specified.
+ print(
+ f"The following library method is customized to be retried according to the following configurations: {modified_retry}"
+ )
+
+ blob.delete(retry=modified_retry)
+ print("Blob {} deleted with a customized retry strategy.".format(blob_name))
+
+
+# [END storage_configure_retries]
+
+
+if __name__ == "__main__":
+ configure_retries(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_copy_file.py b/samples/snippets/storage_copy_file.py
new file mode 100644
index 000000000..5d36aa94b
--- /dev/null
+++ b/samples/snippets/storage_copy_file.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_copy_file]
+from google.cloud import storage
+
+
+def copy_blob(
+ bucket_name, blob_name, destination_bucket_name, destination_blob_name
+):
+ """Copies a blob from one bucket to another with a new name."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+ # destination_bucket_name = "destination-bucket-name"
+ # destination_blob_name = "destination-object-name"
+
+ storage_client = storage.Client()
+
+ source_bucket = storage_client.bucket(bucket_name)
+ source_blob = source_bucket.blob(blob_name)
+ destination_bucket = storage_client.bucket(destination_bucket_name)
+
+ blob_copy = source_bucket.copy_blob(
+ source_blob, destination_bucket, destination_blob_name
+ )
+
+ print(
+ "Blob {} in bucket {} copied to blob {} in bucket {}.".format(
+ source_blob.name,
+ source_bucket.name,
+ blob_copy.name,
+ destination_bucket.name,
+ )
+ )
+
+
+# [END storage_copy_file]
+
+if __name__ == "__main__":
+ copy_blob(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2],
+ destination_bucket_name=sys.argv[3],
+ destination_blob_name=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_copy_file_archived_generation.py b/samples/snippets/storage_copy_file_archived_generation.py
new file mode 100644
index 000000000..988ebcbeb
--- /dev/null
+++ b/samples/snippets/storage_copy_file_archived_generation.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_copy_file_archived_generation]
+from google.cloud import storage
+
+
+def copy_file_archived_generation(
+ bucket_name, blob_name, destination_bucket_name, destination_blob_name, generation
+):
+ """Copies a blob from one bucket to another with a new name with the same generation."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+ # destination_bucket_name = "destination-bucket-name"
+ # destination_blob_name = "destination-object-name"
+ # generation = 1579287380533984
+
+ storage_client = storage.Client()
+
+ source_bucket = storage_client.bucket(bucket_name)
+ source_blob = source_bucket.blob(blob_name)
+ destination_bucket = storage_client.bucket(destination_bucket_name)
+
+ blob_copy = source_bucket.copy_blob(
+ source_blob, destination_bucket, destination_blob_name, source_generation=generation
+ )
+
+ print(
+ "Generation {} of the blob {} in bucket {} copied to blob {} in bucket {}.".format(
+ source_blob.generation,
+ source_blob.name,
+ source_bucket.name,
+ blob_copy.name,
+ destination_bucket.name,
+ )
+ )
+
+
+# [END storage_copy_file_archived_generation]
+
+if __name__ == "__main__":
+ copy_file_archived_generation(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2],
+ destination_bucket_name=sys.argv[3],
+ destination_blob_name=sys.argv[4],
+ generation=sys.argv[5]
+ )
diff --git a/samples/snippets/storage_cors_configuration.py b/samples/snippets/storage_cors_configuration.py
new file mode 100644
index 000000000..3d2595a9d
--- /dev/null
+++ b/samples/snippets/storage_cors_configuration.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_cors_configuration]
+from google.cloud import storage
+
+
+def cors_configuration(bucket_name):
+ """Set a bucket's CORS policies configuration."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.cors = [
+ {
+ "origin": ["*"],
+ "responseHeader": [
+ "Content-Type",
+ "x-goog-resumable"],
+ "method": ['PUT', 'POST'],
+ "maxAgeSeconds": 3600
+ }
+ ]
+ bucket.patch()
+
+ print("Set CORS policies for bucket {} is {}".format(bucket.name, bucket.cors))
+ return bucket
+
+
+# [END storage_cors_configuration]
+
+if __name__ == "__main__":
+ cors_configuration(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_create_bucket.py b/samples/snippets/storage_create_bucket.py
new file mode 100644
index 000000000..aaee9e234
--- /dev/null
+++ b/samples/snippets/storage_create_bucket.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_create_bucket]
+from google.cloud import storage
+
+
+def create_bucket(bucket_name):
+ """Creates a new bucket."""
+ # bucket_name = "your-new-bucket-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.create_bucket(bucket_name)
+
+ print("Bucket {} created".format(bucket.name))
+
+
+# [END storage_create_bucket]
+
+if __name__ == "__main__":
+ create_bucket(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_create_bucket_class_location.py b/samples/snippets/storage_create_bucket_class_location.py
new file mode 100644
index 000000000..64c2652d7
--- /dev/null
+++ b/samples/snippets/storage_create_bucket_class_location.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_create_bucket_class_location]
+from google.cloud import storage
+
+
+def create_bucket_class_location(bucket_name):
+ """Create a new bucket in specific location with storage class"""
+ # bucket_name = "your-new-bucket-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+ bucket.storage_class = "COLDLINE"
+ new_bucket = storage_client.create_bucket(bucket, location="us")
+
+ print(
+ "Created bucket {} in {} with storage class {}".format(
+ new_bucket.name, new_bucket.location, new_bucket.storage_class
+ )
+ )
+ return new_bucket
+
+
+# [END storage_create_bucket_class_location]
+
+if __name__ == "__main__":
+ create_bucket_class_location(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_create_bucket_notifications.py b/samples/snippets/storage_create_bucket_notifications.py
new file mode 100644
index 000000000..a6f218c36
--- /dev/null
+++ b/samples/snippets/storage_create_bucket_notifications.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that creates a notification configuration for a bucket.
+This sample is used on this page:
+ https://cloud.google.com/storage/docs/reporting-changes
+For more information, see README.md.
+"""
+
+# [START storage_create_bucket_notifications]
+from google.cloud import storage
+
+
+def create_bucket_notifications(bucket_name, topic_name):
+ """Creates a notification configuration for a bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The name of a topic
+ # topic_name = "your-topic-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ notification = bucket.notification(topic_name=topic_name)
+ notification.create()
+
+ print(f"Successfully created notification with ID {notification.notification_id} for bucket {bucket_name}")
+
+# [END storage_create_bucket_notifications]
+
+
+if __name__ == "__main__":
+ create_bucket_notifications(bucket_name=sys.argv[1], topic_name=sys.argv[2])
diff --git a/samples/snippets/storage_create_hmac_key.py b/samples/snippets/storage_create_hmac_key.py
new file mode 100644
index 000000000..27a418c39
--- /dev/null
+++ b/samples/snippets/storage_create_hmac_key.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_create_hmac_key]
+from google.cloud import storage
+
+
+def create_key(project_id, service_account_email):
+ """
+ Create a new HMAC key using the given project and service account.
+ """
+ # project_id = 'Your Google Cloud project ID'
+ # service_account_email = 'Service account used to generate the HMAC key'
+
+ storage_client = storage.Client(project=project_id)
+
+ hmac_key, secret = storage_client.create_hmac_key(
+ service_account_email=service_account_email, project_id=project_id
+ )
+
+ print("The base64 encoded secret is {}".format(secret))
+ print("Do not miss that secret, there is no API to recover it.")
+ print("The HMAC key metadata is:")
+ print("Service Account Email: {}".format(hmac_key.service_account_email))
+ print("Key ID: {}".format(hmac_key.id))
+ print("Access ID: {}".format(hmac_key.access_id))
+ print("Project ID: {}".format(hmac_key.project))
+ print("State: {}".format(hmac_key.state))
+ print("Created At: {}".format(hmac_key.time_created))
+ print("Updated At: {}".format(hmac_key.updated))
+ print("Etag: {}".format(hmac_key.etag))
+ return hmac_key
+
+
+# [END storage_create_hmac_key]
+
+if __name__ == "__main__":
+ create_key(project_id=sys.argv[1], service_account_email=sys.argv[2])
diff --git a/samples/snippets/storage_deactivate_hmac_key.py b/samples/snippets/storage_deactivate_hmac_key.py
new file mode 100644
index 000000000..389efb998
--- /dev/null
+++ b/samples/snippets/storage_deactivate_hmac_key.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_deactivate_hmac_key]
+from google.cloud import storage
+
+
+def deactivate_key(access_id, project_id):
+ """
+ Deactivate the HMAC key with the given access ID.
+ """
+ # project_id = "Your Google Cloud project ID"
+ # access_id = "ID of an active HMAC key"
+
+ storage_client = storage.Client(project=project_id)
+
+ hmac_key = storage_client.get_hmac_key_metadata(
+ access_id, project_id=project_id
+ )
+ hmac_key.state = "INACTIVE"
+ hmac_key.update()
+
+ print("The HMAC key is now inactive.")
+ print("The HMAC key metadata is:")
+ print("Service Account Email: {}".format(hmac_key.service_account_email))
+ print("Key ID: {}".format(hmac_key.id))
+ print("Access ID: {}".format(hmac_key.access_id))
+ print("Project ID: {}".format(hmac_key.project))
+ print("State: {}".format(hmac_key.state))
+ print("Created At: {}".format(hmac_key.time_created))
+ print("Updated At: {}".format(hmac_key.updated))
+ print("Etag: {}".format(hmac_key.etag))
+ return hmac_key
+
+
+# [END storage_deactivate_hmac_key]
+
+if __name__ == "__main__":
+ deactivate_key(access_id=sys.argv[1], project_id=sys.argv[2])
diff --git a/samples/snippets/storage_define_bucket_website_configuration.py b/samples/snippets/storage_define_bucket_website_configuration.py
new file mode 100644
index 000000000..ce6c7e66c
--- /dev/null
+++ b/samples/snippets/storage_define_bucket_website_configuration.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_define_bucket_website_configuration]
+from google.cloud import storage
+
+
+def define_bucket_website_configuration(bucket_name, main_page_suffix, not_found_page):
+ """Configure website-related properties of bucket"""
+ # bucket_name = "your-bucket-name"
+ # main_page_suffix = "index.html"
+ # not_found_page = "404.html"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.configure_website(main_page_suffix, not_found_page)
+ bucket.patch()
+
+ print(
+ "Static website bucket {} is set up to use {} as the index page and {} as the 404 page".format(
+ bucket.name, main_page_suffix, not_found_page
+ )
+ )
+ return bucket
+
+
+# [END storage_define_bucket_website_configuration]
+
+if __name__ == "__main__":
+ define_bucket_website_configuration(
+ bucket_name=sys.argv[1],
+ main_page_suffix=sys.argv[2],
+ not_found_page=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_delete_bucket.py b/samples/snippets/storage_delete_bucket.py
new file mode 100644
index 000000000..b3e264c74
--- /dev/null
+++ b/samples/snippets/storage_delete_bucket.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_delete_bucket]
+from google.cloud import storage
+
+
+def delete_bucket(bucket_name):
+ """Deletes a bucket. The bucket must be empty."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.delete()
+
+ print("Bucket {} deleted".format(bucket.name))
+
+
+# [END storage_delete_bucket]
+
+if __name__ == "__main__":
+ delete_bucket(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_delete_bucket_notification.py b/samples/snippets/storage_delete_bucket_notification.py
new file mode 100644
index 000000000..efd41771d
--- /dev/null
+++ b/samples/snippets/storage_delete_bucket_notification.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that deletes a notification configuration for a bucket.
+This sample is used on this page:
+ https://cloud.google.com/storage/docs/reporting-changes
+For more information, see README.md.
+"""
+
+# [START storage_delete_bucket_notification]
+from google.cloud import storage
+
+
+def delete_bucket_notification(bucket_name, notification_id):
+ """Deletes a notification configuration for a bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The ID of the notification
+ # notification_id = "your-notification-id"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ notification = bucket.notification(notification_id=notification_id)
+ notification.delete()
+
+ print(f"Successfully deleted notification with ID {notification_id} for bucket {bucket_name}")
+
+# [END storage_delete_bucket_notification]
+
+
+if __name__ == "__main__":
+ delete_bucket_notification(bucket_name=sys.argv[1], notification_id=sys.argv[2])
diff --git a/samples/snippets/storage_delete_file.py b/samples/snippets/storage_delete_file.py
new file mode 100644
index 000000000..1105f3725
--- /dev/null
+++ b/samples/snippets/storage_delete_file.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_delete_file]
+from google.cloud import storage
+
+
+def delete_blob(bucket_name, blob_name):
+ """Deletes a blob from the bucket."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+ blob.delete()
+
+ print("Blob {} deleted.".format(blob_name))
+
+
+# [END storage_delete_file]
+
+if __name__ == "__main__":
+ delete_blob(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_delete_file_archived_generation.py b/samples/snippets/storage_delete_file_archived_generation.py
new file mode 100644
index 000000000..4e4909001
--- /dev/null
+++ b/samples/snippets/storage_delete_file_archived_generation.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_delete_file_archived_generation]
+from google.cloud import storage
+
+
+def delete_file_archived_generation(bucket_name, blob_name, generation):
+ """Delete a blob in the bucket with the given generation."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+ # generation = 1579287380533984
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.delete_blob(blob_name, generation=generation)
+ print(
+ "Generation {} of blob {} was deleted from {}".format(
+ generation, blob_name, bucket_name
+ )
+ )
+
+
+# [END storage_delete_file_archived_generation]
+
+
+if __name__ == "__main__":
+ delete_file_archived_generation(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2],
+ generation=sys.argv[3]
+ )
diff --git a/samples/snippets/storage_delete_hmac_key.py b/samples/snippets/storage_delete_hmac_key.py
new file mode 100644
index 000000000..403dc193b
--- /dev/null
+++ b/samples/snippets/storage_delete_hmac_key.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_delete_hmac_key]
+from google.cloud import storage
+
+
+def delete_key(access_id, project_id):
+ """
+ Delete the HMAC key with the given access ID. Key must have state INACTIVE
+ in order to succeed.
+ """
+ # project_id = "Your Google Cloud project ID"
+ # access_id = "ID of an HMAC key (must be in INACTIVE state)"
+
+ storage_client = storage.Client(project=project_id)
+
+ hmac_key = storage_client.get_hmac_key_metadata(
+ access_id, project_id=project_id
+ )
+ hmac_key.delete()
+
+ print(
+ "The key is deleted, though it may still appear in list_hmac_keys()"
+ " results."
+ )
+
+
+# [END storage_delete_hmac_key]
+
+if __name__ == "__main__":
+ delete_key(access_id=sys.argv[1], project_id=sys.argv[2])
diff --git a/samples/snippets/storage_disable_bucket_lifecycle_management.py b/samples/snippets/storage_disable_bucket_lifecycle_management.py
new file mode 100644
index 000000000..9ef6971fb
--- /dev/null
+++ b/samples/snippets/storage_disable_bucket_lifecycle_management.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_disable_bucket_lifecycle_management]
+from google.cloud import storage
+
+
+def disable_bucket_lifecycle_management(bucket_name):
+ """Disable lifecycle management for a bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.clear_lifecyle_rules()
+ bucket.patch()
+ rules = bucket.lifecycle_rules
+
+ print("Lifecycle management is disable for bucket {} and the rules are {}".format(bucket_name, list(rules)))
+ return bucket
+
+
+# [END storage_disable_bucket_lifecycle_management]
+
+if __name__ == "__main__":
+ disable_bucket_lifecycle_management(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_disable_default_event_based_hold.py b/samples/snippets/storage_disable_default_event_based_hold.py
new file mode 100644
index 000000000..dff3ed3c1
--- /dev/null
+++ b/samples/snippets/storage_disable_default_event_based_hold.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_disable_default_event_based_hold]
+from google.cloud import storage
+
+
+def disable_default_event_based_hold(bucket_name):
+ """Disables the default event based hold on a given bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.default_event_based_hold = False
+ bucket.patch()
+
+ print("Default event based hold was disabled for {}".format(bucket_name))
+
+
+# [END storage_disable_default_event_based_hold]
+
+
+if __name__ == "__main__":
+ disable_default_event_based_hold(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_disable_requester_pays.py b/samples/snippets/storage_disable_requester_pays.py
new file mode 100644
index 000000000..c49cc28ea
--- /dev/null
+++ b/samples/snippets/storage_disable_requester_pays.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_disable_requester_pays]
+from google.cloud import storage
+
+
+def disable_requester_pays(bucket_name):
+ """Disable a bucket's requesterpays metadata"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.requester_pays = False
+ bucket.patch()
+
+ print("Requester Pays has been disabled for {}".format(bucket_name))
+
+
+# [END storage_disable_requester_pays]
+
+
+if __name__ == "__main__":
+ disable_requester_pays(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_disable_uniform_bucket_level_access.py b/samples/snippets/storage_disable_uniform_bucket_level_access.py
new file mode 100644
index 000000000..4f4691611
--- /dev/null
+++ b/samples/snippets/storage_disable_uniform_bucket_level_access.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_disable_uniform_bucket_level_access]
+from google.cloud import storage
+
+
+def disable_uniform_bucket_level_access(bucket_name):
+ """Disable uniform bucket-level access for a bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ bucket.iam_configuration.uniform_bucket_level_access_enabled = False
+ bucket.patch()
+
+ print(
+ "Uniform bucket-level access was disabled for {}.".format(bucket.name)
+ )
+
+
+# [END storage_disable_uniform_bucket_level_access]
+
+if __name__ == "__main__":
+ disable_uniform_bucket_level_access(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_disable_versioning.py b/samples/snippets/storage_disable_versioning.py
new file mode 100644
index 000000000..98832ba68
--- /dev/null
+++ b/samples/snippets/storage_disable_versioning.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_disable_versioning]
+from google.cloud import storage
+
+
+def disable_versioning(bucket_name):
+ """Disable versioning for this bucket."""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.versioning_enabled = False
+ bucket.patch()
+
+ print("Versioning was disabled for bucket {}".format(bucket))
+ return bucket
+
+
+# [END storage_disable_versioning]
+
+if __name__ == "__main__":
+ disable_versioning(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_download_encrypted_file.py b/samples/snippets/storage_download_encrypted_file.py
new file mode 100644
index 000000000..ac7071fbe
--- /dev/null
+++ b/samples/snippets/storage_download_encrypted_file.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# [START storage_download_encrypted_file]
+import base64
+# [END storage_download_encrypted_file]
+import sys
+# [START storage_download_encrypted_file]
+
+from google.cloud import storage
+
+
+def download_encrypted_blob(
+ bucket_name,
+ source_blob_name,
+ destination_file_name,
+ base64_encryption_key,
+):
+ """Downloads a previously-encrypted blob from Google Cloud Storage.
+
+ The encryption key provided must be the same key provided when uploading
+ the blob.
+ """
+ # bucket_name = "your-bucket-name"
+ # source_blob_name = "storage-object-name"
+ # destination_file_name = "local/path/to/file"
+ # base64_encryption_key = "base64-encoded-encryption-key"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+
+ # Encryption key must be an AES256 key represented as a bytestring with
+ # 32 bytes. Since it's passed in as a base64 encoded string, it needs
+ # to be decoded.
+ encryption_key = base64.b64decode(base64_encryption_key)
+ blob = bucket.blob(source_blob_name, encryption_key=encryption_key)
+
+ blob.download_to_filename(destination_file_name)
+
+ print(
+ "Blob {} downloaded to {}.".format(
+ source_blob_name, destination_file_name
+ )
+ )
+
+
+# [END storage_download_encrypted_file]
+
+if __name__ == "__main__":
+ download_encrypted_blob(
+ bucket_name=sys.argv[1],
+ source_blob_name=sys.argv[2],
+ destination_file_name=sys.argv[3],
+ base64_encryption_key=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_download_file.py b/samples/snippets/storage_download_file.py
new file mode 100644
index 000000000..f8a1c93c8
--- /dev/null
+++ b/samples/snippets/storage_download_file.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_download_file]
+from google.cloud import storage
+
+
+def download_blob(bucket_name, source_blob_name, destination_file_name):
+ """Downloads a blob from the bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+
+ # The ID of your GCS object
+ # source_blob_name = "storage-object-name"
+
+ # The path to which the file should be downloaded
+ # destination_file_name = "local/path/to/file"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+
+ # Construct a client side representation of a blob.
+ # Note `Bucket.blob` differs from `Bucket.get_blob` as it doesn't retrieve
+ # any content from Google Cloud Storage. As we don't need additional data,
+ # using `Bucket.blob` is preferred here.
+ blob = bucket.blob(source_blob_name)
+ blob.download_to_filename(destination_file_name)
+
+ print(
+ "Downloaded storage object {} from bucket {} to local file {}.".format(
+ source_blob_name, bucket_name, destination_file_name
+ )
+ )
+
+
+# [END storage_download_file]
+
+if __name__ == "__main__":
+ download_blob(
+ bucket_name=sys.argv[1],
+ source_blob_name=sys.argv[2],
+ destination_file_name=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_download_file_requester_pays.py b/samples/snippets/storage_download_file_requester_pays.py
new file mode 100644
index 000000000..babbafda7
--- /dev/null
+++ b/samples/snippets/storage_download_file_requester_pays.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_download_file_requester_pays]
+from google.cloud import storage
+
+
+def download_file_requester_pays(
+ bucket_name, project_id, source_blob_name, destination_file_name
+):
+ """Download file using specified project as the requester"""
+ # bucket_name = "your-bucket-name"
+ # project_id = "your-project-id"
+ # source_blob_name = "source-blob-name"
+ # destination_file_name = "local-destination-file-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name, user_project=project_id)
+ blob = bucket.blob(source_blob_name)
+ blob.download_to_filename(destination_file_name)
+
+ print(
+ "Blob {} downloaded to {} using a requester-pays request.".format(
+ source_blob_name, destination_file_name
+ )
+ )
+
+
+# [END storage_download_file_requester_pays]
+
+if __name__ == "__main__":
+ download_file_requester_pays(
+ bucket_name=sys.argv[1],
+ project_id=sys.argv[2],
+ source_blob_name=sys.argv[3],
+ destination_file_name=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_download_public_file.py b/samples/snippets/storage_download_public_file.py
new file mode 100644
index 000000000..8fbb68405
--- /dev/null
+++ b/samples/snippets/storage_download_public_file.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_download_public_file]
+from google.cloud import storage
+
+
+def download_public_file(bucket_name, source_blob_name, destination_file_name):
+ """Downloads a public blob from the bucket."""
+ # bucket_name = "your-bucket-name"
+ # source_blob_name = "storage-object-name"
+ # destination_file_name = "local/path/to/file"
+
+ storage_client = storage.Client.create_anonymous_client()
+
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(source_blob_name)
+ blob.download_to_filename(destination_file_name)
+
+ print(
+ "Downloaded public blob {} from bucket {} to {}.".format(
+ source_blob_name, bucket.name, destination_file_name
+ )
+ )
+
+
+# [END storage_download_public_file]
+
+if __name__ == "__main__":
+ download_public_file(
+ bucket_name=sys.argv[1],
+ source_blob_name=sys.argv[2],
+ destination_file_name=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_enable_bucket_lifecycle_management.py b/samples/snippets/storage_enable_bucket_lifecycle_management.py
new file mode 100644
index 000000000..61c7d7b20
--- /dev/null
+++ b/samples/snippets/storage_enable_bucket_lifecycle_management.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_enable_bucket_lifecycle_management]
+from google.cloud import storage
+
+
+def enable_bucket_lifecycle_management(bucket_name):
+ """Enable lifecycle management for a bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ rules = bucket.lifecycle_rules
+
+ print("Lifecycle management rules for bucket {} are {}".format(bucket_name, list(rules)))
+ bucket.add_lifecycle_delete_rule(age=2)
+ bucket.patch()
+
+ rules = bucket.lifecycle_rules
+ print("Lifecycle management is enable for bucket {} and the rules are {}".format(bucket_name, list(rules)))
+
+ return bucket
+
+
+# [END storage_enable_bucket_lifecycle_management]
+
+if __name__ == "__main__":
+ enable_bucket_lifecycle_management(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_enable_default_event_based_hold.py b/samples/snippets/storage_enable_default_event_based_hold.py
new file mode 100644
index 000000000..a535390c9
--- /dev/null
+++ b/samples/snippets/storage_enable_default_event_based_hold.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_enable_default_event_based_hold]
+from google.cloud import storage
+
+
+def enable_default_event_based_hold(bucket_name):
+ """Enables the default event based hold on a given bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+ bucket.default_event_based_hold = True
+ bucket.patch()
+
+ print("Default event based hold was enabled for {}".format(bucket_name))
+
+
+# [END storage_enable_default_event_based_hold]
+
+
+if __name__ == "__main__":
+ enable_default_event_based_hold(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_enable_requester_pays.py b/samples/snippets/storage_enable_requester_pays.py
new file mode 100644
index 000000000..9787008dd
--- /dev/null
+++ b/samples/snippets/storage_enable_requester_pays.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_enable_requester_pays]
+from google.cloud import storage
+
+
+def enable_requester_pays(bucket_name):
+ """Enable a bucket's requesterpays metadata"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.requester_pays = True
+ bucket.patch()
+
+ print("Requester Pays has been enabled for {}".format(bucket_name))
+
+
+# [END storage_enable_requester_pays]
+
+if __name__ == "__main__":
+ enable_requester_pays(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_enable_uniform_bucket_level_access.py b/samples/snippets/storage_enable_uniform_bucket_level_access.py
new file mode 100644
index 000000000..c689bb735
--- /dev/null
+++ b/samples/snippets/storage_enable_uniform_bucket_level_access.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_enable_uniform_bucket_level_access]
+from google.cloud import storage
+
+
+def enable_uniform_bucket_level_access(bucket_name):
+ """Enable uniform bucket-level access for a bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ bucket.iam_configuration.uniform_bucket_level_access_enabled = True
+ bucket.patch()
+
+ print(
+ "Uniform bucket-level access was enabled for {}.".format(bucket.name)
+ )
+
+
+# [END storage_enable_uniform_bucket_level_access]
+
+if __name__ == "__main__":
+ enable_uniform_bucket_level_access(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_enable_versioning.py b/samples/snippets/storage_enable_versioning.py
new file mode 100644
index 000000000..89693e426
--- /dev/null
+++ b/samples/snippets/storage_enable_versioning.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_enable_versioning]
+from google.cloud import storage
+
+
+def enable_versioning(bucket_name):
+ """Enable versioning for this bucket."""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.versioning_enabled = True
+ bucket.patch()
+
+ print("Versioning was enabled for bucket {}".format(bucket.name))
+ return bucket
+
+
+# [END storage_enable_versioning]
+
+if __name__ == "__main__":
+ enable_versioning(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_fileio_pandas.py b/samples/snippets/storage_fileio_pandas.py
new file mode 100644
index 000000000..d4d01edd7
--- /dev/null
+++ b/samples/snippets/storage_fileio_pandas.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that creates and consumes a GCS blob using pandas with file-like IO
+"""
+
+# [START storage_fileio_pandas_write]
+
+
+def pandas_write(bucket_name, blob_name):
+ """Use pandas to interact with GCS using file-like IO"""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+
+ # The ID of your new GCS object
+ # blob_name = "storage-object-name"
+
+ from google.cloud import storage
+ import pandas as pd
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ with blob.open("w") as f:
+ df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
+ f.write(df.to_csv(index=False))
+
+ print(f"Wrote csv with pandas with name {blob_name} from bucket {bucket.name}.")
+
+
+# [END storage_fileio_pandas_write]
+
+
+# [START storage_fileio_pandas_read]
+
+
+def pandas_read(bucket_name, blob_name):
+ """Use pandas to interact with GCS using file-like IO"""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+
+ # The ID of your new GCS object
+ # blob_name = "storage-object-name"
+
+ from google.cloud import storage
+ import pandas as pd
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ with blob.open("r") as f:
+ pd.read_csv(f)
+
+ print(f"Read csv with pandas with name {blob_name} from bucket {bucket.name}.")
+
+
+# [END storage_fileio_pandas_read]
+
+
+if __name__ == "__main__":
+ pandas_write(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2]
+ )
+
+ pandas_read(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2]
+ )
diff --git a/samples/snippets/storage_fileio_write_read.py b/samples/snippets/storage_fileio_write_read.py
new file mode 100644
index 000000000..5d35c84ab
--- /dev/null
+++ b/samples/snippets/storage_fileio_write_read.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that writes and read a blob in GCS using file-like IO
+"""
+
+# [START storage_fileio_write_read]
+from google.cloud import storage
+
+
+def write_read(bucket_name, blob_name):
+ """Write and read a blob from GCS using file-like IO"""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+
+ # The ID of your new GCS object
+ # blob_name = "storage-object-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ # Mode can be specified as wb/rb for bytes mode.
+ # See: https://docs.python.org/3/library/io.html
+ with blob.open("w") as f:
+ f.write("Hello world")
+
+ with blob.open("r") as f:
+ print(f.read())
+
+
+# [END storage_fileio_write_read]
+
+if __name__ == "__main__":
+ write_read(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2]
+ )
diff --git a/samples/snippets/storage_generate_encryption_key.py b/samples/snippets/storage_generate_encryption_key.py
new file mode 100644
index 000000000..a973418a6
--- /dev/null
+++ b/samples/snippets/storage_generate_encryption_key.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# [START storage_generate_encryption_key]
+import base64
+import os
+
+
+def generate_encryption_key():
+ """Generates a 256 bit (32 byte) AES encryption key and prints the
+ base64 representation.
+
+ This is included for demonstration purposes. You should generate your own
+ key. Please remember that encryption keys should be handled with a
+ comprehensive security policy.
+ """
+ key = os.urandom(32)
+ encoded_key = base64.b64encode(key).decode("utf-8")
+
+ print("Base 64 encoded encryption key: {}".format(encoded_key))
+
+
+# [END storage_generate_encryption_key]
+
+if __name__ == "__main__":
+ generate_encryption_key()
diff --git a/samples/snippets/storage_generate_signed_post_policy_v4.py b/samples/snippets/storage_generate_signed_post_policy_v4.py
new file mode 100644
index 000000000..8217714e2
--- /dev/null
+++ b/samples/snippets/storage_generate_signed_post_policy_v4.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_generate_signed_post_policy_v4]
+import datetime
+# [END storage_generate_signed_post_policy_v4]
+import sys
+# [START storage_generate_signed_post_policy_v4]
+
+from google.cloud import storage
+
+
+def generate_signed_post_policy_v4(bucket_name, blob_name):
+ """Generates a v4 POST Policy and prints an HTML form."""
+ # bucket_name = 'your-bucket-name'
+ # blob_name = 'your-object-name'
+
+ storage_client = storage.Client()
+
+ policy = storage_client.generate_signed_post_policy_v4(
+ bucket_name,
+ blob_name,
+ expiration=datetime.timedelta(minutes=10),
+ fields={
+ 'x-goog-meta-test': 'data'
+ }
+ )
+
+ # Create an HTML form with the provided policy
+ header = ""
+
+ print(form)
+
+ return form
+
+
+# [END storage_generate_signed_post_policy_v4]
+
+if __name__ == "__main__":
+ generate_signed_post_policy_v4(
+ bucket_name=sys.argv[1], blob_name=sys.argv[2]
+ )
diff --git a/samples/snippets/storage_generate_signed_url_v2.py b/samples/snippets/storage_generate_signed_url_v2.py
new file mode 100644
index 000000000..abea3dd54
--- /dev/null
+++ b/samples/snippets/storage_generate_signed_url_v2.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# [START storage_generate_signed_url_v2]
+import datetime
+# [END storage_generate_signed_url_v2]
+import sys
+# [START storage_generate_signed_url_v2]
+
+from google.cloud import storage
+
+
+def generate_signed_url(bucket_name, blob_name):
+ """Generates a v2 signed URL for downloading a blob.
+
+ Note that this method requires a service account key file. You can not use
+ this if you are using Application Default Credentials from Google Compute
+ Engine or from the Google Cloud SDK.
+ """
+ # bucket_name = 'your-bucket-name'
+ # blob_name = 'your-object-name'
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ url = blob.generate_signed_url(
+ # This URL is valid for 1 hour
+ expiration=datetime.timedelta(hours=1),
+ # Allow GET requests using this URL.
+ method="GET",
+ )
+
+ print("The signed url for {} is {}".format(blob.name, url))
+ return url
+
+
+# [END storage_generate_signed_url_v2]
+
+if __name__ == "__main__":
+ generate_signed_url(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_generate_signed_url_v4.py b/samples/snippets/storage_generate_signed_url_v4.py
new file mode 100644
index 000000000..2a45b23e9
--- /dev/null
+++ b/samples/snippets/storage_generate_signed_url_v4.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_generate_signed_url_v4]
+import datetime
+# [END storage_generate_signed_url_v4]
+import sys
+# [START storage_generate_signed_url_v4]
+
+from google.cloud import storage
+
+
+def generate_download_signed_url_v4(bucket_name, blob_name):
+ """Generates a v4 signed URL for downloading a blob.
+
+ Note that this method requires a service account key file. You can not use
+ this if you are using Application Default Credentials from Google Compute
+ Engine or from the Google Cloud SDK.
+ """
+ # bucket_name = 'your-bucket-name'
+ # blob_name = 'your-object-name'
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ url = blob.generate_signed_url(
+ version="v4",
+ # This URL is valid for 15 minutes
+ expiration=datetime.timedelta(minutes=15),
+ # Allow GET requests using this URL.
+ method="GET",
+ )
+
+ print("Generated GET signed URL:")
+ print(url)
+ print("You can use this URL with any user agent, for example:")
+ print("curl '{}'".format(url))
+ return url
+
+
+# [END storage_generate_signed_url_v4]
+
+if __name__ == "__main__":
+ generate_download_signed_url_v4(
+ bucket_name=sys.argv[1], blob_name=sys.argv[2]
+ )
diff --git a/samples/snippets/storage_generate_upload_signed_url_v4.py b/samples/snippets/storage_generate_upload_signed_url_v4.py
new file mode 100644
index 000000000..dc1da8864
--- /dev/null
+++ b/samples/snippets/storage_generate_upload_signed_url_v4.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_generate_upload_signed_url_v4]
+import datetime
+# [END storage_generate_upload_signed_url_v4]
+import sys
+# [START storage_generate_upload_signed_url_v4]
+
+from google.cloud import storage
+
+
+def generate_upload_signed_url_v4(bucket_name, blob_name):
+ """Generates a v4 signed URL for uploading a blob using HTTP PUT.
+
+ Note that this method requires a service account key file. You can not use
+ this if you are using Application Default Credentials from Google Compute
+ Engine or from the Google Cloud SDK.
+ """
+ # bucket_name = 'your-bucket-name'
+ # blob_name = 'your-object-name'
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ url = blob.generate_signed_url(
+ version="v4",
+ # This URL is valid for 15 minutes
+ expiration=datetime.timedelta(minutes=15),
+ # Allow PUT requests using this URL.
+ method="PUT",
+ content_type="application/octet-stream",
+ )
+
+ print("Generated PUT signed URL:")
+ print(url)
+ print("You can use this URL with any user agent, for example:")
+ print(
+ "curl -X PUT -H 'Content-Type: application/octet-stream' "
+ "--upload-file my-file '{}'".format(url)
+ )
+ return url
+
+
+# [END storage_generate_upload_signed_url_v4]
+
+
+if __name__ == "__main__":
+ generate_upload_signed_url_v4(
+ bucket_name=sys.argv[1], blob_name=sys.argv[2]
+ )
diff --git a/samples/snippets/storage_get_bucket_labels.py b/samples/snippets/storage_get_bucket_labels.py
new file mode 100644
index 000000000..b3bcd6208
--- /dev/null
+++ b/samples/snippets/storage_get_bucket_labels.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_get_bucket_labels]
+import pprint
+# [END storage_get_bucket_labels]
+import sys
+# [START storage_get_bucket_labels]
+
+from google.cloud import storage
+
+
+def get_bucket_labels(bucket_name):
+ """Prints out a bucket's labels."""
+ # bucket_name = 'your-bucket-name'
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+
+ labels = bucket.labels
+ pprint.pprint(labels)
+
+
+# [END storage_get_bucket_labels]
+
+if __name__ == "__main__":
+ get_bucket_labels(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_get_bucket_metadata.py b/samples/snippets/storage_get_bucket_metadata.py
new file mode 100644
index 000000000..87cd5eddc
--- /dev/null
+++ b/samples/snippets/storage_get_bucket_metadata.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import sys
+
+# [START storage_get_bucket_metadata]
+
+from google.cloud import storage
+
+
+def bucket_metadata(bucket_name):
+ """Prints out a bucket's metadata."""
+ # bucket_name = 'your-bucket-name'
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ print(f"ID: {bucket.id}")
+ print(f"Name: {bucket.name}")
+ print(f"Storage Class: {bucket.storage_class}")
+ print(f"Location: {bucket.location}")
+ print(f"Location Type: {bucket.location_type}")
+ print(f"Cors: {bucket.cors}")
+ print(f"Default Event Based Hold: {bucket.default_event_based_hold}")
+ print(f"Default KMS Key Name: {bucket.default_kms_key_name}")
+ print(f"Metageneration: {bucket.metageneration}")
+ print(
+ f"Public Access Prevention: {bucket.iam_configuration.public_access_prevention}"
+ )
+ print(f"Retention Effective Time: {bucket.retention_policy_effective_time}")
+ print(f"Retention Period: {bucket.retention_period}")
+ print(f"Retention Policy Locked: {bucket.retention_policy_locked}")
+ print(f"Requester Pays: {bucket.requester_pays}")
+ print(f"Self Link: {bucket.self_link}")
+ print(f"Time Created: {bucket.time_created}")
+ print(f"Versioning Enabled: {bucket.versioning_enabled}")
+ print(f"Labels: {bucket.labels}")
+
+
+# [END storage_get_bucket_metadata]
+
+if __name__ == "__main__":
+ bucket_metadata(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_get_default_event_based_hold.py b/samples/snippets/storage_get_default_event_based_hold.py
new file mode 100644
index 000000000..4cf13914d
--- /dev/null
+++ b/samples/snippets/storage_get_default_event_based_hold.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_default_event_based_hold]
+from google.cloud import storage
+
+
+def get_default_event_based_hold(bucket_name):
+ """Gets the default event based hold on a given bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+
+ if bucket.default_event_based_hold:
+ print("Default event-based hold is enabled for {}".format(bucket_name))
+ else:
+ print(
+ "Default event-based hold is not enabled for {}".format(
+ bucket_name
+ )
+ )
+
+
+# [END storage_get_default_event_based_hold]
+
+
+if __name__ == "__main__":
+ get_default_event_based_hold(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_get_hmac_key.py b/samples/snippets/storage_get_hmac_key.py
new file mode 100644
index 000000000..4dc52240d
--- /dev/null
+++ b/samples/snippets/storage_get_hmac_key.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_hmac_key]
+from google.cloud import storage
+
+
+def get_key(access_id, project_id):
+ """
+ Retrieve the HMACKeyMetadata with the given access id.
+ """
+ # project_id = "Your Google Cloud project ID"
+ # access_id = "ID of an HMAC key"
+
+ storage_client = storage.Client(project=project_id)
+
+ hmac_key = storage_client.get_hmac_key_metadata(
+ access_id, project_id=project_id
+ )
+
+ print("The HMAC key metadata is:")
+ print("Service Account Email: {}".format(hmac_key.service_account_email))
+ print("Key ID: {}".format(hmac_key.id))
+ print("Access ID: {}".format(hmac_key.access_id))
+ print("Project ID: {}".format(hmac_key.project))
+ print("State: {}".format(hmac_key.state))
+ print("Created At: {}".format(hmac_key.time_created))
+ print("Updated At: {}".format(hmac_key.updated))
+ print("Etag: {}".format(hmac_key.etag))
+ return hmac_key
+
+
+# [END storage_get_hmac_key]
+
+if __name__ == "__main__":
+ get_key(access_id=sys.argv[1], project_id=sys.argv[2])
diff --git a/samples/snippets/storage_get_metadata.py b/samples/snippets/storage_get_metadata.py
new file mode 100644
index 000000000..c5ef0b4cc
--- /dev/null
+++ b/samples/snippets/storage_get_metadata.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_metadata]
+from google.cloud import storage
+
+
+def blob_metadata(bucket_name, blob_name):
+ """Prints out a blob's metadata."""
+ # bucket_name = 'your-bucket-name'
+ # blob_name = 'your-object-name'
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ # Retrieve a blob, and its metadata, from Google Cloud Storage.
+ # Note that `get_blob` differs from `Bucket.blob`, which does not
+ # make an HTTP request.
+ blob = bucket.get_blob(blob_name)
+
+ print("Blob: {}".format(blob.name))
+ print("Bucket: {}".format(blob.bucket.name))
+ print("Storage class: {}".format(blob.storage_class))
+ print("ID: {}".format(blob.id))
+ print("Size: {} bytes".format(blob.size))
+ print("Updated: {}".format(blob.updated))
+ print("Generation: {}".format(blob.generation))
+ print("Metageneration: {}".format(blob.metageneration))
+ print("Etag: {}".format(blob.etag))
+ print("Owner: {}".format(blob.owner))
+ print("Component count: {}".format(blob.component_count))
+ print("Crc32c: {}".format(blob.crc32c))
+ print("md5_hash: {}".format(blob.md5_hash))
+ print("Cache-control: {}".format(blob.cache_control))
+ print("Content-type: {}".format(blob.content_type))
+ print("Content-disposition: {}".format(blob.content_disposition))
+ print("Content-encoding: {}".format(blob.content_encoding))
+ print("Content-language: {}".format(blob.content_language))
+ print("Metadata: {}".format(blob.metadata))
+ print("Custom Time: {}".format(blob.custom_time))
+ print("Temporary hold: ", "enabled" if blob.temporary_hold else "disabled")
+ print(
+ "Event based hold: ",
+ "enabled" if blob.event_based_hold else "disabled",
+ )
+ if blob.retention_expiration_time:
+ print(
+ "retentionExpirationTime: {}".format(
+ blob.retention_expiration_time
+ )
+ )
+
+
+# [END storage_get_metadata]
+
+if __name__ == "__main__":
+ blob_metadata(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_get_public_access_prevention.py b/samples/snippets/storage_get_public_access_prevention.py
new file mode 100644
index 000000000..275b84e35
--- /dev/null
+++ b/samples/snippets/storage_get_public_access_prevention.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_public_access_prevention]
+from google.cloud import storage
+
+
+def get_public_access_prevention(bucket_name):
+ """Gets the public access prevention setting (either 'inherited' or 'enforced') for a bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+ iam_configuration = bucket.iam_configuration
+
+ print(
+ f"Public access prevention is {iam_configuration.public_access_prevention} for {bucket.name}."
+ )
+
+
+# [END storage_get_public_access_prevention]
+
+if __name__ == "__main__":
+ get_public_access_prevention(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_get_requester_pays_status.py b/samples/snippets/storage_get_requester_pays_status.py
new file mode 100644
index 000000000..2014d654c
--- /dev/null
+++ b/samples/snippets/storage_get_requester_pays_status.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_requester_pays_status]
+from google.cloud import storage
+
+
+def get_requester_pays_status(bucket_name):
+ """Get a bucket's requester pays metadata"""
+ # bucket_name = "my-bucket"
+ storage_client = storage.Client()
+
+ bucket = storage_client.get_bucket(bucket_name)
+ requester_pays_status = bucket.requester_pays
+
+ if requester_pays_status:
+ print("Requester Pays is enabled for {}".format(bucket_name))
+ else:
+ print("Requester Pays is disabled for {}".format(bucket_name))
+
+
+# [END storage_get_requester_pays_status]
+
+if __name__ == "__main__":
+ get_requester_pays_status(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_get_retention_policy.py b/samples/snippets/storage_get_retention_policy.py
new file mode 100644
index 000000000..f2ca26d26
--- /dev/null
+++ b/samples/snippets/storage_get_retention_policy.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_retention_policy]
+from google.cloud import storage
+
+
+def get_retention_policy(bucket_name):
+ """Gets the retention policy on a given bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ bucket.reload()
+
+ print("Retention Policy for {}".format(bucket_name))
+ print("Retention Period: {}".format(bucket.retention_period))
+ if bucket.retention_policy_locked:
+ print("Retention Policy is locked")
+
+ if bucket.retention_policy_effective_time:
+ print(
+ "Effective Time: {}".format(bucket.retention_policy_effective_time)
+ )
+
+
+# [END storage_get_retention_policy]
+
+
+if __name__ == "__main__":
+ get_retention_policy(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_get_service_account.py b/samples/snippets/storage_get_service_account.py
new file mode 100644
index 000000000..58ababb91
--- /dev/null
+++ b/samples/snippets/storage_get_service_account.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_get_service_account]
+from google.cloud import storage
+
+
+def get_service_account():
+ """Get the service account email"""
+ storage_client = storage.Client()
+
+ email = storage_client.get_service_account_email()
+ print(
+ "The GCS service account for project {} is: {} ".format(
+ storage_client.project, email
+ )
+ )
+
+
+# [END storage_get_service_account]
+
+if __name__ == "__main__":
+ get_service_account()
diff --git a/samples/snippets/storage_get_uniform_bucket_level_access.py b/samples/snippets/storage_get_uniform_bucket_level_access.py
new file mode 100644
index 000000000..eddb8bc1a
--- /dev/null
+++ b/samples/snippets/storage_get_uniform_bucket_level_access.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_get_uniform_bucket_level_access]
+from google.cloud import storage
+
+
+def get_uniform_bucket_level_access(bucket_name):
+ """Get uniform bucket-level access for a bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+ iam_configuration = bucket.iam_configuration
+
+ if iam_configuration.uniform_bucket_level_access_enabled:
+ print(
+ "Uniform bucket-level access is enabled for {}.".format(
+ bucket.name
+ )
+ )
+ print(
+ "Bucket will be locked on {}.".format(
+ iam_configuration.uniform_bucket_level_locked_time
+ )
+ )
+ else:
+ print(
+ "Uniform bucket-level access is disabled for {}.".format(
+ bucket.name
+ )
+ )
+
+
+# [END storage_get_uniform_bucket_level_access]
+
+if __name__ == "__main__":
+ get_uniform_bucket_level_access(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_list_bucket_notifications.py b/samples/snippets/storage_list_bucket_notifications.py
new file mode 100644
index 000000000..0d25138bc
--- /dev/null
+++ b/samples/snippets/storage_list_bucket_notifications.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that lists notification configurations for a bucket.
+This sample is used on this page:
+ https://cloud.google.com/storage/docs/reporting-changes
+For more information, see README.md.
+"""
+
+# [START storage_list_bucket_notifications]
+from google.cloud import storage
+
+
+def list_bucket_notifications(bucket_name):
+ """Lists notification configurations for a bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ notifications = bucket.list_notifications()
+
+ for notification in notifications:
+ print(f"Notification ID: {notification.notification_id}")
+
+# [END storage_list_bucket_notifications]
+
+
+if __name__ == "__main__":
+ list_bucket_notifications(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_list_buckets.py b/samples/snippets/storage_list_buckets.py
new file mode 100644
index 000000000..f5897e47a
--- /dev/null
+++ b/samples/snippets/storage_list_buckets.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# [START storage_list_buckets]
+from google.cloud import storage
+
+
+def list_buckets():
+ """Lists all buckets."""
+
+ storage_client = storage.Client()
+ buckets = storage_client.list_buckets()
+
+ for bucket in buckets:
+ print(bucket.name)
+
+
+# [END storage_list_buckets]
+
+
+if __name__ == "__main__":
+ list_buckets()
diff --git a/samples/snippets/storage_list_file_archived_generations.py b/samples/snippets/storage_list_file_archived_generations.py
new file mode 100644
index 000000000..dc2f5eaf5
--- /dev/null
+++ b/samples/snippets/storage_list_file_archived_generations.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_list_file_archived_generations]
+from google.cloud import storage
+
+
+def list_file_archived_generations(bucket_name):
+ """Lists all the blobs in the bucket with generation."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+
+ blobs = storage_client.list_blobs(bucket_name, versions=True)
+
+ for blob in blobs:
+ print("{},{}".format(blob.name, blob.generation))
+
+
+# [END storage_list_file_archived_generations]
+
+
+if __name__ == "__main__":
+ list_file_archived_generations(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_list_files.py b/samples/snippets/storage_list_files.py
new file mode 100644
index 000000000..c6a80d9fa
--- /dev/null
+++ b/samples/snippets/storage_list_files.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_list_files]
+from google.cloud import storage
+
+
+def list_blobs(bucket_name):
+ """Lists all the blobs in the bucket."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+
+ # Note: Client.list_blobs requires at least package version 1.17.0.
+ blobs = storage_client.list_blobs(bucket_name)
+
+ for blob in blobs:
+ print(blob.name)
+
+
+# [END storage_list_files]
+
+
+if __name__ == "__main__":
+ list_blobs(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_list_files_with_prefix.py b/samples/snippets/storage_list_files_with_prefix.py
new file mode 100644
index 000000000..f79413fb6
--- /dev/null
+++ b/samples/snippets/storage_list_files_with_prefix.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_list_files_with_prefix]
+from google.cloud import storage
+
+
+def list_blobs_with_prefix(bucket_name, prefix, delimiter=None):
+ """Lists all the blobs in the bucket that begin with the prefix.
+
+ This can be used to list all blobs in a "folder", e.g. "public/".
+
+ The delimiter argument can be used to restrict the results to only the
+ "files" in the given "folder". Without the delimiter, the entire tree under
+ the prefix is returned. For example, given these blobs:
+
+ a/1.txt
+ a/b/2.txt
+
+ If you specify prefix ='a/', without a delimiter, you'll get back:
+
+ a/1.txt
+ a/b/2.txt
+
+ However, if you specify prefix='a/' and delimiter='/', you'll get back
+ only the file directly under 'a/':
+
+ a/1.txt
+
+ As part of the response, you'll also get back a blobs.prefixes entity
+ that lists the "subfolders" under `a/`:
+
+ a/b/
+ """
+
+ storage_client = storage.Client()
+
+ # Note: Client.list_blobs requires at least package version 1.17.0.
+ blobs = storage_client.list_blobs(bucket_name, prefix=prefix, delimiter=delimiter)
+
+ print("Blobs:")
+ for blob in blobs:
+ print(blob.name)
+
+ if delimiter:
+ print("Prefixes:")
+ for prefix in blobs.prefixes:
+ print(prefix)
+
+
+# [END storage_list_files_with_prefix]
+
+if __name__ == "__main__":
+ list_blobs_with_prefix(
+ bucket_name=sys.argv[1], prefix=sys.argv[2], delimiter=sys.argv[3]
+ )
diff --git a/samples/snippets/storage_list_hmac_keys.py b/samples/snippets/storage_list_hmac_keys.py
new file mode 100644
index 000000000..8e5c53b58
--- /dev/null
+++ b/samples/snippets/storage_list_hmac_keys.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_list_hmac_keys]
+from google.cloud import storage
+
+
+def list_keys(project_id):
+ """
+ List all HMAC keys associated with the project.
+ """
+ # project_id = "Your Google Cloud project ID"
+
+ storage_client = storage.Client(project=project_id)
+ hmac_keys = storage_client.list_hmac_keys(project_id=project_id)
+ print("HMAC Keys:")
+ for hmac_key in hmac_keys:
+ print(
+ "Service Account Email: {}".format(hmac_key.service_account_email)
+ )
+ print("Access ID: {}".format(hmac_key.access_id))
+ return hmac_keys
+
+
+# [END storage_list_hmac_keys]
+
+if __name__ == "__main__":
+ list_keys(project_id=sys.argv[1])
diff --git a/samples/snippets/storage_lock_retention_policy.py b/samples/snippets/storage_lock_retention_policy.py
new file mode 100644
index 000000000..d59572f5d
--- /dev/null
+++ b/samples/snippets/storage_lock_retention_policy.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_lock_retention_policy]
+from google.cloud import storage
+
+
+def lock_retention_policy(bucket_name):
+ """Locks the retention policy on a given bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ # get_bucket gets the current metageneration value for the bucket,
+ # required by lock_retention_policy.
+ bucket = storage_client.get_bucket(bucket_name)
+
+ # Warning: Once a retention policy is locked it cannot be unlocked
+ # and retention period can only be increased.
+ bucket.lock_retention_policy()
+
+ print("Retention policy for {} is now locked".format(bucket_name))
+ print(
+ "Retention policy effective as of {}".format(
+ bucket.retention_policy_effective_time
+ )
+ )
+
+
+# [END storage_lock_retention_policy]
+
+
+if __name__ == "__main__":
+ lock_retention_policy(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_make_public.py b/samples/snippets/storage_make_public.py
new file mode 100644
index 000000000..79ae40d12
--- /dev/null
+++ b/samples/snippets/storage_make_public.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_make_public]
+from google.cloud import storage
+
+
+def make_blob_public(bucket_name, blob_name):
+ """Makes a blob publicly accessible."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ blob.make_public()
+
+ print(
+ "Blob {} is publicly accessible at {}".format(
+ blob.name, blob.public_url
+ )
+ )
+
+
+# [END storage_make_public]
+
+if __name__ == "__main__":
+ make_blob_public(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_move_file.py b/samples/snippets/storage_move_file.py
new file mode 100644
index 000000000..a881a38ba
--- /dev/null
+++ b/samples/snippets/storage_move_file.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_move_file]
+from google.cloud import storage
+
+
+def move_blob(bucket_name, blob_name, destination_bucket_name, destination_blob_name):
+ """Moves a blob from one bucket to another with a new name."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The ID of your GCS object
+ # blob_name = "your-object-name"
+ # The ID of the bucket to move the object to
+ # destination_bucket_name = "destination-bucket-name"
+ # The ID of your new GCS object (optional)
+ # destination_blob_name = "destination-object-name"
+
+ storage_client = storage.Client()
+
+ source_bucket = storage_client.bucket(bucket_name)
+ source_blob = source_bucket.blob(blob_name)
+ destination_bucket = storage_client.bucket(destination_bucket_name)
+
+ blob_copy = source_bucket.copy_blob(
+ source_blob, destination_bucket, destination_blob_name
+ )
+ source_bucket.delete_blob(blob_name)
+
+ print(
+ "Blob {} in bucket {} moved to blob {} in bucket {}.".format(
+ source_blob.name,
+ source_bucket.name,
+ blob_copy.name,
+ destination_bucket.name,
+ )
+ )
+
+
+# [END storage_move_file]
+
+if __name__ == "__main__":
+ move_blob(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2],
+ destination_bucket_name=sys.argv[3],
+ destination_blob_name=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_object_csek_to_cmek.py b/samples/snippets/storage_object_csek_to_cmek.py
new file mode 100644
index 000000000..9d4d710bf
--- /dev/null
+++ b/samples/snippets/storage_object_csek_to_cmek.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import base64
+import sys
+
+# [START storage_object_csek_to_cmek]
+from google.cloud import storage
+
+
+def object_csek_to_cmek(bucket_name, blob_name, encryption_key, kms_key_name):
+ """Change a blob's customer-supplied encryption key to KMS key"""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+ # encryption_key = "TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g="
+ # kms_key_name = "projects/PROJ/locations/LOC/keyRings/RING/cryptoKey/KEY"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ current_encryption_key = base64.b64decode(encryption_key)
+ source_blob = bucket.blob(blob_name, encryption_key=current_encryption_key)
+
+ destination_blob = bucket.blob(blob_name, kms_key_name=kms_key_name)
+ token, rewritten, total = destination_blob.rewrite(source_blob)
+
+ while token is not None:
+ token, rewritten, total = destination_blob.rewrite(source_blob, token=token)
+
+ print(
+ "Blob {} in bucket {} is now managed by the KMS key {} instead of a customer-supplied encryption key".format(
+ blob_name, bucket_name, kms_key_name
+ )
+ )
+ return destination_blob
+
+
+# [END storage_object_csek_to_cmek]
+
+if __name__ == "__main__":
+ object_csek_to_cmek(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2],
+ encryption_key=sys.argv[3],
+ kms_key_name=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_object_get_kms_key.py b/samples/snippets/storage_object_get_kms_key.py
new file mode 100644
index 000000000..dddfc9151
--- /dev/null
+++ b/samples/snippets/storage_object_get_kms_key.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_object_get_kms_key]
+from google.cloud import storage
+
+
+def object_get_kms_key(bucket_name, blob_name):
+ """Retrieve the KMS key of a blob"""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+
+ storage_client = storage.Client()
+
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.get_blob(blob_name)
+
+ kms_key = blob.kms_key_name
+
+ print("The KMS key of a blob is {}".format(blob.kms_key_name))
+ return kms_key
+
+
+# [END storage_object_get_kms_key]
+
+if __name__ == "__main__":
+ object_get_kms_key(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_print_bucket_acl.py b/samples/snippets/storage_print_bucket_acl.py
new file mode 100644
index 000000000..0804f7a9a
--- /dev/null
+++ b/samples/snippets/storage_print_bucket_acl.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_print_bucket_acl]
+from google.cloud import storage
+
+
+def print_bucket_acl(bucket_name):
+ """Prints out a bucket's access control list."""
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ for entry in bucket.acl:
+ print("{}: {}".format(entry["role"], entry["entity"]))
+
+
+# [END storage_print_bucket_acl]
+
+if __name__ == "__main__":
+ print_bucket_acl(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_print_bucket_acl_for_user.py b/samples/snippets/storage_print_bucket_acl_for_user.py
new file mode 100644
index 000000000..fa786d03a
--- /dev/null
+++ b/samples/snippets/storage_print_bucket_acl_for_user.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_print_bucket_acl_for_user]
+from google.cloud import storage
+
+
+def print_bucket_acl_for_user(bucket_name, user_email):
+ """Prints out a bucket's access control list for a given user."""
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ bucket.acl.reload()
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # get the roles for different types of entities.
+ roles = bucket.acl.user(user_email).get_roles()
+
+ print(roles)
+
+
+# [END storage_print_bucket_acl_for_user]
+
+if __name__ == "__main__":
+ print_bucket_acl_for_user(bucket_name=sys.argv[1], user_email=sys.argv[2])
diff --git a/samples/snippets/storage_print_file_acl.py b/samples/snippets/storage_print_file_acl.py
new file mode 100644
index 000000000..f34a5283b
--- /dev/null
+++ b/samples/snippets/storage_print_file_acl.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_print_file_acl]
+from google.cloud import storage
+
+
+def print_blob_acl(bucket_name, blob_name):
+ """Prints out a blob's access control list."""
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ for entry in blob.acl:
+ print("{}: {}".format(entry["role"], entry["entity"]))
+
+
+# [END storage_print_file_acl]
+
+if __name__ == "__main__":
+ print_blob_acl(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_print_file_acl_for_user.py b/samples/snippets/storage_print_file_acl_for_user.py
new file mode 100644
index 000000000..e399b9160
--- /dev/null
+++ b/samples/snippets/storage_print_file_acl_for_user.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_print_file_acl_for_user]
+from google.cloud import storage
+
+
+def print_blob_acl_for_user(bucket_name, blob_name, user_email):
+ """Prints out a blob's access control list for a given user."""
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ blob.acl.reload()
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # get the roles for different types of entities.
+ roles = blob.acl.user(user_email).get_roles()
+
+ print(roles)
+
+
+# [END storage_print_file_acl_for_user]
+
+if __name__ == "__main__":
+ print_blob_acl_for_user(
+ bucket_name=sys.argv[1], blob_name=sys.argv[2], user_email=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_print_pubsub_bucket_notification.py b/samples/snippets/storage_print_pubsub_bucket_notification.py
new file mode 100644
index 000000000..3df45dc1f
--- /dev/null
+++ b/samples/snippets/storage_print_pubsub_bucket_notification.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that gets a notification configuration for a bucket.
+This sample is used on this page:
+ https://cloud.google.com/storage/docs/reporting-changes
+For more information, see README.md.
+"""
+
+# [START storage_print_pubsub_bucket_notification]
+from google.cloud import storage
+
+
+def print_pubsub_bucket_notification(bucket_name, notification_id):
+ """Gets a notification configuration for a bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The ID of the notification
+ # notification_id = "your-notification-id"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ notification = bucket.get_notification(notification_id)
+
+ print(f"Notification ID: {notification.notification_id}")
+ print(f"Topic Name: {notification.topic_name}")
+ print(f"Event Types: {notification.event_types}")
+ print(f"Custom Attributes: {notification.custom_attributes}")
+ print(f"Payload Format: {notification.payload_format}")
+ print(f"Blob Name Prefix: {notification.blob_name_prefix}")
+ print(f"Etag: {notification.etag}")
+ print(f"Self Link: {notification.self_link}")
+
+# [END storage_print_pubsub_bucket_notification]
+
+
+if __name__ == "__main__":
+ print_pubsub_bucket_notification(bucket_name=sys.argv[1], notification_id=sys.argv[2])
diff --git a/samples/snippets/storage_release_event_based_hold.py b/samples/snippets/storage_release_event_based_hold.py
new file mode 100644
index 000000000..8c3c11b6f
--- /dev/null
+++ b/samples/snippets/storage_release_event_based_hold.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_release_event_based_hold]
+from google.cloud import storage
+
+
+def release_event_based_hold(bucket_name, blob_name):
+ """Releases the event based hold on a given blob"""
+
+ # bucket_name = "my-bucket"
+ # blob_name = "my-blob"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ blob.event_based_hold = False
+ blob.patch()
+
+ print("Event based hold was released for {}".format(blob_name))
+
+
+# [END storage_release_event_based_hold]
+
+
+if __name__ == "__main__":
+ release_event_based_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_release_temporary_hold.py b/samples/snippets/storage_release_temporary_hold.py
new file mode 100644
index 000000000..02a6ca96c
--- /dev/null
+++ b/samples/snippets/storage_release_temporary_hold.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_release_temporary_hold]
+from google.cloud import storage
+
+
+def release_temporary_hold(bucket_name, blob_name):
+ """Releases the temporary hold on a given blob"""
+
+ # bucket_name = "my-bucket"
+ # blob_name = "my-blob"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ blob.temporary_hold = False
+ blob.patch()
+
+ print("Temporary hold was release for #{blob_name}")
+
+
+# [END storage_release_temporary_hold]
+
+
+if __name__ == "__main__":
+ release_temporary_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_remove_bucket_conditional_iam_binding.py b/samples/snippets/storage_remove_bucket_conditional_iam_binding.py
new file mode 100644
index 000000000..242544d8e
--- /dev/null
+++ b/samples/snippets/storage_remove_bucket_conditional_iam_binding.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_bucket_conditional_iam_binding]
+from google.cloud import storage
+
+
+def remove_bucket_conditional_iam_binding(
+ bucket_name, role, title, description, expression
+):
+ """Remove a conditional IAM binding from a bucket's IAM policy."""
+ # bucket_name = "your-bucket-name"
+ # role = "IAM role, e.g. roles/storage.objectViewer"
+ # title = "Condition title."
+ # description = "Condition description."
+ # expression = "Condition expression."
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+
+ # Set the policy's version to 3 to use condition in bindings.
+ policy.version = 3
+
+ condition = {
+ "title": title,
+ "description": description,
+ "expression": expression,
+ }
+ policy.bindings = [
+ binding
+ for binding in policy.bindings
+ if not (binding["role"] == role and binding.get("condition") == condition)
+ ]
+
+ bucket.set_iam_policy(policy)
+
+ print("Conditional Binding was removed.")
+
+
+# [END storage_remove_bucket_conditional_iam_binding]
+
+
+if __name__ == "__main__":
+ remove_bucket_conditional_iam_binding(
+ bucket_name=sys.argv[1],
+ role=sys.argv[2],
+ title=sys.argv[3],
+ description=sys.argv[4],
+ expression=sys.argv[5],
+ )
diff --git a/samples/snippets/storage_remove_bucket_default_owner.py b/samples/snippets/storage_remove_bucket_default_owner.py
new file mode 100644
index 000000000..beaf6be84
--- /dev/null
+++ b/samples/snippets/storage_remove_bucket_default_owner.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_bucket_default_owner]
+from google.cloud import storage
+
+
+def remove_bucket_default_owner(bucket_name, user_email):
+ """Removes a user from the access control list of the given bucket's
+ default object access control list."""
+ # bucket_name = "your-bucket-name"
+ # user_email = "name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ bucket.acl.reload()
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # remove access for different types of entities.
+ bucket.default_object_acl.user(user_email).revoke_read()
+ bucket.default_object_acl.user(user_email).revoke_write()
+ bucket.default_object_acl.user(user_email).revoke_owner()
+ bucket.default_object_acl.save()
+
+ print(
+ "Removed user {} from the default acl of bucket {}.".format(
+ user_email, bucket_name
+ )
+ )
+
+
+# [END storage_remove_bucket_default_owner]
+
+if __name__ == "__main__":
+ remove_bucket_default_owner(
+ bucket_name=sys.argv[1], user_email=sys.argv[2]
+ )
diff --git a/samples/snippets/storage_remove_bucket_iam_member.py b/samples/snippets/storage_remove_bucket_iam_member.py
new file mode 100644
index 000000000..ef75a1a15
--- /dev/null
+++ b/samples/snippets/storage_remove_bucket_iam_member.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_bucket_iam_member]
+from google.cloud import storage
+
+
+def remove_bucket_iam_member(bucket_name, role, member):
+ """Remove member from bucket IAM Policy"""
+ # bucket_name = "your-bucket-name"
+ # role = "IAM role, e.g. roles/storage.objectViewer"
+ # member = "IAM identity, e.g. user: name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+
+ for binding in policy.bindings:
+ print(binding)
+ if binding["role"] == role and binding.get("condition") is None:
+ binding["members"].discard(member)
+
+ bucket.set_iam_policy(policy)
+
+ print("Removed {} with role {} from {}.".format(member, role, bucket_name))
+
+
+# [END storage_remove_bucket_iam_member]
+
+if __name__ == "__main__":
+ remove_bucket_iam_member(
+ bucket_name=sys.argv[1], role=sys.argv[2], member=sys.argv[3]
+ )
diff --git a/samples/snippets/storage_remove_bucket_label.py b/samples/snippets/storage_remove_bucket_label.py
new file mode 100644
index 000000000..58bbfef2d
--- /dev/null
+++ b/samples/snippets/storage_remove_bucket_label.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_remove_bucket_label]
+import pprint
+# [END storage_remove_bucket_label]
+import sys
+# [START storage_remove_bucket_label]
+
+from google.cloud import storage
+
+
+def remove_bucket_label(bucket_name):
+ """Remove a label from a bucket."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ labels = bucket.labels
+
+ if "example" in labels:
+ del labels["example"]
+
+ bucket.labels = labels
+ bucket.patch()
+
+ print("Removed labels on {}.".format(bucket.name))
+ pprint.pprint(bucket.labels)
+
+
+# [END storage_remove_bucket_label]
+
+if __name__ == "__main__":
+ remove_bucket_label(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_remove_bucket_owner.py b/samples/snippets/storage_remove_bucket_owner.py
new file mode 100644
index 000000000..f54e7a7cc
--- /dev/null
+++ b/samples/snippets/storage_remove_bucket_owner.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_bucket_owner]
+from google.cloud import storage
+
+
+def remove_bucket_owner(bucket_name, user_email):
+ """Removes a user from the access control list of the given bucket."""
+ # bucket_name = "your-bucket-name"
+ # user_email = "name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ # Reload fetches the current ACL from Cloud Storage.
+ bucket.acl.reload()
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # remove access for different types of entities.
+ bucket.acl.user(user_email).revoke_read()
+ bucket.acl.user(user_email).revoke_write()
+ bucket.acl.user(user_email).revoke_owner()
+ bucket.acl.save()
+
+ print("Removed user {} from bucket {}.".format(user_email, bucket_name))
+
+
+# [END storage_remove_bucket_owner]
+
+if __name__ == "__main__":
+ remove_bucket_owner(bucket_name=sys.argv[1], user_email=sys.argv[2])
diff --git a/samples/snippets/storage_remove_cors_configuration.py b/samples/snippets/storage_remove_cors_configuration.py
new file mode 100644
index 000000000..48ee74338
--- /dev/null
+++ b/samples/snippets/storage_remove_cors_configuration.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_cors_configuration]
+from google.cloud import storage
+
+
+def remove_cors_configuration(bucket_name):
+ """Remove a bucket's CORS policies configuration."""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.cors = []
+ bucket.patch()
+
+ print("Remove CORS policies for bucket {}.".format(bucket.name))
+ return bucket
+
+
+# [END storage_remove_cors_configuration]
+
+if __name__ == "__main__":
+ remove_cors_configuration(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_remove_file_owner.py b/samples/snippets/storage_remove_file_owner.py
new file mode 100644
index 000000000..9db83cce0
--- /dev/null
+++ b/samples/snippets/storage_remove_file_owner.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_file_owner]
+from google.cloud import storage
+
+
+def remove_blob_owner(bucket_name, blob_name, user_email):
+ """Removes a user from the access control list of the given blob in the
+ given bucket."""
+ # bucket_name = "your-bucket-name"
+ # blob_name = "your-object-name"
+ # user_email = "name@example.com"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ # You can also use `group`, `domain`, `all_authenticated` and `all` to
+ # remove access for different types of entities.
+ blob.acl.user(user_email).revoke_read()
+ blob.acl.user(user_email).revoke_write()
+ blob.acl.user(user_email).revoke_owner()
+ blob.acl.save()
+
+ print(
+ "Removed user {} from blob {} in bucket {}.".format(
+ user_email, blob_name, bucket_name
+ )
+ )
+
+
+# [END storage_remove_file_owner]
+
+if __name__ == "__main__":
+ remove_blob_owner(
+ bucket_name=sys.argv[1], blob_name=sys.argv[2], user_email=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_remove_retention_policy.py b/samples/snippets/storage_remove_retention_policy.py
new file mode 100644
index 000000000..cb8ee548c
--- /dev/null
+++ b/samples/snippets/storage_remove_retention_policy.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_remove_retention_policy]
+from google.cloud import storage
+
+
+def remove_retention_policy(bucket_name):
+ """Removes the retention policy on a given bucket"""
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ bucket.reload()
+
+ if bucket.retention_policy_locked:
+ print(
+ "Unable to remove retention period as retention policy is locked."
+ )
+ return
+
+ bucket.retention_period = None
+ bucket.patch()
+
+ print("Removed bucket {} retention policy".format(bucket.name))
+
+
+# [END storage_remove_retention_policy]
+
+
+if __name__ == "__main__":
+ remove_retention_policy(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_rename_file.py b/samples/snippets/storage_rename_file.py
new file mode 100644
index 000000000..b47e18621
--- /dev/null
+++ b/samples/snippets/storage_rename_file.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_rename_file]
+from google.cloud import storage
+
+
+def rename_blob(bucket_name, blob_name, new_name):
+ """Renames a blob."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The ID of the GCS object to rename
+ # blob_name = "your-object-name"
+ # The new ID of the GCS object
+ # new_name = "new-object-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ new_blob = bucket.rename_blob(blob, new_name)
+
+ print("Blob {} has been renamed to {}".format(blob.name, new_blob.name))
+
+
+# [END storage_rename_file]
+
+if __name__ == "__main__":
+ rename_blob(bucket_name=sys.argv[1], blob_name=sys.argv[2], new_name=sys.argv[3])
diff --git a/samples/snippets/storage_rotate_encryption_key.py b/samples/snippets/storage_rotate_encryption_key.py
new file mode 100644
index 000000000..663ee4796
--- /dev/null
+++ b/samples/snippets/storage_rotate_encryption_key.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_rotate_encryption_key]
+import base64
+# [END storage_rotate_encryption_key]
+import sys
+# [START storage_rotate_encryption_key]
+
+from google.cloud import storage
+
+
+def rotate_encryption_key(
+ bucket_name, blob_name, base64_encryption_key, base64_new_encryption_key
+):
+ """Performs a key rotation by re-writing an encrypted blob with a new
+ encryption key."""
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ current_encryption_key = base64.b64decode(base64_encryption_key)
+ new_encryption_key = base64.b64decode(base64_new_encryption_key)
+
+ # Both source_blob and destination_blob refer to the same storage object,
+ # but destination_blob has the new encryption key.
+ source_blob = bucket.blob(
+ blob_name, encryption_key=current_encryption_key
+ )
+ destination_blob = bucket.blob(
+ blob_name, encryption_key=new_encryption_key
+ )
+
+ token = None
+
+ while True:
+ token, bytes_rewritten, total_bytes = destination_blob.rewrite(
+ source_blob, token=token
+ )
+ if token is None:
+ break
+
+ print("Key rotation complete for Blob {}".format(blob_name))
+
+
+# [END storage_rotate_encryption_key]
+
+if __name__ == "__main__":
+ rotate_encryption_key(
+ bucket_name=sys.argv[1],
+ blob_name=sys.argv[2],
+ base64_encryption_key=sys.argv[3],
+ base64_new_encryption_key=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_set_bucket_default_kms_key.py b/samples/snippets/storage_set_bucket_default_kms_key.py
new file mode 100644
index 000000000..7ba4718b2
--- /dev/null
+++ b/samples/snippets/storage_set_bucket_default_kms_key.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_bucket_default_kms_key]
+from google.cloud import storage
+
+
+def enable_default_kms_key(bucket_name, kms_key_name):
+ """Sets a bucket's default KMS key."""
+ # bucket_name = "your-bucket-name"
+ # kms_key_name = "projects/PROJ/locations/LOC/keyRings/RING/cryptoKey/KEY"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+ bucket.default_kms_key_name = kms_key_name
+ bucket.patch()
+
+ print(
+ "Set default KMS key for bucket {} to {}.".format(
+ bucket.name, bucket.default_kms_key_name
+ )
+ )
+
+
+# [END storage_set_bucket_default_kms_key]
+
+if __name__ == "__main__":
+ enable_default_kms_key(bucket_name=sys.argv[1], kms_key_name=sys.argv[2])
diff --git a/samples/snippets/storage_set_bucket_public_iam.py b/samples/snippets/storage_set_bucket_public_iam.py
new file mode 100644
index 000000000..4b7df89df
--- /dev/null
+++ b/samples/snippets/storage_set_bucket_public_iam.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google LLC. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_bucket_public_iam]
+from typing import List
+
+from google.cloud import storage
+
+
+def set_bucket_public_iam(
+ bucket_name: str = "your-bucket-name",
+ members: List[str] = ["allUsers"],
+):
+ """Set a public IAM Policy to bucket"""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+ policy.bindings.append(
+ {"role": "roles/storage.objectViewer", "members": members}
+ )
+
+ bucket.set_iam_policy(policy)
+
+ print("Bucket {} is now publicly readable".format(bucket.name))
+
+
+# [END storage_set_bucket_public_iam]
+
+if __name__ == "__main__":
+ set_bucket_public_iam(
+ bucket_name=sys.argv[1],
+ )
diff --git a/samples/snippets/storage_set_event_based_hold.py b/samples/snippets/storage_set_event_based_hold.py
new file mode 100644
index 000000000..52a89b88e
--- /dev/null
+++ b/samples/snippets/storage_set_event_based_hold.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_event_based_hold]
+from google.cloud import storage
+
+
+def set_event_based_hold(bucket_name, blob_name):
+ """Sets a event based hold on a given blob"""
+ # bucket_name = "my-bucket"
+ # blob_name = "my-blob"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ blob.event_based_hold = True
+ blob.patch()
+
+ print("Event based hold was set for {}".format(blob_name))
+
+
+# [END storage_set_event_based_hold]
+
+
+if __name__ == "__main__":
+ set_event_based_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_set_metadata.py b/samples/snippets/storage_set_metadata.py
new file mode 100644
index 000000000..07529ac68
--- /dev/null
+++ b/samples/snippets/storage_set_metadata.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright 2020 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_metadata]
+from google.cloud import storage
+
+
+def set_blob_metadata(bucket_name, blob_name):
+ """Set a blob's metadata."""
+ # bucket_name = 'your-bucket-name'
+ # blob_name = 'your-object-name'
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.get_blob(blob_name)
+ metadata = {'color': 'Red', 'name': 'Test'}
+ blob.metadata = metadata
+ blob.patch()
+
+ print("The metadata for the blob {} is {}".format(blob.name, blob.metadata))
+
+
+# [END storage_set_metadata]
+
+if __name__ == "__main__":
+ set_blob_metadata(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_set_public_access_prevention_enforced.py b/samples/snippets/storage_set_public_access_prevention_enforced.py
new file mode 100644
index 000000000..59ce5ce56
--- /dev/null
+++ b/samples/snippets/storage_set_public_access_prevention_enforced.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_public_access_prevention_enforced]
+from google.cloud import storage
+from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_ENFORCED
+
+
+def set_public_access_prevention_enforced(bucket_name):
+ """Enforce public access prevention for a bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ bucket.iam_configuration.public_access_prevention = (
+ PUBLIC_ACCESS_PREVENTION_ENFORCED
+ )
+ bucket.patch()
+
+ print(f"Public access prevention is set to enforced for {bucket.name}.")
+
+
+# [END storage_set_public_access_prevention_enforced]
+
+if __name__ == "__main__":
+ set_public_access_prevention_enforced(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_set_public_access_prevention_inherited.py b/samples/snippets/storage_set_public_access_prevention_inherited.py
new file mode 100644
index 000000000..97e218f9d
--- /dev/null
+++ b/samples/snippets/storage_set_public_access_prevention_inherited.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+"""Sample that sets public access prevention to inherited.
+This sample is used on this page:
+ https://cloud.google.com/storage/docs/using-public-access-prevention
+For more information, see README.md.
+"""
+
+# [START storage_set_public_access_prevention_inherited]
+
+from google.cloud import storage
+from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_INHERITED
+
+
+def set_public_access_prevention_inherited(bucket_name):
+ """Sets the public access prevention status to inherited, so that the bucket inherits its setting from its parent project."""
+ # The ID of your GCS bucket
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ bucket.iam_configuration.public_access_prevention = (
+ PUBLIC_ACCESS_PREVENTION_INHERITED
+ )
+ bucket.patch()
+
+ print(f"Public access prevention is 'inherited' for {bucket.name}.")
+
+
+# [END storage_set_public_access_prevention_inherited]
+
+if __name__ == "__main__":
+ set_public_access_prevention_inherited(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_set_public_access_prevention_unspecified.py b/samples/snippets/storage_set_public_access_prevention_unspecified.py
new file mode 100644
index 000000000..ae2c4701c
--- /dev/null
+++ b/samples/snippets/storage_set_public_access_prevention_unspecified.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_public_access_prevention_unspecified]
+from google.cloud import storage
+from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_UNSPECIFIED
+
+
+def set_public_access_prevention_unspecified(bucket_name):
+ """Sets the public access prevention status to unspecified, so that the bucket inherits its setting from its parent project."""
+ # The ID of your GCS bucket
+ # bucket_name = "my-bucket"
+
+ storage_client = storage.Client()
+ bucket = storage_client.get_bucket(bucket_name)
+
+ bucket.iam_configuration.public_access_prevention = (
+ PUBLIC_ACCESS_PREVENTION_UNSPECIFIED
+ )
+ bucket.patch()
+
+ print(f"Public access prevention is 'unspecified' for {bucket.name}.")
+
+
+# [END storage_set_public_access_prevention_unspecified]
+
+if __name__ == "__main__":
+ set_public_access_prevention_unspecified(bucket_name=sys.argv[1])
diff --git a/samples/snippets/storage_set_retention_policy.py b/samples/snippets/storage_set_retention_policy.py
new file mode 100644
index 000000000..2b3602491
--- /dev/null
+++ b/samples/snippets/storage_set_retention_policy.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_retention_policy]
+from google.cloud import storage
+
+
+def set_retention_policy(bucket_name, retention_period):
+ """Defines a retention policy on a given bucket"""
+ # bucket_name = "my-bucket"
+ # retention_period = 10
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ bucket.retention_period = retention_period
+ bucket.patch()
+
+ print(
+ "Bucket {} retention period set for {} seconds".format(
+ bucket.name, bucket.retention_period
+ )
+ )
+
+
+# [END storage_set_retention_policy]
+
+
+if __name__ == "__main__":
+ set_retention_policy(bucket_name=sys.argv[1], retention_period=sys.argv[2])
diff --git a/samples/snippets/storage_set_temporary_hold.py b/samples/snippets/storage_set_temporary_hold.py
new file mode 100644
index 000000000..edeb3c578
--- /dev/null
+++ b/samples/snippets/storage_set_temporary_hold.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_set_temporary_hold]
+from google.cloud import storage
+
+
+def set_temporary_hold(bucket_name, blob_name):
+ """Sets a temporary hold on a given blob"""
+ # bucket_name = "my-bucket"
+ # blob_name = "my-blob"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(blob_name)
+
+ blob.temporary_hold = True
+ blob.patch()
+
+ print("Temporary hold was set for #{blob_name}")
+
+
+# [END storage_set_temporary_hold]
+
+
+if __name__ == "__main__":
+ set_temporary_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2])
diff --git a/samples/snippets/storage_upload_encrypted_file.py b/samples/snippets/storage_upload_encrypted_file.py
new file mode 100644
index 000000000..e7d02c67b
--- /dev/null
+++ b/samples/snippets/storage_upload_encrypted_file.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# [START storage_upload_encrypted_file]
+import base64
+# [END storage_upload_encrypted_file]
+import sys
+# [START storage_upload_encrypted_file]
+
+from google.cloud import storage
+
+
+def upload_encrypted_blob(
+ bucket_name,
+ source_file_name,
+ destination_blob_name,
+ base64_encryption_key,
+):
+ """Uploads a file to a Google Cloud Storage bucket using a custom
+ encryption key.
+
+ The file will be encrypted by Google Cloud Storage and only
+ retrievable using the provided encryption key.
+ """
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ # Encryption key must be an AES256 key represented as a bytestring with
+ # 32 bytes. Since it's passed in as a base64 encoded string, it needs
+ # to be decoded.
+ encryption_key = base64.b64decode(base64_encryption_key)
+ blob = bucket.blob(
+ destination_blob_name, encryption_key=encryption_key
+ )
+
+ blob.upload_from_filename(source_file_name)
+
+ print(
+ "File {} uploaded to {}.".format(
+ source_file_name, destination_blob_name
+ )
+ )
+
+
+# [END storage_upload_encrypted_file]
+
+if __name__ == "__main__":
+ upload_encrypted_blob(
+ bucket_name=sys.argv[1],
+ source_file_name=sys.argv[2],
+ destination_blob_name=sys.argv[3],
+ base64_encryption_key=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_upload_file.py b/samples/snippets/storage_upload_file.py
new file mode 100644
index 000000000..fb02c3632
--- /dev/null
+++ b/samples/snippets/storage_upload_file.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_upload_file]
+from google.cloud import storage
+
+
+def upload_blob(bucket_name, source_file_name, destination_blob_name):
+ """Uploads a file to the bucket."""
+ # The ID of your GCS bucket
+ # bucket_name = "your-bucket-name"
+ # The path to your file to upload
+ # source_file_name = "local/path/to/file"
+ # The ID of your GCS object
+ # destination_blob_name = "storage-object-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(destination_blob_name)
+
+ blob.upload_from_filename(source_file_name)
+
+ print(
+ "File {} uploaded to {}.".format(
+ source_file_name, destination_blob_name
+ )
+ )
+
+
+# [END storage_upload_file]
+
+if __name__ == "__main__":
+ upload_blob(
+ bucket_name=sys.argv[1],
+ source_file_name=sys.argv[2],
+ destination_blob_name=sys.argv[3],
+ )
diff --git a/samples/snippets/storage_upload_with_kms_key.py b/samples/snippets/storage_upload_with_kms_key.py
new file mode 100644
index 000000000..e83c10aea
--- /dev/null
+++ b/samples/snippets/storage_upload_with_kms_key.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_upload_with_kms_key]
+from google.cloud import storage
+
+
+def upload_blob_with_kms(
+ bucket_name, source_file_name, destination_blob_name, kms_key_name
+):
+ """Uploads a file to the bucket, encrypting it with the given KMS key."""
+ # bucket_name = "your-bucket-name"
+ # source_file_name = "local/path/to/file"
+ # destination_blob_name = "storage-object-name"
+ # kms_key_name = "projects/PROJ/locations/LOC/keyRings/RING/cryptoKey/KEY"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+ blob = bucket.blob(destination_blob_name, kms_key_name=kms_key_name)
+ blob.upload_from_filename(source_file_name)
+
+ print(
+ "File {} uploaded to {} with encryption key {}.".format(
+ source_file_name, destination_blob_name, kms_key_name
+ )
+ )
+
+
+# [END storage_upload_with_kms_key]
+
+if __name__ == "__main__":
+ upload_blob_with_kms(
+ bucket_name=sys.argv[1],
+ source_file_name=sys.argv[2],
+ destination_blob_name=sys.argv[3],
+ kms_key_name=sys.argv[4],
+ )
diff --git a/samples/snippets/storage_view_bucket_iam_members.py b/samples/snippets/storage_view_bucket_iam_members.py
new file mode 100644
index 000000000..5272f0ddb
--- /dev/null
+++ b/samples/snippets/storage_view_bucket_iam_members.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+# [START storage_view_bucket_iam_members]
+from google.cloud import storage
+
+
+def view_bucket_iam_members(bucket_name):
+ """View IAM Policy for a bucket"""
+ # bucket_name = "your-bucket-name"
+
+ storage_client = storage.Client()
+ bucket = storage_client.bucket(bucket_name)
+
+ policy = bucket.get_iam_policy(requested_policy_version=3)
+
+ for binding in policy.bindings:
+ print("Role: {}, Members: {}".format(binding["role"], binding["members"]))
+
+
+# [END storage_view_bucket_iam_members]
+
+
+if __name__ == "__main__":
+ view_bucket_iam_members(bucket_name=sys.argv[1])
diff --git a/samples/snippets/uniform_bucket_level_access_test.py b/samples/snippets/uniform_bucket_level_access_test.py
new file mode 100644
index 000000000..b43fa016f
--- /dev/null
+++ b/samples/snippets/uniform_bucket_level_access_test.py
@@ -0,0 +1,52 @@
+# Copyright 2019 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import storage_disable_uniform_bucket_level_access
+import storage_enable_uniform_bucket_level_access
+import storage_get_uniform_bucket_level_access
+
+
+def test_get_uniform_bucket_level_access(bucket, capsys):
+ storage_get_uniform_bucket_level_access.get_uniform_bucket_level_access(
+ bucket.name
+ )
+ out, _ = capsys.readouterr()
+ assert (
+ "Uniform bucket-level access is disabled for {}.".format(bucket.name)
+ in out
+ )
+
+
+def test_enable_uniform_bucket_level_access(bucket, capsys):
+ short_name = storage_enable_uniform_bucket_level_access
+ short_name.enable_uniform_bucket_level_access(
+ bucket.name
+ )
+ out, _ = capsys.readouterr()
+ assert (
+ "Uniform bucket-level access was enabled for {}.".format(bucket.name)
+ in out
+ )
+
+
+def test_disable_uniform_bucket_level_access(bucket, capsys):
+ short_name = storage_disable_uniform_bucket_level_access
+ short_name.disable_uniform_bucket_level_access(
+ bucket.name
+ )
+ out, _ = capsys.readouterr()
+ assert (
+ "Uniform bucket-level access was disabled for {}.".format(bucket.name)
+ in out
+ )
diff --git a/setup.py b/setup.py
index d679c2727..0bb36ff93 100644
--- a/setup.py
+++ b/setup.py
@@ -91,6 +91,7 @@
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
"Operating System :: OS Independent",
"Topic :: Internet",
],
diff --git a/tests/conformance/test_conformance.py b/tests/conformance/test_conformance.py
index b85f0eaa7..cf4c026a8 100644
--- a/tests/conformance/test_conformance.py
+++ b/tests/conformance/test_conformance.py
@@ -52,6 +52,7 @@
_CONF_TEST_SERVICE_ACCOUNT_EMAIL = (
"my-service-account@my-project-id.iam.gserviceaccount.com"
)
+_CONF_TEST_PUBSUB_TOPIC_NAME = "my-topic-name"
_STRING_CONTENT = "hello world"
_BYTE_CONTENT = b"12345678"
@@ -190,7 +191,7 @@ def client_get_service_account_email(client, _preconditions, **_):
def notification_create(client, _preconditions, **resources):
bucket = client.bucket(resources.get("bucket").name)
- notification = bucket.notification()
+ notification = bucket.notification(topic_name=_CONF_TEST_PUBSUB_TOPIC_NAME)
notification.create()
@@ -761,7 +762,9 @@ def object(client, bucket):
@pytest.fixture
def notification(client, bucket):
- notification = client.bucket(bucket.name).notification()
+ notification = client.bucket(bucket.name).notification(
+ topic_name=_CONF_TEST_PUBSUB_TOPIC_NAME
+ )
notification.create()
notification.reload()
yield notification
diff --git a/tests/system/test_kms_integration.py b/tests/system/test_kms_integration.py
index a2df6848a..67dc5351f 100644
--- a/tests/system/test_kms_integration.py
+++ b/tests/system/test_kms_integration.py
@@ -148,6 +148,7 @@ def test_bucket_w_default_kms_key_name(
blobs_to_delete.append(defaulted_blob)
assert defaulted_blob.download_as_bytes() == payload
+ _helpers.retry_429_harder(_helpers.retry_has_kms_key_name(defaulted_blob.reload))()
# We don't know the current version of the key.
assert defaulted_blob.kms_key_name.startswith(kms_key_name)
diff --git a/tests/system/test_notification.py b/tests/system/test_notification.py
index 3f03ac39a..6c49064aa 100644
--- a/tests/system/test_notification.py
+++ b/tests/system/test_notification.py
@@ -149,6 +149,34 @@ def test_notification_create_w_user_project(
notification.delete()
+def test_notification_create_wo_topic_name(
+ storage_client,
+ buckets_to_delete,
+ topic_name,
+ notification_topic,
+ event_types,
+ payload_format,
+):
+ from google.cloud.exceptions import BadRequest
+
+ bucket_name = _helpers.unique_name("notification-wo-name")
+ bucket = _helpers.retry_429_503(storage_client.create_bucket)(bucket_name)
+ buckets_to_delete.append(bucket)
+
+ assert list(bucket.list_notifications()) == []
+
+ notification = bucket.notification(
+ topic_name=None,
+ custom_attributes=custom_attributes,
+ event_types=event_types,
+ blob_name_prefix=blob_name_prefix,
+ payload_format=payload_format,
+ )
+
+ with pytest.raises(BadRequest):
+ notification.create()
+
+
def test_bucket_get_notification(
storage_client,
buckets_to_delete,
diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py
index db5212466..90d27abd6 100644
--- a/tests/unit/test_blob.py
+++ b/tests/unit/test_blob.py
@@ -5585,6 +5585,8 @@ def test_open(self):
self.assertEqual(type(f.buffer), BlobWriter)
f = blob.open("wb")
self.assertEqual(type(f), BlobWriter)
+ f = blob.open("wb", ignore_flush=True)
+ self.assertTrue(f._ignore_flush)
with self.assertRaises(NotImplementedError):
blob.open("a")
@@ -5592,6 +5594,12 @@ def test_open(self):
blob.open("rb", encoding="utf-8")
with self.assertRaises(ValueError):
blob.open("wb", encoding="utf-8")
+ with self.assertRaises(ValueError):
+ blob.open("r", ignore_flush=True)
+ with self.assertRaises(ValueError):
+ blob.open("rb", ignore_flush=True)
+ with self.assertRaises(ValueError):
+ blob.open("w", ignore_flush=False)
class Test__quote(unittest.TestCase):
diff --git a/tests/unit/test_fileio.py b/tests/unit/test_fileio.py
index aa64411f7..bf017e44f 100644
--- a/tests/unit/test_fileio.py
+++ b/tests/unit/test_fileio.py
@@ -272,6 +272,13 @@ def test_attributes_explicit(self):
self.assertEqual(writer._chunk_size, 512 * 1024)
self.assertEqual(writer._retry, DEFAULT_RETRY)
+ def test_deprecated_text_mode_attribute(self):
+ blob = mock.Mock()
+ blob.chunk_size = 256 * 1024
+ writer = self._make_blob_writer(blob, text_mode=True)
+ self.assertTrue(writer._ignore_flush)
+ writer.flush() # This should do nothing and not raise an error.
+
def test_reject_wrong_chunk_size(self):
blob = mock.Mock()
blob.chunk_size = 123
@@ -857,7 +864,7 @@ def test_write(self, mock_warn):
unwrapped_writer = self._make_blob_writer(
blob,
chunk_size=chunk_size,
- text_mode=True,
+ ignore_flush=True,
num_retries=NUM_RETRIES,
content_type=PLAIN_CONTENT_TYPE,
)
diff --git a/tests/unit/test_notification.py b/tests/unit/test_notification.py
index 04ffd68a1..cf4e15c13 100644
--- a/tests/unit/test_notification.py
+++ b/tests/unit/test_notification.py
@@ -242,6 +242,35 @@ def test_create_w_existing_notification_id(self):
client._post_resource.assert_not_called()
+ def test_create_wo_topic_name(self):
+ from google.cloud.exceptions import BadRequest
+ from google.cloud.storage.notification import NONE_PAYLOAD_FORMAT
+
+ client = mock.Mock(spec=["_post_resource", "project"])
+ client.project = self.BUCKET_PROJECT
+ client._post_resource.side_effect = BadRequest(
+ "Invalid Google Cloud Pub/Sub topic."
+ )
+ bucket = self._make_bucket(client)
+ notification = self._make_one(bucket, None)
+
+ with self.assertRaises(BadRequest):
+ notification.create()
+
+ expected_topic = self.TOPIC_REF_FMT.format(self.BUCKET_PROJECT, "")
+ expected_data = {
+ "topic": expected_topic,
+ "payload_format": NONE_PAYLOAD_FORMAT,
+ }
+ expected_query_params = {}
+ client._post_resource.assert_called_once_with(
+ self.CREATE_PATH,
+ expected_data,
+ query_params=expected_query_params,
+ timeout=self._get_default_timeout(),
+ retry=None,
+ )
+
def test_create_w_defaults(self):
from google.cloud.storage.notification import NONE_PAYLOAD_FORMAT