diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 3f7634f25..c631e1f7d 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:f016446d6e520e5fb552c45b110cba3f217bffdd3d06bdddd076e9e6d13266cf -# created: 2025-02-21T19:32:52.01306189Z + digest: sha256:5581906b957284864632cde4e9c51d1cc66b0094990b27e689132fe5cd036046 +# created: 2025-03-05 diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index 8f2aae9b2..6c430b00d 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -4,9 +4,7 @@ # Note: This file is autogenerated. To make changes to the assignee # team, please update `codeowner_team` in `.repo-metadata.json`. assign_issues: - - andrewsg - - cojenco + - chandra-siri assign_prs: - - andrewsg - - cojenco + - chandra-siri diff --git a/.kokoro/continuous/prerelease-deps.cfg b/.kokoro/continuous/prerelease-deps.cfg index 3595fb43f..07db02426 100644 --- a/.kokoro/continuous/prerelease-deps.cfg +++ b/.kokoro/continuous/prerelease-deps.cfg @@ -5,3 +5,9 @@ env_vars: { key: "NOX_SESSION" value: "prerelease_deps" } + +# Credentials needed to test universe domain. +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "client-library-test-universe-domain-credential" +} diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile deleted file mode 100644 index e5410e296..000000000 --- a/.kokoro/docker/docs/Dockerfile +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2024 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 ubuntu:24.04 - -ENV DEBIAN_FRONTEND noninteractive - -# Ensure local Python is preferred over distribution Python. -ENV PATH /usr/local/bin:$PATH - -# Install dependencies. -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-transport-https \ - build-essential \ - ca-certificates \ - curl \ - dirmngr \ - git \ - gpg-agent \ - graphviz \ - libbz2-dev \ - libdb5.3-dev \ - libexpat1-dev \ - libffi-dev \ - liblzma-dev \ - libreadline-dev \ - libsnappy-dev \ - libssl-dev \ - libsqlite3-dev \ - portaudio19-dev \ - redis-server \ - software-properties-common \ - ssh \ - sudo \ - tcl \ - tcl-dev \ - tk \ - tk-dev \ - uuid-dev \ - wget \ - zlib1g-dev \ - && add-apt-repository universe \ - && apt-get update \ - && apt-get -y install jq \ - && apt-get clean autoclean \ - && apt-get autoremove -y \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /var/cache/apt/archives/*.deb - - -###################### Install python 3.10.14 for docs/docfx session - -# Download python 3.10.14 -RUN wget https://www.python.org/ftp/python/3.10.14/Python-3.10.14.tgz - -# Extract files -RUN tar -xvf Python-3.10.14.tgz - -# Install python 3.10.14 -RUN ./Python-3.10.14/configure --enable-optimizations -RUN make altinstall - -ENV PATH /usr/local/bin/python3.10:$PATH - -###################### Install pip -RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ - && python3.10 /tmp/get-pip.py \ - && rm /tmp/get-pip.py - -# Test pip -RUN python3.10 -m pip - -# Install build requirements -COPY requirements.txt /requirements.txt -RUN python3.10 -m pip install --require-hashes -r requirements.txt - -CMD ["python3.10"] diff --git a/.kokoro/docker/docs/fetch_gpg_keys.sh b/.kokoro/docker/docs/fetch_gpg_keys.sh deleted file mode 100755 index d653dd868..000000000 --- a/.kokoro/docker/docs/fetch_gpg_keys.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# 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. - -# A script to fetch gpg keys with retry. -# Avoid jinja parsing the file. -# - -function retry { - if [[ "${#}" -le 1 ]]; then - echo "Usage: ${0} retry_count commands.." - exit 1 - fi - local retries=${1} - local command="${@:2}" - until [[ "${retries}" -le 0 ]]; do - $command && return 0 - if [[ $? -ne 0 ]]; then - echo "command failed, retrying" - ((retries--)) - fi - done - return 1 -} - -# 3.6.9, 3.7.5 (Ned Deily) -retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ - 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D - -# 3.8.0 (Ɓukasz Langa) -retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ - E3FF2839C048B25C084DEBE9B26995E310250568 - -# diff --git a/.kokoro/docker/docs/requirements.in b/.kokoro/docker/docs/requirements.in deleted file mode 100644 index 586bd0703..000000000 --- a/.kokoro/docker/docs/requirements.in +++ /dev/null @@ -1,2 +0,0 @@ -nox -gcp-docuploader diff --git a/.kokoro/docker/docs/requirements.txt b/.kokoro/docker/docs/requirements.txt deleted file mode 100644 index a9360a25b..000000000 --- a/.kokoro/docker/docs/requirements.txt +++ /dev/null @@ -1,297 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes requirements.in -# -argcomplete==3.5.3 \ - --hash=sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61 \ - --hash=sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392 - # via nox -cachetools==5.5.0 \ - --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ - --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a - # via google-auth -certifi==2024.12.14 \ - --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ - --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db - # via requests -charset-normalizer==3.4.1 \ - --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ - --hash=sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa \ - --hash=sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a \ - --hash=sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294 \ - --hash=sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b \ - --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \ - --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \ - --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \ - --hash=sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4 \ - --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \ - --hash=sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2 \ - --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \ - --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \ - --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \ - --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \ - --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \ - --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \ - --hash=sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496 \ - --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \ - --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \ - --hash=sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e \ - --hash=sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a \ - --hash=sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4 \ - --hash=sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca \ - --hash=sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78 \ - --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \ - --hash=sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5 \ - --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \ - --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \ - --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \ - --hash=sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765 \ - --hash=sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6 \ - --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \ - --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \ - --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \ - --hash=sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd \ - --hash=sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c \ - --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \ - --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \ - --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \ - --hash=sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770 \ - --hash=sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824 \ - --hash=sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f \ - --hash=sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf \ - --hash=sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487 \ - --hash=sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d \ - --hash=sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd \ - --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \ - --hash=sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534 \ - --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \ - --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \ - --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \ - --hash=sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd \ - --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \ - --hash=sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9 \ - --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \ - --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \ - --hash=sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d \ - --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \ - --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \ - --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \ - --hash=sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7 \ - --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \ - --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \ - --hash=sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8 \ - --hash=sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41 \ - --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \ - --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \ - --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \ - --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \ - --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \ - --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \ - --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \ - --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \ - --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \ - --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \ - --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \ - --hash=sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e \ - --hash=sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6 \ - --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \ - --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \ - --hash=sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e \ - --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \ - --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \ - --hash=sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c \ - --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \ - --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \ - --hash=sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089 \ - --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \ - --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \ - --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ - --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 - # via requests -click==8.1.8 \ - --hash=sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2 \ - --hash=sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a - # via gcp-docuploader -colorlog==6.9.0 \ - --hash=sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff \ - --hash=sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2 - # via - # gcp-docuploader - # nox -distlib==0.3.9 \ - --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ - --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 - # via virtualenv -filelock==3.16.1 \ - --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ - --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 - # via virtualenv -gcp-docuploader==0.6.5 \ - --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ - --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea - # via -r requirements.in -google-api-core==2.24.0 \ - --hash=sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9 \ - --hash=sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf - # via - # google-cloud-core - # google-cloud-storage -google-auth==2.37.0 \ - --hash=sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00 \ - --hash=sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0 - # via - # google-api-core - # google-cloud-core - # google-cloud-storage -google-cloud-core==2.4.1 \ - --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ - --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 - # via google-cloud-storage -google-cloud-storage==2.19.0 \ - --hash=sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba \ - --hash=sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2 - # via gcp-docuploader -google-crc32c==1.6.0 \ - --hash=sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24 \ - --hash=sha256:18e311c64008f1f1379158158bb3f0c8d72635b9eb4f9545f8cf990c5668e59d \ - --hash=sha256:236c87a46cdf06384f614e9092b82c05f81bd34b80248021f729396a78e55d7e \ - --hash=sha256:35834855408429cecf495cac67ccbab802de269e948e27478b1e47dfb6465e57 \ - --hash=sha256:386122eeaaa76951a8196310432c5b0ef3b53590ef4c317ec7588ec554fec5d2 \ - --hash=sha256:40b05ab32a5067525670880eb5d169529089a26fe35dce8891127aeddc1950e8 \ - --hash=sha256:48abd62ca76a2cbe034542ed1b6aee851b6f28aaca4e6551b5599b6f3ef175cc \ - --hash=sha256:50cf2a96da226dcbff8671233ecf37bf6e95de98b2a2ebadbfdf455e6d05df42 \ - --hash=sha256:51c4f54dd8c6dfeb58d1df5e4f7f97df8abf17a36626a217f169893d1d7f3e9f \ - --hash=sha256:5bcc90b34df28a4b38653c36bb5ada35671ad105c99cfe915fb5bed7ad6924aa \ - --hash=sha256:62f6d4a29fea082ac4a3c9be5e415218255cf11684ac6ef5488eea0c9132689b \ - --hash=sha256:6eceb6ad197656a1ff49ebfbbfa870678c75be4344feb35ac1edf694309413dc \ - --hash=sha256:7aec8e88a3583515f9e0957fe4f5f6d8d4997e36d0f61624e70469771584c760 \ - --hash=sha256:91ca8145b060679ec9176e6de4f89b07363d6805bd4760631ef254905503598d \ - --hash=sha256:a184243544811e4a50d345838a883733461e67578959ac59964e43cca2c791e7 \ - --hash=sha256:a9e4b426c3702f3cd23b933436487eb34e01e00327fac20c9aebb68ccf34117d \ - --hash=sha256:bb0966e1c50d0ef5bc743312cc730b533491d60585a9a08f897274e57c3f70e0 \ - --hash=sha256:bb8b3c75bd157010459b15222c3fd30577042a7060e29d42dabce449c087f2b3 \ - --hash=sha256:bd5e7d2445d1a958c266bfa5d04c39932dc54093fa391736dbfdb0f1929c1fb3 \ - --hash=sha256:c87d98c7c4a69066fd31701c4e10d178a648c2cac3452e62c6b24dc51f9fcc00 \ - --hash=sha256:d2952396dc604544ea7476b33fe87faedc24d666fb0c2d5ac971a2b9576ab871 \ - --hash=sha256:d8797406499f28b5ef791f339594b0b5fdedf54e203b5066675c406ba69d705c \ - --hash=sha256:d9e9913f7bd69e093b81da4535ce27af842e7bf371cde42d1ae9e9bd382dc0e9 \ - --hash=sha256:e2806553238cd076f0a55bddab37a532b53580e699ed8e5606d0de1f856b5205 \ - --hash=sha256:ebab974b1687509e5c973b5c4b8b146683e101e102e17a86bd196ecaa4d099fc \ - --hash=sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d \ - --hash=sha256:f7a1fc29803712f80879b0806cb83ab24ce62fc8daf0569f2204a0cfd7f68ed4 - # via - # google-cloud-storage - # google-resumable-media -google-resumable-media==2.7.2 \ - --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ - --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 - # via google-cloud-storage -googleapis-common-protos==1.66.0 \ - --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ - --hash=sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed - # via google-api-core -idna==3.10 \ - --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ - --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 - # via requests -nox==2024.10.9 \ - --hash=sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab \ - --hash=sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95 - # via -r requirements.in -packaging==24.2 \ - --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ - --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f - # via nox -platformdirs==4.3.6 \ - --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ - --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb - # via virtualenv -proto-plus==1.25.0 \ - --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ - --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 - # via google-api-core -protobuf==5.29.3 \ - --hash=sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f \ - --hash=sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7 \ - --hash=sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888 \ - --hash=sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620 \ - --hash=sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da \ - --hash=sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252 \ - --hash=sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a \ - --hash=sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e \ - --hash=sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107 \ - --hash=sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f \ - --hash=sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84 - # via - # gcp-docuploader - # google-api-core - # googleapis-common-protos - # proto-plus -pyasn1==0.6.1 \ - --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ - --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 - # via - # pyasn1-modules - # rsa -pyasn1-modules==0.4.1 \ - --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ - --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c - # via google-auth -requests==2.32.3 \ - --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ - --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 - # via - # google-api-core - # google-cloud-storage -rsa==4.9 \ - --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ - --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 - # via google-auth -six==1.17.0 \ - --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ - --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 - # via gcp-docuploader -tomli==2.2.1 \ - --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ - --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ - --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ - --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ - --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ - --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ - --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ - --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ - --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ - --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ - --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ - --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ - --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ - --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ - --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ - --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ - --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ - --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ - --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ - --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ - --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ - --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ - --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ - --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ - --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ - --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ - --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ - --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ - --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ - --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ - --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ - --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 - # via nox -urllib3==2.3.0 \ - --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ - --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d - # via requests -virtualenv==20.28.1 \ - --hash=sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb \ - --hash=sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329 - # via nox diff --git a/.kokoro/docs/common.cfg b/.kokoro/docs/common.cfg deleted file mode 100644 index 73480a2ff..000000000 --- a/.kokoro/docs/common.cfg +++ /dev/null @@ -1,66 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# 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" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-storage/.kokoro/publish-docs.sh" -} - -env_vars: { - key: "STAGING_BUCKET" - value: "docs-staging" -} - -env_vars: { - key: "V2_STAGING_BUCKET" - # Push google cloud library docs to the Cloud RAD bucket `docs-staging-v2` - value: "docs-staging-v2" -} - -# It will upload the docker image after successful builds. -env_vars: { - key: "TRAMPOLINE_IMAGE_UPLOAD" - value: "true" -} - -# It will always build the docker image. -env_vars: { - key: "TRAMPOLINE_DOCKERFILE" - value: ".kokoro/docker/docs/Dockerfile" -} - -# Fetch the token needed for reporting release status to GitHub -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "yoshi-automation-github-key" - } - } -} - -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "docuploader_service_account" - } - } -} diff --git a/.kokoro/docs/docs-presubmit.cfg b/.kokoro/docs/docs-presubmit.cfg deleted file mode 100644 index a5a723164..000000000 --- a/.kokoro/docs/docs-presubmit.cfg +++ /dev/null @@ -1,28 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "STAGING_BUCKET" - value: "gcloud-python-test" -} - -env_vars: { - key: "V2_STAGING_BUCKET" - value: "gcloud-python-test" -} - -# We only upload the image in the main `docs` build. -env_vars: { - key: "TRAMPOLINE_IMAGE_UPLOAD" - value: "false" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-storage/.kokoro/build.sh" -} - -# Only run this nox session. -env_vars: { - key: "NOX_SESSION" - value: "docs docfx" -} diff --git a/.kokoro/docs/docs.cfg b/.kokoro/docs/docs.cfg deleted file mode 100644 index 8f43917d9..000000000 --- a/.kokoro/docs/docs.cfg +++ /dev/null @@ -1 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/.kokoro/presubmit/prerelease-deps.cfg b/.kokoro/presubmit/prerelease-deps.cfg deleted file mode 100644 index 3595fb43f..000000000 --- a/.kokoro/presubmit/prerelease-deps.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Only run this nox session. -env_vars: { - key: "NOX_SESSION" - value: "prerelease_deps" -} diff --git a/.kokoro/publish-docs.sh b/.kokoro/publish-docs.sh deleted file mode 100755 index 4ed4aaf13..000000000 --- a/.kokoro/publish-docs.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# Copyright 2024 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 -# -# https://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. - -set -eo pipefail - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -export PATH="${HOME}/.local/bin:${PATH}" - -# build docs -nox -s docs - -# create metadata -python3.10 -m docuploader create-metadata \ - --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ - --version=$(python3.10 setup.py --version) \ - --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ - --distribution-name=$(python3.10 setup.py --name) \ - --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ - --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ - --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) - -cat docs.metadata - -# upload docs -python3.10 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" - - -# docfx yaml files -nox -s docfx - -# create metadata. -python3.10 -m docuploader create-metadata \ - --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ - --version=$(python3.10 setup.py --version) \ - --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ - --distribution-name=$(python3.10 setup.py --name) \ - --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ - --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ - --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) - -cat docs.metadata - -# upload docs -python3.10 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" diff --git a/.kokoro/release.sh b/.kokoro/release.sh deleted file mode 100755 index a15b26b59..000000000 --- a/.kokoro/release.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# Copyright 2024 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 -# -# https://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. - -set -eo pipefail - -# Start the releasetool reporter -python3 -m pip install --require-hashes -r github/python-storage/.kokoro/requirements.txt -python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-2") -cd github/python-storage -python3 setup.py sdist bdist_wheel -twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/.kokoro/release/common.cfg b/.kokoro/release/common.cfg deleted file mode 100644 index 17918dc86..000000000 --- a/.kokoro/release/common.cfg +++ /dev/null @@ -1,49 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# 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.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-storage/.kokoro/release.sh" -} - -# Fetch PyPI password -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "google-cloud-pypi-token-keystore-2" - } - } -} - -# Tokens needed to report release status back to GitHub -env_vars: { - key: "SECRET_MANAGER_KEYS" - value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem, client-library-test-universe-domain-credential" -} - -# Store the packages we uploaded to PyPI. That way, we have a record of exactly -# what we published, which we can use to generate SBOMs and attestations. -action { - define_artifacts { - regex: "github/python-storage/**/*.tar.gz" - strip_prefix: "github/python-storage" - } -} diff --git a/.kokoro/release/release.cfg b/.kokoro/release/release.cfg deleted file mode 100644 index 8f43917d9..000000000 --- a/.kokoro/release/release.cfg +++ /dev/null @@ -1 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/.kokoro/requirements.in b/.kokoro/requirements.in deleted file mode 100644 index fff4d9ce0..000000000 --- a/.kokoro/requirements.in +++ /dev/null @@ -1,11 +0,0 @@ -gcp-docuploader -gcp-releasetool>=2 # required for compatibility with cryptography>=42.x -importlib-metadata -typing-extensions -twine -wheel -setuptools -nox>=2022.11.21 # required to remove dependency on py -charset-normalizer<3 -click<8.1.0 -cryptography>=42.0.5 diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt deleted file mode 100644 index 14466eb39..000000000 --- a/.kokoro/requirements.txt +++ /dev/null @@ -1,537 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes requirements.in -# -argcomplete==3.4.0 \ - --hash=sha256:69a79e083a716173e5532e0fa3bef45f793f4e61096cf52b5a42c0211c8b8aa5 \ - --hash=sha256:c2abcdfe1be8ace47ba777d4fce319eb13bf8ad9dace8d085dcad6eded88057f - # via nox -attrs==23.2.0 \ - --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \ - --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 - # via gcp-releasetool -backports-tarfile==1.2.0 \ - --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ - --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 - # via jaraco-context -cachetools==5.3.3 \ - --hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \ - --hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105 - # via google-auth -certifi==2024.7.4 \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 - # via requests -cffi==1.16.0 \ - --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ - --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ - --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ - --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ - --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ - --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ - --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ - --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ - --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ - --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ - --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ - --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ - --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ - --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ - --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ - --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ - --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ - --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ - --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ - --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ - --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ - --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ - --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ - --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ - --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ - --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ - --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ - --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ - --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ - --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ - --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ - --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ - --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ - --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ - --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ - --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ - --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ - --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ - --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ - --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ - --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ - --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ - --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ - --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ - --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ - --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ - --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ - --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ - --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ - --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ - --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ - --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 - # via cryptography -charset-normalizer==2.1.1 \ - --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ - --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f - # via - # -r requirements.in - # requests -click==8.0.4 \ - --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ - --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb - # via - # -r requirements.in - # gcp-docuploader - # gcp-releasetool -colorlog==6.8.2 \ - --hash=sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44 \ - --hash=sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33 - # via - # gcp-docuploader - # nox -cryptography==42.0.8 \ - --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ - --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ - --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ - --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ - --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ - --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ - --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ - --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ - --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ - --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ - --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ - --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ - --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ - --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ - --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ - --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ - --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ - --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ - --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ - --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ - --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ - --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ - --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ - --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ - --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ - --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ - --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ - --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ - --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ - --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ - --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ - --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e - # via - # -r requirements.in - # gcp-releasetool - # secretstorage -distlib==0.3.8 \ - --hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \ - --hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64 - # via virtualenv -docutils==0.21.2 \ - --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ - --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 - # via readme-renderer -filelock==3.15.4 \ - --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ - --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 - # via virtualenv -gcp-docuploader==0.6.5 \ - --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ - --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea - # via -r requirements.in -gcp-releasetool==2.0.1 \ - --hash=sha256:34314a910c08e8911d9c965bd44f8f2185c4f556e737d719c33a41f6a610de96 \ - --hash=sha256:b0d5863c6a070702b10883d37c4bdfd74bf930fe417f36c0c965d3b7c779ae62 - # via -r requirements.in -google-api-core==2.19.1 \ - --hash=sha256:f12a9b8309b5e21d92483bbd47ce2c445861ec7d269ef6784ecc0ea8c1fa6125 \ - --hash=sha256:f4695f1e3650b316a795108a76a1c416e6afb036199d1c1f1f110916df479ffd - # via - # google-cloud-core - # google-cloud-storage -google-auth==2.31.0 \ - --hash=sha256:042c4702efa9f7d3c48d3a69341c209381b125faa6dbf3ebe56bc7e40ae05c23 \ - --hash=sha256:87805c36970047247c8afe614d4e3af8eceafc1ebba0c679fe75ddd1d575e871 - # via - # gcp-releasetool - # google-api-core - # google-cloud-core - # google-cloud-storage -google-cloud-core==2.4.1 \ - --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ - --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 - # via google-cloud-storage -google-cloud-storage==2.17.0 \ - --hash=sha256:49378abff54ef656b52dca5ef0f2eba9aa83dc2b2c72c78714b03a1a95fe9388 \ - --hash=sha256:5b393bc766b7a3bc6f5407b9e665b2450d36282614b7945e570b3480a456d1e1 - # via gcp-docuploader -google-crc32c==1.5.0 \ - --hash=sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a \ - --hash=sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876 \ - --hash=sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c \ - --hash=sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289 \ - --hash=sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298 \ - --hash=sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02 \ - --hash=sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f \ - --hash=sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2 \ - --hash=sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a \ - --hash=sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb \ - --hash=sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210 \ - --hash=sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5 \ - --hash=sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee \ - --hash=sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c \ - --hash=sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a \ - --hash=sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314 \ - --hash=sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd \ - --hash=sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65 \ - --hash=sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37 \ - --hash=sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4 \ - --hash=sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13 \ - --hash=sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894 \ - --hash=sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31 \ - --hash=sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e \ - --hash=sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709 \ - --hash=sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740 \ - --hash=sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc \ - --hash=sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d \ - --hash=sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c \ - --hash=sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c \ - --hash=sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d \ - --hash=sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906 \ - --hash=sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61 \ - --hash=sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57 \ - --hash=sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c \ - --hash=sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a \ - --hash=sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438 \ - --hash=sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946 \ - --hash=sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7 \ - --hash=sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96 \ - --hash=sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091 \ - --hash=sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae \ - --hash=sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d \ - --hash=sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88 \ - --hash=sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2 \ - --hash=sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd \ - --hash=sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541 \ - --hash=sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728 \ - --hash=sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178 \ - --hash=sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968 \ - --hash=sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346 \ - --hash=sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8 \ - --hash=sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93 \ - --hash=sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7 \ - --hash=sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273 \ - --hash=sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462 \ - --hash=sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94 \ - --hash=sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd \ - --hash=sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e \ - --hash=sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57 \ - --hash=sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b \ - --hash=sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9 \ - --hash=sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a \ - --hash=sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100 \ - --hash=sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325 \ - --hash=sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183 \ - --hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \ - --hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4 - # via - # google-cloud-storage - # google-resumable-media -google-resumable-media==2.7.1 \ - --hash=sha256:103ebc4ba331ab1bfdac0250f8033627a2cd7cde09e7ccff9181e31ba4315b2c \ - --hash=sha256:eae451a7b2e2cdbaaa0fd2eb00cc8a1ee5e95e16b55597359cbc3d27d7d90e33 - # via google-cloud-storage -googleapis-common-protos==1.63.2 \ - --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ - --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 - # via google-api-core -idna==3.7 \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 - # via requests -importlib-metadata==8.0.0 \ - --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ - --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 - # via - # -r requirements.in - # keyring - # twine -jaraco-classes==3.4.0 \ - --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ - --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 - # via keyring -jaraco-context==5.3.0 \ - --hash=sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266 \ - --hash=sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2 - # via keyring -jaraco-functools==4.0.1 \ - --hash=sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664 \ - --hash=sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8 - # via keyring -jeepney==0.8.0 \ - --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ - --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 - # via - # keyring - # secretstorage -jinja2==3.1.4 \ - --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ - --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d - # via gcp-releasetool -keyring==25.2.1 \ - --hash=sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50 \ - --hash=sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b - # via - # gcp-releasetool - # twine -markdown-it-py==3.0.0 \ - --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ - --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb - # via rich -markupsafe==2.1.5 \ - --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ - --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ - --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ - --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ - --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ - --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ - --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ - --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ - --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ - --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ - --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ - --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ - --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ - --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ - --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ - --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ - --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ - --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ - --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ - --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ - --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ - --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ - --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ - --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ - --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ - --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ - --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ - --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ - --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ - --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ - --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ - --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ - --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ - --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ - --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ - --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ - --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ - --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ - --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ - --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ - --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ - --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ - --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ - --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ - --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ - --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ - --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ - --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ - --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ - --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ - --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ - --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ - --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ - --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ - --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ - --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ - --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ - --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ - --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ - --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 - # via jinja2 -mdurl==0.1.2 \ - --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ - --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba - # via markdown-it-py -more-itertools==10.3.0 \ - --hash=sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463 \ - --hash=sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320 - # via - # jaraco-classes - # jaraco-functools -nh3==0.2.18 \ - --hash=sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164 \ - --hash=sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86 \ - --hash=sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b \ - --hash=sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad \ - --hash=sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204 \ - --hash=sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a \ - --hash=sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200 \ - --hash=sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189 \ - --hash=sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f \ - --hash=sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811 \ - --hash=sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844 \ - --hash=sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4 \ - --hash=sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be \ - --hash=sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50 \ - --hash=sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307 \ - --hash=sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe - # via readme-renderer -nox==2024.4.15 \ - --hash=sha256:6492236efa15a460ecb98e7b67562a28b70da006ab0be164e8821177577c0565 \ - --hash=sha256:ecf6700199cdfa9e5ea0a41ff5e6ef4641d09508eda6edb89d9987864115817f - # via -r requirements.in -packaging==24.1 \ - --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ - --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 - # via - # gcp-releasetool - # nox -pkginfo==1.10.0 \ - --hash=sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297 \ - --hash=sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097 - # via twine -platformdirs==4.2.2 \ - --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ - --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 - # via virtualenv -proto-plus==1.24.0 \ - --hash=sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445 \ - --hash=sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12 - # via google-api-core -protobuf==5.27.2 \ - --hash=sha256:0e341109c609749d501986b835f667c6e1e24531096cff9d34ae411595e26505 \ - --hash=sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b \ - --hash=sha256:354d84fac2b0d76062e9b3221f4abbbacdfd2a4d8af36bab0474f3a0bb30ab38 \ - --hash=sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863 \ - --hash=sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470 \ - --hash=sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6 \ - --hash=sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce \ - --hash=sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca \ - --hash=sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5 \ - --hash=sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e \ - --hash=sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714 - # via - # gcp-docuploader - # gcp-releasetool - # google-api-core - # googleapis-common-protos - # proto-plus -pyasn1==0.6.0 \ - --hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \ - --hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473 - # via - # pyasn1-modules - # rsa -pyasn1-modules==0.4.0 \ - --hash=sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6 \ - --hash=sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b - # via google-auth -pycparser==2.22 \ - --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ - --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc - # via cffi -pygments==2.18.0 \ - --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ - --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a - # via - # readme-renderer - # rich -pyjwt==2.8.0 \ - --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \ - --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320 - # via gcp-releasetool -pyperclip==1.9.0 \ - --hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310 - # via gcp-releasetool -python-dateutil==2.9.0.post0 \ - --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ - --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 - # via gcp-releasetool -readme-renderer==44.0 \ - --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151 \ - --hash=sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1 - # via twine -requests==2.32.3 \ - --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ - --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 - # via - # gcp-releasetool - # google-api-core - # google-cloud-storage - # requests-toolbelt - # twine -requests-toolbelt==1.0.0 \ - --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ - --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 - # via twine -rfc3986==2.0.0 \ - --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ - --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c - # via twine -rich==13.7.1 \ - --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ - --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 - # via twine -rsa==4.9 \ - --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ - --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 - # via google-auth -secretstorage==3.3.3 \ - --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ - --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 - # via keyring -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 - # via - # gcp-docuploader - # python-dateutil -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via nox -twine==5.1.1 \ - --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ - --hash=sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db - # via -r requirements.in -typing-extensions==4.12.2 \ - --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ - --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 - # via -r requirements.in -urllib3==2.2.2 \ - --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ - --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 - # via - # requests - # twine -virtualenv==20.26.6 \ - --hash=sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48 \ - --hash=sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2 - # via nox -wheel==0.43.0 \ - --hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \ - --hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81 - # via -r requirements.in -zipp==3.19.2 \ - --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ - --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c - # via importlib-metadata - -# The following packages are considered to be unsafe in a requirements file: -setuptools==70.2.0 \ - --hash=sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05 \ - --hash=sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1 - # via -r requirements.in diff --git a/CHANGELOG.md b/CHANGELOG.md index fefb84f50..8e66795a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ [1]: https://pypi.org/project/google-cloud-storage/#history +## [3.1.1](https://github.com/googleapis/python-storage/compare/v3.1.0...v3.1.1) (2025-06-13) + + +### Bug Fixes + +* Add a check for partial response data ([#1487](https://github.com/googleapis/python-storage/issues/1487)) ([7e0412a](https://github.com/googleapis/python-storage/commit/7e0412a4fdfedcaa4683d5ef7d9155d5d58efa11)) +* Add trove classifier for Python 3.13 ([0100916](https://github.com/googleapis/python-storage/commit/01009164beaab8931a1e1684966e3060edcf77b7)) +* **deps:** Require google-crc32c >= 1.1.3 ([0100916](https://github.com/googleapis/python-storage/commit/01009164beaab8931a1e1684966e3060edcf77b7)) +* **deps:** Require protobuf >= 3.20.2, < 7.0.0 ([0100916](https://github.com/googleapis/python-storage/commit/01009164beaab8931a1e1684966e3060edcf77b7)) +* **deps:** Require requests >= 2.22.0 ([0100916](https://github.com/googleapis/python-storage/commit/01009164beaab8931a1e1684966e3060edcf77b7)) +* Remove setup.cfg configuration for creating universal wheels ([#1448](https://github.com/googleapis/python-storage/issues/1448)) ([d3b6b3f](https://github.com/googleapis/python-storage/commit/d3b6b3f96a6f94aa7c371902f48d1363ae6bfb5c)) +* Resolve issue where pre-release versions of dependencies are installed ([0100916](https://github.com/googleapis/python-storage/commit/01009164beaab8931a1e1684966e3060edcf77b7)) +* Segmentation fault in tink while writing data ([#1490](https://github.com/googleapis/python-storage/issues/1490)) ([2a46c0b](https://github.com/googleapis/python-storage/commit/2a46c0b9e6ec561ae3151d2a9a80c7452634487e)) + + +### Documentation + +* Move quickstart to top of readme ([#1451](https://github.com/googleapis/python-storage/issues/1451)) ([53257cf](https://github.com/googleapis/python-storage/commit/53257cf20a4de3810156ae9576a7092f5527df98)) +* Update README to break infinite redirect loop ([#1450](https://github.com/googleapis/python-storage/issues/1450)) ([03f1594](https://github.com/googleapis/python-storage/commit/03f1594eb90ea1298a3a23927537c86ac35d33d5)) + ## [3.1.0](https://github.com/googleapis/python-storage/compare/v3.0.0...v3.1.0) (2025-02-27) @@ -79,7 +99,7 @@ Please consult the README for details on this major version release. ### Bug Fixes -* Properly escape URL construction for XML MPU API ([#1333](https://github.com/googleapis/python-storage/issues/1333)) ([bf4d0e0](https://github.com/googleapis/python-storage/commit/bf4d0e0a2ef1d608d679c22b13d8f5d90b39c7b2)) +* Properly escape URL construction for XML MPU API, fixing a path traversal issue that allowed uploads to unintended buckets. Reported by @jdomeracki. ([#1333](https://github.com/googleapis/python-storage/issues/1333)) ([bf4d0e0](https://github.com/googleapis/python-storage/commit/bf4d0e0a2ef1d608d679c22b13d8f5d90b39c7b2)) ## [2.18.0](https://github.com/googleapis/python-storage/compare/v2.17.0...v2.18.0) (2024-07-09) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d53ad8707..316d8b266 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: - 3.7, 3.8, 3.9, 3.10, 3.11 and 3.12 on both UNIX and Windows. + 3.7, 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should diff --git a/README.rst b/README.rst index 4a94b178f..a7db13a25 100644 --- a/README.rst +++ b/README.rst @@ -8,6 +8,8 @@ allows world-wide storage and retrieval of any amount of data at any time. You c 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. +**NOTE**: `3.0 Major Version Notes`_ are available. Feedback welcome. + A comprehensive list of changes in each version may be found in the `CHANGELOG`_. - `Product Documentation`_ @@ -29,7 +31,7 @@ Google APIs Client Libraries, in `Client Libraries Explained`_. .. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-storage.svg :target: https://pypi.org/project/google-cloud-storage/ .. _Google Cloud Storage: https://cloud.google.com/storage -.. _Client Library Documentation: https://cloud.google.com/python/docs/reference/storage/latest +.. _Client Library Documentation: https://cloud.google.com/python/docs/reference/storage/latest/summary_overview .. _Product Documentation: https://cloud.google.com/storage .. _CHANGELOG: https://github.com/googleapis/python-storage/blob/main/CHANGELOG.md .. _github.com/googleapis/python-storage: https://github.com/googleapis/python-storage @@ -37,75 +39,6 @@ Google APIs Client Libraries, in `Client Libraries Explained`_. .. _Storage Control API: https://cloud.google.com/storage/docs/reference/rpc/google.storage.control.v2 .. _Client Libraries Explained: https://cloud.google.com/apis/docs/client-libraries-explained -3.0 Major Version Notes ------------------------ - -Feedback Welcome -~~~~~~~~~~~~~~~~ - -If you experience that backwards compatibility for your application is broken -with this major version release, please let us know through the Github issues -system. While some breaks of backwards compatibility may be unavoidable due to -new features in the major version release, we will do our best to minimize -them. Thank you. - -Exception Handling -~~~~~~~~~~~~~~~~~~ - -In Python Storage 3.0, the dependency ``google-resumable-media`` was integrated. -The ``google-resumable-media`` dependency included exceptions -``google.resumable_media.common.InvalidResponse`` and -``google.resumable_media.common.DataCorruption``, which were often imported -directly in user application code. The replacements for these exceptions are -``google.cloud.storage.exceptions.InvalidResponse`` and -``google.cloud.storage.exceptions.DataCorruption``. Please update application code -to import and use these exceptions instead. - -For backwards compatibility, if ``google-resumable-media`` is installed, the new -exceptions will be defined as subclasses of the old exceptions, so applications -should continue to work without modification. This backwards compatibility -feature may be removed in a future major version update. - -Some users may be using the original exception classes from the -``google-resumable-media`` library without explicitly installing that library. So -as not to break user applications following this pattern, -``google-resumable-media`` is still in the list of dependencies in this package's -setup.py file. Applications which do not import directly from -``google-resumable-media`` can safely disregard this dependency. -This backwards compatibility feature **will be removed** in a future major -version update. Please migrate to using the ``google.cloud.storage.exceptions`` -classes as above. - -Checksum Defaults -~~~~~~~~~~~~~~~~~ - -In Python Storage 3.0, uploads and downloads now have a default of "auto" where -applicable. "Auto" will use crc32c checksums, except for unusual cases where the -fast (C extension) crc32c implementation is not available, in which case it will -use md5 instead. Before Python Storage 3.0, the default was md5 for most -downloads and None for most uploads. Note that ranged downloads ("start" or -"end" set) still do not support any checksumming, and some features in -``transfer_manager.py`` still support crc32c only. - -Note: The method ``Blob.upload_from_file()`` requires a file in bytes mode, but -when checksum is set to None, as was the previous default, would not throw an -error if passed a file in string mode under some circumstances. With the new -defaults, it will now raise a TypeError. Please use a file opened in bytes -reading mode as required. - -Miscellaneous -~~~~~~~~~~~~~ - -- The ``BlobWriter`` class now attempts to terminate an ongoing resumable upload if - the writer exits with an exception. -- Retry behavior is now identical between media operations (uploads and - downloads) and other operations, and custom predicates are now supported for - media operations as well. -- ``Blob.download_as_filename()`` will now delete the empty file if it results in a - google.cloud.exceptions.NotFound exception (HTTP 404). -- Previously, object upload, metadata update, and delete methods had retries - disabled by default unless the generation or metageneration was specified in - the request. This has now changed so that retries are enabled by default. Quick Start ----------- @@ -186,6 +119,26 @@ Windows pip install google-cloud-storage +Example Usage +~~~~~~~~~~~~~ + +.. code-block:: python + + # 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(f"Bucket {bucket.name} created.") + + Tracing With OpenTelemetry ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -240,6 +193,77 @@ For a list of libraries that can be instrumented, refer to the `OpenTelemetry Re .. _Google Cloud Trace: https://cloud.google.com/trace +3.0 Major Version Notes +----------------------- + +Feedback Welcome +~~~~~~~~~~~~~~~~ + +If you experience that backwards compatibility for your application is broken +with this major version release, please let us know through the Github issues +system. While some breaks of backwards compatibility may be unavoidable due to +new features in the major version release, we will do our best to minimize +them. Thank you. + +Exception Handling +~~~~~~~~~~~~~~~~~~ + +In Python Storage 3.0, the dependency ``google-resumable-media`` was integrated. +The ``google-resumable-media`` dependency included exceptions +``google.resumable_media.common.InvalidResponse`` and +``google.resumable_media.common.DataCorruption``, which were often imported +directly in user application code. The replacements for these exceptions are +``google.cloud.storage.exceptions.InvalidResponse`` and +``google.cloud.storage.exceptions.DataCorruption``. Please update application code +to import and use these exceptions instead. + +For backwards compatibility, if ``google-resumable-media`` is installed, the new +exceptions will be defined as subclasses of the old exceptions, so applications +should continue to work without modification. This backwards compatibility +feature may be removed in a future major version update. + +Some users may be using the original exception classes from the +``google-resumable-media`` library without explicitly installing that library. So +as not to break user applications following this pattern, +``google-resumable-media`` is still in the list of dependencies in this package's +setup.py file. Applications which do not import directly from +``google-resumable-media`` can safely disregard this dependency. +This backwards compatibility feature **will be removed** in a future major +version update. Please migrate to using the ``google.cloud.storage.exceptions`` +classes as above. + +Checksum Defaults +~~~~~~~~~~~~~~~~~ + +In Python Storage 3.0, uploads and downloads now have a default of "auto" where +applicable. "Auto" will use crc32c checksums, except for unusual cases where the +fast (C extension) crc32c implementation is not available, in which case it will +use md5 instead. Before Python Storage 3.0, the default was md5 for most +downloads and None for most uploads. Note that ranged downloads ("start" or +"end" set) still do not support any checksumming, and some features in +``transfer_manager.py`` still support crc32c only. + +Note: The method ``Blob.upload_from_file()`` requires a file in bytes mode, but +when checksum is set to None, as was the previous default, would not throw an +error if passed a file in string mode under some circumstances. With the new +defaults, it will now raise a TypeError. Please use a file opened in bytes +reading mode as required. + +Miscellaneous +~~~~~~~~~~~~~ + +- The ``BlobWriter`` class now attempts to terminate an ongoing resumable upload if + the writer exits with an exception. +- Retry behavior is now identical between media operations (uploads and + downloads) and other operations, and custom predicates are now supported for + media operations as well. +- ``Blob.download_as_filename()`` will now delete the empty file if it results in a + google.cloud.exceptions.NotFound exception (HTTP 404). +- Previously, object upload, metadata update, and delete methods had retries + disabled by default unless the generation or metageneration was specified in + the request. This has now changed so that retries are enabled by default. + + Next Steps ~~~~~~~~~~ diff --git a/docs/retry_timeout.rst b/docs/retry_timeout.rst index c9911a3f2..44d3d8a58 100644 --- a/docs/retry_timeout.rst +++ b/docs/retry_timeout.rst @@ -112,8 +112,8 @@ explicit policy in your code. from google.cloud.storage.retry import DEFAULT_RETRY - # Customize retry with a deadline of 500 seconds (default=120 seconds). - modified_retry = DEFAULT_RETRY.with_deadline(500.0) + # Customize retry with a timeout of 500 seconds (default=120 seconds). + modified_retry = DEFAULT_RETRY.with_timeout(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). diff --git a/google/cloud/storage/_media/requests/download.py b/google/cloud/storage/_media/requests/download.py index 2c1b9392c..67535f923 100644 --- a/google/cloud/storage/_media/requests/download.py +++ b/google/cloud/storage/_media/requests/download.py @@ -43,6 +43,12 @@ Please restart the download. """ +_RESPONSE_HEADERS_INFO = """\ +The X-Goog-Stored-Content-Length is {}. The X-Goog-Stored-Content-Encoding is {}. +The download request read {} bytes of data. +If the download was incomplete, please check the network connection and restart the download. +""" + class Download(_request_helpers.RequestsMixin, _download.Download): """Helper to manage downloading a resource from a Google API. @@ -141,13 +147,30 @@ def _write_to_stream(self, response): ): actual_checksum = _helpers.prepare_checksum_digest(checksum_object.digest()) if actual_checksum != expected_checksum: - msg = _CHECKSUM_MISMATCH.format( - self.media_url, - expected_checksum, - actual_checksum, - checksum_type=self.checksum.upper(), + headers = self._get_headers(response) + x_goog_encoding = headers.get("x-goog-stored-content-encoding") + x_goog_length = headers.get("x-goog-stored-content-length") + content_length_msg = _RESPONSE_HEADERS_INFO.format( + x_goog_length, x_goog_encoding, self._bytes_downloaded ) - raise DataCorruption(response, msg) + if ( + x_goog_length + and self._bytes_downloaded < int(x_goog_length) + and x_goog_encoding != "gzip" + ): + # The library will attempt to trigger a retry by raising a ConnectionError, if + # (a) bytes_downloaded is less than response header x-goog-stored-content-length, and + # (b) the object is not gzip-compressed when stored in Cloud Storage. + raise ConnectionError(content_length_msg) + else: + msg = _CHECKSUM_MISMATCH.format( + self.media_url, + expected_checksum, + actual_checksum, + checksum_type=self.checksum.upper(), + ) + msg += content_length_msg + raise DataCorruption(response, msg) def consume( self, @@ -339,13 +362,30 @@ def _write_to_stream(self, response): actual_checksum = _helpers.prepare_checksum_digest(checksum_object.digest()) if actual_checksum != expected_checksum: - msg = _CHECKSUM_MISMATCH.format( - self.media_url, - expected_checksum, - actual_checksum, - checksum_type=self.checksum.upper(), + headers = self._get_headers(response) + x_goog_encoding = headers.get("x-goog-stored-content-encoding") + x_goog_length = headers.get("x-goog-stored-content-length") + content_length_msg = _RESPONSE_HEADERS_INFO.format( + x_goog_length, x_goog_encoding, self._bytes_downloaded ) - raise DataCorruption(response, msg) + if ( + x_goog_length + and self._bytes_downloaded < int(x_goog_length) + and x_goog_encoding != "gzip" + ): + # The library will attempt to trigger a retry by raising a ConnectionError, if + # (a) bytes_downloaded is less than response header x-goog-stored-content-length, and + # (b) the object is not gzip-compressed when stored in Cloud Storage. + raise ConnectionError(content_length_msg) + else: + msg = _CHECKSUM_MISMATCH.format( + self.media_url, + expected_checksum, + actual_checksum, + checksum_type=self.checksum.upper(), + ) + msg += content_length_msg + raise DataCorruption(response, msg) def consume( self, diff --git a/google/cloud/storage/fileio.py b/google/cloud/storage/fileio.py index 2b4754648..289a09cee 100644 --- a/google/cloud/storage/fileio.py +++ b/google/cloud/storage/fileio.py @@ -477,7 +477,7 @@ def write(self, b): self._buffer.seek(0, io.SEEK_END) pos = self._buffer.write(b) self._buffer.seek(bookmark) - return self._cursor + pos + return pos def read(self, size=-1): """Read and move the cursor.""" diff --git a/google/cloud/storage/version.py b/google/cloud/storage/version.py index 6ce498ba5..fa35f1da3 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__ = "3.1.0" +__version__ = "3.1.1" diff --git a/noxfile.py b/noxfile.py index 384880848..2a7614331 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,11 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Generated by synthtool. DO NOT EDIT! - from __future__ import absolute_import import os import pathlib +import re import shutil import nox @@ -29,16 +28,27 @@ DEFAULT_PYTHON_VERSION = "3.8" SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"] -UNIT_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] +UNIT_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] CONFORMANCE_TEST_PYTHON_VERSIONS = ["3.8"] -_DEFAULT_STORAGE_HOST = "https://storage.googleapis.com" - CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() # Error if a python version is missing nox.options.error_on_missing_interpreters = True +nox.options.sessions = [ + "blacken", + "conftest_retry", + "docfx", + "docs", + "lint", + "lint_setup_py", + "system", + "unit", + # cover must be last to avoid error `No data to report` + "cover", +] + @nox.session(python=DEFAULT_PYTHON_VERSION) def lint(session): @@ -159,8 +169,8 @@ def system(session): session.install( "google-cloud-testutils", "google-cloud-iam", - "google-cloud-pubsub < 2.0.0", - "google-cloud-kms < 2.0dev", + "google-cloud-pubsub", + "google-cloud-kms", "brotli", "-c", constraints_path, @@ -300,3 +310,81 @@ def docfx(session): os.path.join("docs", ""), os.path.join("docs", "_build", "html", ""), ) + + +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[-1]) +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def prerelease_deps(session, protobuf_implementation): + """Run all tests with prerelease versions of dependencies installed.""" + + # Install all test dependencies + session.install("mock", "pytest", "pytest-cov", "brotli") + + # Install dependencies needed for system tests + session.install( + "google-cloud-pubsub", + "google-cloud-kms", + "google-cloud-testutils", + "google-cloud-iam", + ) + + # Install all dependencies + session.install("-e", ".[protobuf, tracing]") + + prerel_deps = [ + "google-api-core", + "google-auth", + "google-cloud-core", + "google-crc32c", + "google-resumable-media", + "opentelemetry-api", + "protobuf", + ] + + package_namespaces = { + "google-api-core": "google.api_core", + "google-auth": "google.auth", + "google-cloud-core": "google.cloud.version", + "opentelemetry-api": "opentelemetry.version", + "protobuf": "google.protobuf", + } + + for dep in prerel_deps: + session.install("--pre", "--no-deps", "--upgrade", dep) + print(f"Installed {dep}") + + version_namespace = package_namespaces.get(dep) + + if version_namespace: + session.run( + "python", + "-c", + f"import {version_namespace}; print({version_namespace}.__version__)", + ) + # Remaining dependencies + other_deps = [ + "requests", + ] + session.install(*other_deps) + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) + + session.run( + "py.test", + "--verbose", + f"--junitxml=system_{session.python}_sponge_log.xml", + os.path.join("tests", "system"), + *session.posargs, + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/owlbot.py b/owlbot.py index 8bd9de751..08ddbb8fc 100644 --- a/owlbot.py +++ b/owlbot.py @@ -26,12 +26,6 @@ templated_files = common.py_library( cov_level=100, split_system_tests=True, - system_test_external_dependencies=[ - "google-cloud-iam", - "google-cloud-pubsub < 2.0.0", - # See: https://github.com/googleapis/python-storage/issues/226 - "google-cloud-kms < 2.0dev", - ], intersphinx_dependencies={ # python-requests url temporary change related to # https://github.com/psf/requests/issues/6140#issuecomment-1135071992 @@ -48,7 +42,8 @@ "README.rst", ".kokoro/continuous/continuous.cfg", ".kokoro/presubmit/system-3.8.cfg", - ".kokoro/samples/python3.6", # remove python 3.6 support + ".kokoro/presubmit/prerelease-deps.cfg", + ".kokoro/continuous/prerelease-deps.cfg", ".github/blunderbuss.yml", # blunderbuss assignment to python squad ".github/workflows", # exclude gh actions as credentials are needed for tests ".github/release-please.yml", # special support for a python2 branch in this repo @@ -84,12 +79,6 @@ """omit = .nox/*""") -s.replace( - ".kokoro/release/common.cfg", - 'value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem"', - 'value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem, client-library-test-universe-domain-credential"' -) - python.py_samples(skip_readmes=True) s.shell.run(["nox", "-s", "blacken"], hide_output=False) diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py index 17a05b9f2..7eba203a4 100644 --- a/samples/snippets/noxfile_config.py +++ b/samples/snippets/noxfile_config.py @@ -73,12 +73,15 @@ def get_cloud_kms_key(): if session == 'py-3.12': return ('projects/python-docs-samples-tests-312/locations/us/' 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key') + if session == 'py-3.13': + return ('projects/python-docs-samples-tests-313/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", "3.6", "3.7", "3.11", "3.12"], + 'ignored_versions': ["2.7", "3.6", "3.7", "3.11", "3.12", "3.13"], # 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 diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt index 7f13e54c9..5644295d0 100644 --- a/samples/snippets/requirements-test.txt +++ b/samples/snippets/requirements-test.txt @@ -1,4 +1,4 @@ pytest===7.4.4; python_version == '3.7' -pytest==8.3.4; python_version >= '3.8' -mock==5.1.0 +pytest==8.3.5; python_version >= '3.8' +mock==5.2.0 backoff==2.2.1 diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index a5a006ab2..751f8cfbe 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,5 +1,5 @@ -google-cloud-pubsub==2.27.2 -google-cloud-storage==2.19.0 +google-cloud-pubsub==2.29.0 +google-cloud-storage==3.1.0 pandas===1.3.5; python_version == '3.7' pandas===2.0.3; python_version == '3.8' pandas==2.2.3; python_version >= '3.9' diff --git a/samples/snippets/snippets_test.py b/samples/snippets/snippets_test.py index 339693dd8..3fe377b6b 100644 --- a/samples/snippets/snippets_test.py +++ b/samples/snippets/snippets_test.py @@ -25,6 +25,7 @@ import requests import storage_add_bucket_label +import storage_async_download import storage_async_upload import storage_batch_request import storage_bucket_delete_default_kms_key @@ -43,6 +44,7 @@ import storage_delete_file import storage_delete_file_archived_generation import storage_disable_bucket_lifecycle_management +import storage_disable_soft_delete import storage_disable_versioning import storage_download_byte_range import storage_download_file @@ -60,21 +62,29 @@ import storage_get_bucket_metadata import storage_get_metadata import storage_get_service_account +import storage_get_soft_delete_policy +import storage_get_soft_deleted_bucket import storage_list_buckets import storage_list_file_archived_generations import storage_list_files import storage_list_files_with_prefix +import storage_list_soft_deleted_buckets +import storage_list_soft_deleted_object_versions +import storage_list_soft_deleted_objects 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_restore_object +import storage_restore_soft_deleted_bucket import storage_set_autoclass import storage_set_bucket_default_kms_key import storage_set_client_endpoint -import storage_set_object_retention_policy import storage_set_metadata +import storage_set_object_retention_policy +import storage_set_soft_delete_policy import storage_trace_quickstart import storage_transfer_manager_download_bucket import storage_transfer_manager_download_chunks_concurrently @@ -130,6 +140,34 @@ def test_bucket(): bucket.delete(force=True) +@pytest.fixture(scope="module") +def test_soft_deleted_bucket(): + """Yields a soft-deleted bucket.""" + bucket = None + while bucket is None or bucket.exists(): + bucket_name = f"storage-snippets-test-{uuid.uuid4()}" + bucket = storage.Client().bucket(bucket_name) + bucket.create() + # [Assumption] Bucket is created with default policy , ie soft delete on. + bucket.delete() + yield bucket + + +@pytest.fixture(scope="function") +def test_soft_delete_enabled_bucket(): + """Yields a bucket with soft-delete enabled that is deleted after the test completes.""" + bucket = None + while bucket is None or bucket.exists(): + bucket_name = f"storage-snippets-test-{uuid.uuid4()}" + bucket = storage.Client().bucket(bucket_name) + # Soft-delete retention for 7 days (minimum allowed by API) + bucket.soft_delete_policy.retention_duration_seconds = 7 * 24 * 60 * 60 + # Soft-delete requires a region + bucket.create(location="US-CENTRAL1") + 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 @@ -194,6 +232,12 @@ def test_list_buckets(test_bucket, capsys): assert test_bucket.name in out +def test_list_soft_deleted_buckets(test_soft_deleted_bucket, capsys): + storage_list_soft_deleted_buckets.list_soft_deleted_buckets() + out, _ = capsys.readouterr() + assert test_soft_deleted_bucket.name in out + + def test_list_blobs(test_blob, capsys): storage_list_files.list_blobs(test_blob.bucket.name) out, _ = capsys.readouterr() @@ -206,6 +250,22 @@ def test_bucket_metadata(test_bucket, capsys): assert test_bucket.name in out +def test_get_soft_deleted_bucket(test_soft_deleted_bucket, capsys): + storage_get_soft_deleted_bucket.get_soft_deleted_bucket( + test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation + ) + out, _ = capsys.readouterr() + assert test_soft_deleted_bucket.name in out + + +def test_restore_soft_deleted_bucket(test_soft_deleted_bucket, capsys): + storage_restore_soft_deleted_bucket.restore_bucket( + test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation + ) + out, _ = capsys.readouterr() + assert test_soft_deleted_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" @@ -267,6 +327,21 @@ def test_async_upload(bucket, capsys): assert f"Uploaded 3 files to bucket {bucket.name}" in out +def test_async_download(test_bucket, capsys): + object_count = 3 + source_files = [f"async_sample_blob_{x}" for x in range(object_count)] + for source in source_files: + blob = test_bucket.blob(source) + blob.upload_from_string(source) + + asyncio.run( + storage_async_download.async_download_blobs(test_bucket.name, *source_files) + ) + out, _ = capsys.readouterr() + for x in range(object_count): + assert f"Downloaded storage object async_sample_blob_{x}" in out + + def test_download_byte_range(test_blob): with tempfile.NamedTemporaryFile() as dest_file: storage_download_byte_range.download_byte_range( @@ -829,7 +904,10 @@ def test_object_retention_policy(test_bucket_create, capsys): test_bucket_create.name ) out, _ = capsys.readouterr() - assert f"Created bucket {test_bucket_create.name} with object retention enabled setting" in out + assert ( + f"Created bucket {test_bucket_create.name} with object retention enabled setting" + in out + ) blob_name = "test_object_retention" storage_set_object_retention_policy.set_object_retention_policy( @@ -850,7 +928,10 @@ def test_create_bucket_hierarchical_namespace(test_bucket_create, capsys): test_bucket_create.name ) out, _ = capsys.readouterr() - assert f"Created bucket {test_bucket_create.name} with hierarchical namespace enabled" in out + assert ( + f"Created bucket {test_bucket_create.name} with hierarchical namespace enabled" + in out + ) def test_storage_trace_quickstart(test_bucket, capsys): @@ -863,3 +944,96 @@ def test_storage_trace_quickstart(test_bucket, capsys): assert ( f"Downloaded storage object {blob_name} from bucket {test_bucket.name}" in out ) + + +def test_storage_disable_soft_delete(test_soft_delete_enabled_bucket, capsys): + bucket_name = test_soft_delete_enabled_bucket.name + storage_disable_soft_delete.disable_soft_delete(bucket_name) + out, _ = capsys.readouterr() + assert f"Soft-delete policy is disabled for bucket {bucket_name}" in out + + +def test_storage_get_soft_delete_policy(test_soft_delete_enabled_bucket, capsys): + bucket_name = test_soft_delete_enabled_bucket.name + storage_get_soft_delete_policy.get_soft_delete_policy(bucket_name) + out, _ = capsys.readouterr() + assert f"Soft-delete policy for {bucket_name}" in out + assert "Object soft-delete policy is enabled" in out + assert "Object retention duration: " in out + assert "Policy effective time: " in out + + # Disable the soft-delete policy + test_soft_delete_enabled_bucket.soft_delete_policy.retention_duration_seconds = 0 + test_soft_delete_enabled_bucket.patch() + storage_get_soft_delete_policy.get_soft_delete_policy(bucket_name) + out, _ = capsys.readouterr() + assert f"Soft-delete policy for {bucket_name}" in out + assert "Object soft-delete policy is disabled" in out + + +def test_storage_set_soft_delete_policy(test_soft_delete_enabled_bucket, capsys): + bucket_name = test_soft_delete_enabled_bucket.name + retention_duration_seconds = 10 * 24 * 60 * 60 # 10 days + storage_set_soft_delete_policy.set_soft_delete_policy( + bucket_name, retention_duration_seconds + ) + out, _ = capsys.readouterr() + assert ( + f"Soft delete policy for bucket {bucket_name} was set to {retention_duration_seconds} seconds retention period" + in out + ) + + +def test_storage_list_soft_deleted_objects(test_soft_delete_enabled_bucket, capsys): + bucket_name = test_soft_delete_enabled_bucket.name + blob_name = f"test_object_{uuid.uuid4().hex}.txt" + blob_content = "This object will be soft-deleted for listing." + blob = test_soft_delete_enabled_bucket.blob(blob_name) + blob.upload_from_string(blob_content) + blob_generation = blob.generation + + blob.delete() # Soft-delete the object + storage_list_soft_deleted_objects.list_soft_deleted_objects(bucket_name) + out, _ = capsys.readouterr() + assert f"Name: {blob_name}, Generation: {blob_generation}" in out + + +def test_storage_list_soft_deleted_object_versions( + test_soft_delete_enabled_bucket, capsys +): + bucket_name = test_soft_delete_enabled_bucket.name + blob_name = f"test_object_{uuid.uuid4().hex}.txt" + blob_content = "This object will be soft-deleted for version listing." + blob = test_soft_delete_enabled_bucket.blob(blob_name) + blob.upload_from_string(blob_content) + blob_generation = blob.generation + + blob.delete() # Soft-delete the object + storage_list_soft_deleted_object_versions.list_soft_deleted_object_versions( + bucket_name, blob_name + ) + out, _ = capsys.readouterr() + assert f"Version ID: {blob_generation}" in out + + +def test_storage_restore_soft_deleted_object(test_soft_delete_enabled_bucket, capsys): + bucket_name = test_soft_delete_enabled_bucket.name + blob_name = f"test-restore-sd-obj-{uuid.uuid4().hex}.txt" + blob_content = "This object will be soft-deleted and restored." + blob = test_soft_delete_enabled_bucket.blob(blob_name) + blob.upload_from_string(blob_content) + blob_generation = blob.generation + + blob.delete() # Soft-delete the object + storage_restore_object.restore_soft_deleted_object( + bucket_name, blob_name, blob_generation + ) + out, _ = capsys.readouterr() + assert ( + f"Soft-deleted object {blob_name} is restored in the bucket {bucket_name}" + in out + ) + + # Verify the restoration + blob = test_soft_delete_enabled_bucket.get_blob(blob_name) + assert blob is not None diff --git a/samples/snippets/storage_async_download.py b/samples/snippets/storage_async_download.py new file mode 100755 index 000000000..ed8f3f304 --- /dev/null +++ b/samples/snippets/storage_async_download.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +# Copyright 2025 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 asyncio +import argparse + +"""Sample that asynchronously downloads multiple files from GCS to application's memory. +""" + + +# [START storage_async_download] +# This sample can be run by calling `async.run(async_download_blobs('bucket_name', ['file1', 'file2']))` +async def async_download_blobs(bucket_name, *file_names): + """Downloads a number of files in parallel from the bucket. + """ + # The ID of your GCS bucket. + # bucket_name = "your-bucket-name" + + # The list of files names to download, these files should be present in bucket. + # file_names = ["myfile1", "myfile2"] + + import asyncio + from google.cloud import storage + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + loop = asyncio.get_running_loop() + + tasks = [] + for file_name in file_names: + blob = bucket.blob(file_name) + # The first arg, None, tells it to use the default loops executor + tasks.append(loop.run_in_executor(None, blob.download_as_bytes)) + + # If the method returns a value (such as download_as_bytes), gather will return the values + _ = await asyncio.gather(*tasks) + for file_name in file_names: + print(f"Downloaded storage object {file_name}") + + +# [END storage_async_download] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-b', '--bucket_name', type=str, dest='bucket_name', help='provide the name of the GCS bucket') + parser.add_argument( + '-f', '--file_name', + action='append', + type=str, + dest='file_names', + help='Example: -f file1.txt or --file_name my_fav.mp4 . It can be used multiple times.' + ) + args = parser.parse_args() + + asyncio.run(async_download_blobs(args.bucket_name, *args.file_names)) diff --git a/samples/snippets/storage_configure_retries.py b/samples/snippets/storage_configure_retries.py index ef1e422b6..25c2529a4 100644 --- a/samples/snippets/storage_configure_retries.py +++ b/samples/snippets/storage_configure_retries.py @@ -38,16 +38,15 @@ def configure_retries(bucket_name, blob_name): 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 a timeout of 500 seconds (default=120 seconds). + modified_retry = DEFAULT_RETRY.with_timeout(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. + # blob.delete() uses DEFAULT_RETRY by default. + # Pass in modified_retry to override the default retry behavior. print( f"The following library method is customized to be retried according to the following configurations: {modified_retry}" ) diff --git a/samples/snippets/storage_disable_soft_delete.py b/samples/snippets/storage_disable_soft_delete.py new file mode 100644 index 000000000..dc2447ae8 --- /dev/null +++ b/samples/snippets/storage_disable_soft_delete.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2025 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_disable_soft_delete] +from google.cloud import storage + + +def disable_soft_delete(bucket_name): + """Disable soft-delete policy for the bucket.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + # Setting the retention duration to 0 disables soft-delete. + bucket.soft_delete_policy.retention_duration_seconds = 0 + bucket.patch() + + print(f"Soft-delete policy is disabled for bucket {bucket_name}") + + +# [END storage_disable_soft_delete] + +if __name__ == "__main__": + disable_soft_delete(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_soft_delete_policy.py b/samples/snippets/storage_get_soft_delete_policy.py new file mode 100644 index 000000000..99c4e572a --- /dev/null +++ b/samples/snippets/storage_get_soft_delete_policy.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# Copyright 2025 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_soft_delete_policy] +from google.cloud import storage + + +def get_soft_delete_policy(bucket_name): + """Gets the soft-delete policy of the bucket""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + print(f"Soft-delete policy for {bucket_name}") + if ( + bucket.soft_delete_policy + and bucket.soft_delete_policy.retention_duration_seconds + ): + print("Object soft-delete policy is enabled") + print( + f"Object retention duration: {bucket.soft_delete_policy.retention_duration_seconds} seconds" + ) + print(f"Policy effective time: {bucket.soft_delete_policy.effective_time}") + else: + print("Object soft-delete policy is disabled") + + +# [END storage_get_soft_delete_policy] + +if __name__ == "__main__": + get_soft_delete_policy(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_soft_deleted_bucket.py b/samples/snippets/storage_get_soft_deleted_bucket.py new file mode 100644 index 000000000..2b7955046 --- /dev/null +++ b/samples/snippets/storage_get_soft_deleted_bucket.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2025 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_soft_deleted_bucket] + +from google.cloud import storage + + +def get_soft_deleted_bucket(bucket_name, generation): + """Prints out a soft-deleted bucket's metadata. + + Args: + bucket_name: str + The name of the bucket to get. + + generation: + The generation of the bucket. + + """ + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name, soft_deleted=True, generation=generation) + + print(f"ID: {bucket.id}") + print(f"Name: {bucket.name}") + print(f"Soft Delete time: {bucket.soft_delete_time}") + print(f"Hard Delete Time : {bucket.hard_delete_time}") + + +# [END storage_get_soft_deleted_bucket] + +if __name__ == "__main__": + get_soft_deleted_bucket(bucket_name=sys.argv[1], generation=sys.argv[2]) diff --git a/samples/snippets/storage_list_soft_deleted_buckets.py b/samples/snippets/storage_list_soft_deleted_buckets.py new file mode 100644 index 000000000..16abd90f0 --- /dev/null +++ b/samples/snippets/storage_list_soft_deleted_buckets.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# Copyright 2025 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. + +# [START storage_list_soft_deleted_buckets] + +from google.cloud import storage + + +def list_soft_deleted_buckets(): + """Lists all soft-deleted buckets.""" + + storage_client = storage.Client() + buckets = storage_client.list_buckets(soft_deleted=True) + + for bucket in buckets: + print(bucket.name) + + +# [END storage_list_soft_deleted_buckets] + + +if __name__ == "__main__": + list_soft_deleted_buckets() diff --git a/samples/snippets/storage_list_soft_deleted_object_versions.py b/samples/snippets/storage_list_soft_deleted_object_versions.py new file mode 100644 index 000000000..ecb9851c4 --- /dev/null +++ b/samples/snippets/storage_list_soft_deleted_object_versions.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2025 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_list_soft_deleted_object_versions] +from google.cloud import storage + + +def list_soft_deleted_object_versions(bucket_name, blob_name): + """Lists all versions of a soft-deleted object in the bucket.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + + storage_client = storage.Client() + blobs = storage_client.list_blobs(bucket_name, prefix=blob_name, soft_deleted=True) + + # Note: The call returns a response only when the iterator is consumed. + for blob in blobs: + print( + f"Version ID: {blob.generation}, Soft Delete Time: {blob.soft_delete_time}" + ) + + +# [END storage_list_soft_deleted_object_versions] + +if __name__ == "__main__": + list_soft_deleted_object_versions(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_list_soft_deleted_objects.py b/samples/snippets/storage_list_soft_deleted_objects.py new file mode 100644 index 000000000..764cac56a --- /dev/null +++ b/samples/snippets/storage_list_soft_deleted_objects.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2025 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_list_soft_deleted_objects] +from google.cloud import storage + + +def list_soft_deleted_objects(bucket_name): + """Lists all soft-deleted objects in the bucket.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + blobs = storage_client.list_blobs(bucket_name, soft_deleted=True) + + # Note: The call returns a response only when the iterator is consumed. + for blob in blobs: + print( + f"Name: {blob.name}, Generation: {blob.generation}, Soft Delete Time: {blob.soft_delete_time}" + ) + + +# [END storage_list_soft_deleted_objects] + +if __name__ == "__main__": + list_soft_deleted_objects(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_restore_object.py b/samples/snippets/storage_restore_object.py new file mode 100644 index 000000000..d1e3f2937 --- /dev/null +++ b/samples/snippets/storage_restore_object.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# Copyright 2025 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_restore_object] +from google.cloud import storage + + +def restore_soft_deleted_object(bucket_name, blob_name, blob_generation): + """Restores a soft-deleted object in the bucket.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # blob_generation = "your-object-version-id" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Restore function will override if a live object already + # exists with the same name. + bucket.restore_blob(blob_name, generation=blob_generation) + + print( + f"Soft-deleted object {blob_name} is restored in the bucket {bucket_name}" + ) + + +# [END storage_restore_object] + +if __name__ == "__main__": + restore_soft_deleted_object( + bucket_name=sys.argv[1], blob_name=sys.argv[2], blob_generation=sys.argv[3] + ) diff --git a/samples/snippets/storage_restore_soft_deleted_bucket.py b/samples/snippets/storage_restore_soft_deleted_bucket.py new file mode 100644 index 000000000..fb6291997 --- /dev/null +++ b/samples/snippets/storage_restore_soft_deleted_bucket.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Copyright 2025 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_restore_soft_deleted_bucket] + +from google.cloud import storage + + +def restore_bucket(bucket_name, bucket_generation): + storage_client = storage.Client() + bucket = storage_client.restore_bucket(bucket_name=bucket_name, generation=bucket_generation) + print(f"Soft-deleted bucket {bucket.name} with ID: {bucket.id} was restored.") + print(f"Bucket Generation: {bucket.generation}") + + +# [END storage_restore_soft_deleted_bucket] + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Wrong inputs!! Usage of script - \"python storage_restore_soft_deleted_bucket.py \" ") + sys.exit(1) + restore_bucket(bucket_name=sys.argv[1], bucket_generation=sys.argv[2]) diff --git a/samples/snippets/storage_set_soft_delete_policy.py b/samples/snippets/storage_set_soft_delete_policy.py new file mode 100644 index 000000000..26bc59436 --- /dev/null +++ b/samples/snippets/storage_set_soft_delete_policy.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# Copyright 2025 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_soft_delete_policy] +from google.cloud import storage + + +def set_soft_delete_policy(bucket_name, duration_in_seconds): + """Sets a soft-delete policy on the bucket""" + # bucket_name = "your-bucket-name" + # duration_in_seconds = "your-soft-delete-retention-duration-in-seconds" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + bucket.soft_delete_policy.retention_duration_seconds = duration_in_seconds + bucket.patch() + + print( + f"Soft delete policy for bucket {bucket_name} was set to {duration_in_seconds} seconds retention period" + ) + + +# [END storage_set_soft_delete_policy] + +if __name__ == "__main__": + set_soft_delete_policy(bucket_name=sys.argv[1], duration_in_seconds=sys.argv[2]) diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 052350089..000000000 --- a/setup.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2023 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 -# -# https://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. - -# Generated by synthtool. DO NOT EDIT! -[bdist_wheel] -universal = 1 diff --git a/setup.py b/setup.py index 31c360f40..43e3404f6 100644 --- a/setup.py +++ b/setup.py @@ -28,9 +28,9 @@ # 'Development Status :: 5 - Production/Stable' release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-auth >= 2.26.1, < 3.0dev", - "google-api-core >= 2.15.0, <3.0.0dev", - "google-cloud-core >= 2.4.2, < 3.0dev", + "google-auth >= 2.26.1, < 3.0.0", + "google-api-core >= 2.15.0, < 3.0.0", + "google-cloud-core >= 2.4.2, < 3.0.0", # The dependency "google-resumable-media" is no longer used. However, the # dependency is still included here to accommodate users who may be # importing exception classes from the google-resumable-media without @@ -38,14 +38,14 @@ # exceptions and importing. Users who are not importing # google-resumable-media classes in their application can safely disregard # this dependency. - "google-resumable-media >= 2.7.2", - "requests >= 2.18.0, < 3.0.0dev", - "google-crc32c >= 1.0, < 2.0dev", + "google-resumable-media >= 2.7.2, < 3.0.0", + "requests >= 2.22.0, < 3.0.0", + "google-crc32c >= 1.1.3, < 2.0.0", ] extras = { - "protobuf": ["protobuf<6.0.0dev"], + "protobuf": ["protobuf >= 3.20.2, < 7.0.0"], "tracing": [ - "opentelemetry-api >= 1.1.0", + "opentelemetry-api >= 1.1.0, < 2.0.0", ], } @@ -93,6 +93,7 @@ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Operating System :: OS Independent", "Topic :: Internet", ], diff --git a/testing/constraints-3.13.txt b/testing/constraints-3.13.txt new file mode 100644 index 000000000..e69de29bb diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index e69de29bb..9c17b387b 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -0,0 +1,15 @@ +# This constraints file is used to check that lower bounds +# are correct in setup.py +# List all library dependencies and extras in this file. +# Pin the version to the lower bound. +# e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", +# Then this file should have google-cloud-foo==1.14.0 +google-auth==2.26.1 +google-api-core==2.15.0 +google-cloud-core==2.4.2 +google-resumable-media==2.7.2 +requests==2.22.0 +google-crc32c==1.1.3 +protobuf==3.20.2 +opentelemetry-api==1.1.0 + diff --git a/tests/resumable_media/system/requests/test_download.py b/tests/resumable_media/system/requests/test_download.py index 15fe7d2c0..04c7246f6 100644 --- a/tests/resumable_media/system/requests/test_download.py +++ b/tests/resumable_media/system/requests/test_download.py @@ -463,7 +463,7 @@ def test_corrupt_download(self, add_files, corrupting_transport, checksum): info[checksum], checksum_type=checksum.upper(), ) - assert exc_info.value.args == (msg,) + assert msg in exc_info.value.args[0] def test_corrupt_download_no_check(self, add_files, corrupting_transport): for info in ALL_FILES: diff --git a/tests/resumable_media/unit/requests/test_download.py b/tests/resumable_media/unit/requests/test_download.py index 3da234a29..568d3238c 100644 --- a/tests/resumable_media/unit/requests/test_download.py +++ b/tests/resumable_media/unit/requests/test_download.py @@ -124,7 +124,11 @@ def test__write_to_stream_with_hash_check_fail(self, checksum): msg = download_mod._CHECKSUM_MISMATCH.format( EXAMPLE_URL, bad_checksum, good_checksum, checksum_type=checksum.upper() ) - assert error.args[0] == msg + assert msg in error.args[0] + assert ( + f"The download request read {download._bytes_downloaded} bytes of data." + in error.args[0] + ) # Check mocks. response.__enter__.assert_called_once_with() @@ -186,6 +190,29 @@ def test__write_to_stream_with_invalid_checksum_type(self): error = exc_info.value assert error.args[0] == "checksum must be ``'md5'``, ``'crc32c'`` or ``None``" + @pytest.mark.parametrize("checksum", ["md5", "crc32c"]) + def test__write_to_stream_incomplete_read(self, checksum): + stream = io.BytesIO() + download = download_mod.Download(EXAMPLE_URL, stream=stream, checksum=checksum) + + chunk1 = b"first chunk" + mock_full_content_length = len(chunk1) + 123 + headers = {"x-goog-stored-content-length": mock_full_content_length} + bad_checksum = "d3JvbmcgbiBtYWRlIHVwIQ==" + header_value = "crc32c={bad},md5={bad}".format(bad=bad_checksum) + headers[_helpers._HASH_HEADER] = header_value + response = _mock_response(chunks=[chunk1], headers=headers) + + with pytest.raises(ConnectionError) as exc_info: + download._write_to_stream(response) + + assert not download.finished + error = exc_info.value + assert ( + f"The download request read {download._bytes_downloaded} bytes of data." + in error.args[0] + ) + def _consume_helper( self, stream=None, @@ -304,7 +331,11 @@ def test_consume_with_stream_hash_check_fail(self, checksum): msg = download_mod._CHECKSUM_MISMATCH.format( EXAMPLE_URL, bad_checksum, good_checksum, checksum_type=checksum.upper() ) - assert error.args[0] == msg + assert msg in error.args[0] + assert ( + f"The download request read {download._bytes_downloaded} bytes of data." + in error.args[0] + ) # Check mocks. transport.request.assert_called_once_with( @@ -599,7 +630,11 @@ def test__write_to_stream_with_hash_check_fail(self, checksum): msg = download_mod._CHECKSUM_MISMATCH.format( EXAMPLE_URL, bad_checksum, good_checksum, checksum_type=checksum.upper() ) - assert error.args[0] == msg + assert msg in error.args[0] + assert ( + f"The download request read {download._bytes_downloaded} bytes of data." + in error.args[0] + ) # Check mocks. response.__enter__.assert_called_once_with() @@ -632,6 +667,31 @@ def test__write_to_stream_with_invalid_checksum_type(self): error = exc_info.value assert error.args[0] == "checksum must be ``'md5'``, ``'crc32c'`` or ``None``" + @pytest.mark.parametrize("checksum", ["md5", "crc32c"]) + def test__write_to_stream_incomplete_read(self, checksum): + stream = io.BytesIO() + download = download_mod.RawDownload( + EXAMPLE_URL, stream=stream, checksum=checksum + ) + + chunk1 = b"first chunk" + mock_full_content_length = len(chunk1) + 123 + headers = {"x-goog-stored-content-length": mock_full_content_length} + bad_checksum = "d3JvbmcgbiBtYWRlIHVwIQ==" + header_value = "crc32c={bad},md5={bad}".format(bad=bad_checksum) + headers[_helpers._HASH_HEADER] = header_value + response = _mock_raw_response(chunks=[chunk1], headers=headers) + + with pytest.raises(ConnectionError) as exc_info: + download._write_to_stream(response) + + assert not download.finished + error = exc_info.value + assert ( + f"The download request read {download._bytes_downloaded} bytes of data." + in error.args[0] + ) + def _consume_helper( self, stream=None, @@ -754,7 +814,11 @@ def test_consume_with_stream_hash_check_fail(self, checksum): msg = download_mod._CHECKSUM_MISMATCH.format( EXAMPLE_URL, bad_checksum, good_checksum, checksum_type=checksum.upper() ) - assert error.args[0] == msg + assert msg in error.args[0] + assert ( + f"The download request read {download._bytes_downloaded} bytes of data." + in error.args[0] + ) # Check mocks. transport.request.assert_called_once_with( diff --git a/tests/system/test_notification.py b/tests/system/test_notification.py index f52ae3219..9b631c29b 100644 --- a/tests/system/test_notification.py +++ b/tests/system/test_notification.py @@ -59,14 +59,14 @@ def topic_path(storage_client, topic_name): @pytest.fixture(scope="session") def notification_topic(storage_client, publisher_client, topic_path, no_mtls): - _helpers.retry_429(publisher_client.create_topic)(topic_path) - policy = publisher_client.get_iam_policy(topic_path) + _helpers.retry_429(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( f"serviceAccount:{storage_client.get_service_account_email()}" ) - publisher_client.set_iam_policy(topic_path, policy) + publisher_client.set_iam_policy(request={"resource": topic_path, "policy": policy}) def test_notification_create_minimal( diff --git a/tests/unit/test_fileio.py b/tests/unit/test_fileio.py index 8da25d9e3..920a3c4c2 100644 --- a/tests/unit/test_fileio.py +++ b/tests/unit/test_fileio.py @@ -367,12 +367,14 @@ def test_write(self, mock_warn): # Write under chunk_size. This should be buffered and the upload not # initiated. - writer.write(TEST_BINARY_DATA[0:4]) + w1 = writer.write(TEST_BINARY_DATA[0:4]) + self.assertEqual(w1, 4) blob._initiate_resumable_upload.assert_not_called() # Write over chunk_size. This should result in upload initialization # and multiple chunks uploaded. - writer.write(TEST_BINARY_DATA[4:32]) + w2 = writer.write(TEST_BINARY_DATA[4:32]) + self.assertEqual(w2, 28) blob._initiate_resumable_upload.assert_called_once_with( blob.bucket.client, writer._buffer,