diff --git a/.coveragerc b/.coveragerc index 03a3142..05274f7 100644 --- a/.coveragerc +++ b/.coveragerc @@ -10,8 +10,3 @@ exclude_lines = pragma: NO COVER # Ignore debug-only repr def __repr__ - # Ignore pkg_resources exceptions. - # This is added at the module level as a safeguard for if someone - # generates the code and tries to run it without pip installing. This - # makes it virtually impossible to test properly. - except pkg_resources.DistributionNotFound diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 3815c98..fccaa8e 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:7a40313731a7cb1454eef6b33d3446ebb121836738dc3ab3d2d3ded5268c35b6 + digest: sha256:3bf87e47c2173d7eed42714589dc4da2c07c3268610f1e47f8e1a30decbfc7f1 diff --git a/.github/release-please.yml b/.github/release-please.yml index 466597e..528b274 100644 --- a/.github/release-please.yml +++ b/.github/release-please.yml @@ -1,2 +1,3 @@ releaseType: python handleGHRelease: true +manifest: true diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 7092a13..e97d89e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.9" - name: Install nox run: | python -m pip install --upgrade setuptools pip wheel @@ -28,7 +28,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.9" - name: Install nox run: | python -m pip install --upgrade setuptools pip wheel diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d2aee5b..16d5a9e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,7 +12,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.8" - name: Install nox run: | python -m pip install --upgrade setuptools pip wheel diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 87ade4d..23000c0 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -41,7 +41,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.8" - name: Install coverage run: | python -m pip install --upgrade setuptools pip wheel diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile index 238b87b..f8137d0 100644 --- a/.kokoro/docker/docs/Dockerfile +++ b/.kokoro/docker/docs/Dockerfile @@ -60,16 +60,16 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && rm -f /var/cache/apt/archives/*.deb -###################### Install python 3.8.11 +###################### Install python 3.9.13 -# Download python 3.8.11 -RUN wget https://www.python.org/ftp/python/3.8.11/Python-3.8.11.tgz +# Download python 3.9.13 +RUN wget https://www.python.org/ftp/python/3.9.13/Python-3.9.13.tgz # Extract files -RUN tar -xvf Python-3.8.11.tgz +RUN tar -xvf Python-3.9.13.tgz -# Install python 3.8.11 -RUN ./Python-3.8.11/configure --enable-optimizations +# Install python 3.9.13 +RUN ./Python-3.9.13/configure --enable-optimizations RUN make altinstall ###################### Install pip diff --git a/.kokoro/requirements.in b/.kokoro/requirements.in index 7718391..cbd7e77 100644 --- a/.kokoro/requirements.in +++ b/.kokoro/requirements.in @@ -5,4 +5,6 @@ typing-extensions twine wheel setuptools -nox \ No newline at end of file +nox +charset-normalizer<3 +click<8.1.0 diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index d15994b..05dc467 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2022.6.15 \ - --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ - --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 +certifi==2022.12.7 \ + --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ + --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ @@ -93,11 +93,14 @@ cffi==1.15.1 \ charset-normalizer==2.1.1 \ --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f - # via requests + # 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.7.0 \ @@ -110,29 +113,33 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==37.0.4 \ - --hash=sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59 \ - --hash=sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596 \ - --hash=sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3 \ - --hash=sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5 \ - --hash=sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab \ - --hash=sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884 \ - --hash=sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82 \ - --hash=sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b \ - --hash=sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441 \ - --hash=sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa \ - --hash=sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d \ - --hash=sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b \ - --hash=sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a \ - --hash=sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6 \ - --hash=sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157 \ - --hash=sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280 \ - --hash=sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282 \ - --hash=sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67 \ - --hash=sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8 \ - --hash=sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046 \ - --hash=sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327 \ - --hash=sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9 +cryptography==38.0.3 \ + --hash=sha256:068147f32fa662c81aebab95c74679b401b12b57494872886eb5c1139250ec5d \ + --hash=sha256:06fc3cc7b6f6cca87bd56ec80a580c88f1da5306f505876a71c8cfa7050257dd \ + --hash=sha256:25c1d1f19729fb09d42e06b4bf9895212292cb27bb50229f5aa64d039ab29146 \ + --hash=sha256:402852a0aea73833d982cabb6d0c3bb582c15483d29fb7085ef2c42bfa7e38d7 \ + --hash=sha256:4e269dcd9b102c5a3d72be3c45d8ce20377b8076a43cbed6f660a1afe365e436 \ + --hash=sha256:5419a127426084933076132d317911e3c6eb77568a1ce23c3ac1e12d111e61e0 \ + --hash=sha256:554bec92ee7d1e9d10ded2f7e92a5d70c1f74ba9524947c0ba0c850c7b011828 \ + --hash=sha256:5e89468fbd2fcd733b5899333bc54d0d06c80e04cd23d8c6f3e0542358c6060b \ + --hash=sha256:65535bc550b70bd6271984d9863a37741352b4aad6fb1b3344a54e6950249b55 \ + --hash=sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36 \ + --hash=sha256:6addc3b6d593cd980989261dc1cce38263c76954d758c3c94de51f1e010c9a50 \ + --hash=sha256:728f2694fa743a996d7784a6194da430f197d5c58e2f4e278612b359f455e4a2 \ + --hash=sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a \ + --hash=sha256:78cf5eefac2b52c10398a42765bfa981ce2372cbc0457e6bf9658f41ec3c41d8 \ + --hash=sha256:7f836217000342d448e1c9a342e9163149e45d5b5eca76a30e84503a5a96cab0 \ + --hash=sha256:8d41a46251bf0634e21fac50ffd643216ccecfaf3701a063257fe0b2be1b6548 \ + --hash=sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320 \ + --hash=sha256:9b24bcff7853ed18a63cfb0c2b008936a9554af24af2fb146e16d8e1aed75748 \ + --hash=sha256:b1b35d9d3a65542ed2e9d90115dfd16bbc027b3f07ee3304fc83580f26e43249 \ + --hash=sha256:b1b52c9e5f8aa2b802d48bd693190341fae201ea51c7a167d69fc48b60e8a959 \ + --hash=sha256:bbf203f1a814007ce24bd4d51362991d5cb90ba0c177a9c08825f2cc304d871f \ + --hash=sha256:be243c7e2bfcf6cc4cb350c0d5cdf15ca6383bbcb2a8ef51d3c9411a9d4386f0 \ + --hash=sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd \ + --hash=sha256:c46837ea467ed1efea562bbeb543994c2d1f6e800785bd5a2c98bc096f5cb220 \ + --hash=sha256:dfb4f4dd568de1b6af9f4cda334adf7d72cf5bc052516e1b2608b683375dd95c \ + --hash=sha256:ed7b00096790213e09eb11c97cc6e2b757f15f3d2f85833cd2d3ec3fe37c1722 # via # gcp-releasetool # secretstorage @@ -148,23 +155,23 @@ filelock==3.8.0 \ --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 # via virtualenv -gcp-docuploader==0.6.3 \ - --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ - --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b +gcp-docuploader==0.6.4 \ + --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ + --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf # via -r requirements.in -gcp-releasetool==1.8.7 \ - --hash=sha256:3d2a67c9db39322194afb3b427e9cb0476ce8f2a04033695f0aeb63979fc2b37 \ - --hash=sha256:5e4d28f66e90780d77f3ecf1e9155852b0c3b13cbccb08ab07e66b2357c8da8d +gcp-releasetool==1.10.0 \ + --hash=sha256:72a38ca91b59c24f7e699e9227c90cbe4dd71b789383cb0164b088abae294c83 \ + --hash=sha256:8c7c99320208383d4bb2b808c6880eb7a81424afe7cdba3c8d84b25f4f0e097d # via -r requirements.in -google-api-core==2.8.2 \ - --hash=sha256:06f7244c640322b508b125903bb5701bebabce8832f85aba9335ec00b3d02edc \ - --hash=sha256:93c6a91ccac79079ac6bbf8b74ee75db970cc899278b97d53bc012f35908cf50 +google-api-core==2.10.2 \ + --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ + --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e # via # google-cloud-core # google-cloud-storage -google-auth==2.11.0 \ - --hash=sha256:be62acaae38d0049c21ca90f27a23847245c9f161ff54ede13af2cb6afecbac9 \ - --hash=sha256:ed65ecf9f681832298e29328e1ef0a3676e3732b2e56f41532d45f70a22de0fb +google-auth==2.14.1 \ + --hash=sha256:ccaa901f31ad5cbb562615eb8b664b3dd0bf5404a67618e642307f00613eda4d \ + --hash=sha256:f5d8701633bebc12e0deea4df8abd8aff31c28b355360597f7f2ee60f2e4d016 # via # gcp-releasetool # google-api-core @@ -174,76 +181,102 @@ google-cloud-core==2.3.2 \ --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a # via google-cloud-storage -google-cloud-storage==2.5.0 \ - --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ - --hash=sha256:382f34b91de2212e3c2e7b40ec079d27ee2e3dbbae99b75b1bcd8c63063ce235 +google-cloud-storage==2.6.0 \ + --hash=sha256:104ca28ae61243b637f2f01455cc8a05e8f15a2a18ced96cb587241cdd3820f5 \ + --hash=sha256:4ad0415ff61abdd8bb2ae81c1f8f7ec7d91a1011613f2db87c614c550f97bfe9 # via gcp-docuploader -google-crc32c==1.3.0 \ - --hash=sha256:04e7c220798a72fd0f08242bc8d7a05986b2a08a0573396187fd32c1dcdd58b3 \ - --hash=sha256:05340b60bf05b574159e9bd940152a47d38af3fb43803ffe71f11d704b7696a6 \ - --hash=sha256:12674a4c3b56b706153a358eaa1018c4137a5a04635b92b4652440d3d7386206 \ - --hash=sha256:127f9cc3ac41b6a859bd9dc4321097b1a4f6aa7fdf71b4f9227b9e3ebffb4422 \ - --hash=sha256:13af315c3a0eec8bb8b8d80b8b128cb3fcd17d7e4edafc39647846345a3f003a \ - --hash=sha256:1926fd8de0acb9d15ee757175ce7242e235482a783cd4ec711cc999fc103c24e \ - --hash=sha256:226f2f9b8e128a6ca6a9af9b9e8384f7b53a801907425c9a292553a3a7218ce0 \ - --hash=sha256:276de6273eb074a35bc598f8efbc00c7869c5cf2e29c90748fccc8c898c244df \ - --hash=sha256:318f73f5484b5671f0c7f5f63741ab020a599504ed81d209b5c7129ee4667407 \ - --hash=sha256:3bbce1be3687bbfebe29abdb7631b83e6b25da3f4e1856a1611eb21854b689ea \ - --hash=sha256:42ae4781333e331a1743445931b08ebdad73e188fd554259e772556fc4937c48 \ - --hash=sha256:58be56ae0529c664cc04a9c76e68bb92b091e0194d6e3c50bea7e0f266f73713 \ - --hash=sha256:5da2c81575cc3ccf05d9830f9e8d3c70954819ca9a63828210498c0774fda1a3 \ - --hash=sha256:6311853aa2bba4064d0c28ca54e7b50c4d48e3de04f6770f6c60ebda1e975267 \ - --hash=sha256:650e2917660e696041ab3dcd7abac160b4121cd9a484c08406f24c5964099829 \ - --hash=sha256:6a4db36f9721fdf391646685ecffa404eb986cbe007a3289499020daf72e88a2 \ - --hash=sha256:779cbf1ce375b96111db98fca913c1f5ec11b1d870e529b1dc7354b2681a8c3a \ - --hash=sha256:7f6fe42536d9dcd3e2ffb9d3053f5d05221ae3bbcefbe472bdf2c71c793e3183 \ - --hash=sha256:891f712ce54e0d631370e1f4997b3f182f3368179198efc30d477c75d1f44942 \ - --hash=sha256:95c68a4b9b7828ba0428f8f7e3109c5d476ca44996ed9a5f8aac6269296e2d59 \ - --hash=sha256:96a8918a78d5d64e07c8ea4ed2bc44354e3f93f46a4866a40e8db934e4c0d74b \ - --hash=sha256:9c3cf890c3c0ecfe1510a452a165431b5831e24160c5fcf2071f0f85ca5a47cd \ - --hash=sha256:9f58099ad7affc0754ae42e6d87443299f15d739b0ce03c76f515153a5cda06c \ - --hash=sha256:a0b9e622c3b2b8d0ce32f77eba617ab0d6768b82836391e4f8f9e2074582bf02 \ - --hash=sha256:a7f9cbea4245ee36190f85fe1814e2d7b1e5f2186381b082f5d59f99b7f11328 \ - --hash=sha256:bab4aebd525218bab4ee615786c4581952eadc16b1ff031813a2fd51f0cc7b08 \ - --hash=sha256:c124b8c8779bf2d35d9b721e52d4adb41c9bfbde45e6a3f25f0820caa9aba73f \ - --hash=sha256:c9da0a39b53d2fab3e5467329ed50e951eb91386e9d0d5b12daf593973c3b168 \ - --hash=sha256:ca60076c388728d3b6ac3846842474f4250c91efbfe5afa872d3ffd69dd4b318 \ - --hash=sha256:cb6994fff247987c66a8a4e550ef374671c2b82e3c0d2115e689d21e511a652d \ - --hash=sha256:d1c1d6236feab51200272d79b3d3e0f12cf2cbb12b208c835b175a21efdb0a73 \ - --hash=sha256:dd7760a88a8d3d705ff562aa93f8445ead54f58fd482e4f9e2bafb7e177375d4 \ - --hash=sha256:dda4d8a3bb0b50f540f6ff4b6033f3a74e8bf0bd5320b70fab2c03e512a62812 \ - --hash=sha256:e0f1ff55dde0ebcfbef027edc21f71c205845585fffe30d4ec4979416613e9b3 \ - --hash=sha256:e7a539b9be7b9c00f11ef16b55486141bc2cdb0c54762f84e3c6fc091917436d \ - --hash=sha256:eb0b14523758e37802f27b7f8cd973f5f3d33be7613952c0df904b68c4842f0e \ - --hash=sha256:ed447680ff21c14aaceb6a9f99a5f639f583ccfe4ce1a5e1d48eb41c3d6b3217 \ - --hash=sha256:f52a4ad2568314ee713715b1e2d79ab55fab11e8b304fd1462ff5cccf4264b3e \ - --hash=sha256:fbd60c6aaa07c31d7754edbc2334aef50601b7f1ada67a96eb1eb57c7c72378f \ - --hash=sha256:fc28e0db232c62ca0c3600884933178f0825c99be4474cdd645e378a10588125 \ - --hash=sha256:fe31de3002e7b08eb20823b3735b97c86c5926dd0581c7710a680b418a8709d4 \ - --hash=sha256:fec221a051150eeddfdfcff162e6db92c65ecf46cb0f7bb1bf812a1520ec026b \ - --hash=sha256:ff71073ebf0e42258a42a0b34f2c09ec384977e7f6808999102eedd5b49920e3 +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-resumable-media -google-resumable-media==2.3.3 \ - --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ - --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 +google-resumable-media==2.4.0 \ + --hash=sha256:2aa004c16d295c8f6c33b2b4788ba59d366677c0a25ae7382436cb30f776deaa \ + --hash=sha256:8d5518502f92b9ecc84ac46779bd4f09694ecb3ba38a3e7ca737a86d15cbca1f # via google-cloud-storage -googleapis-common-protos==1.56.4 \ - --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ - --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 +googleapis-common-protos==1.57.0 \ + --hash=sha256:27a849d6205838fb6cc3c1c21cb9800707a661bb21c6ce7fb13e99eb1f8a0c46 \ + --hash=sha256:a9f4a1d7f6d9809657b7f1316a1aa527f6664891531bcfcc13b6696e685f443c # via google-api-core -idna==3.3 \ - --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ - --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==4.12.0 \ - --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ - --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 +importlib-metadata==5.0.0 \ + --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ + --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via # -r requirements.in + # keyring # twine -jaraco-classes==3.2.2 \ - --hash=sha256:6745f113b0b588239ceb49532aa09c3ebb947433ce311ef2f8e3ad64ebb74594 \ - --hash=sha256:e6ef6fd3fcf4579a7a019d87d1e56a883f4e4c35cfe925f86731abc58804e647 +jaraco-classes==3.2.3 \ + --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ + --hash=sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a # via keyring jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ @@ -255,9 +288,9 @@ jinja2==3.1.2 \ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 # via gcp-releasetool -keyring==23.9.0 \ - --hash=sha256:4c32a31174faaee48f43a7e2c7e9c3216ec5e95acf22a2bebfb4a1d05056ee44 \ - --hash=sha256:98f060ec95ada2ab910c195a2d4317be6ef87936a766b239c46aa3c7aac4f0db +keyring==23.11.0 \ + --hash=sha256:3dd30011d555f1345dec2c262f0153f2f0ca6bca041fb1dc4588349bb4c0ac1e \ + --hash=sha256:ad192263e2cdd5f12875dedc2da13534359a7e760e77f8d04b50968a821c2361 # via # gcp-releasetool # twine @@ -303,9 +336,9 @@ markupsafe==2.1.1 \ --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 # via jinja2 -more-itertools==8.14.0 \ - --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ - --hash=sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750 +more-itertools==9.0.0 \ + --hash=sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41 \ + --hash=sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab # via jaraco-classes nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ @@ -321,34 +354,33 @@ pkginfo==1.8.3 \ --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c # via twine -platformdirs==2.5.2 \ - --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ - --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 +platformdirs==2.5.4 \ + --hash=sha256:1006647646d80f16130f052404c6b901e80ee4ed6bef6792e1f238a8969106f7 \ + --hash=sha256:af0276409f9a02373d540bf8480021a048711d572745aef4b7842dad245eba10 # via virtualenv -protobuf==3.20.2 \ - --hash=sha256:03d76b7bd42ac4a6e109742a4edf81ffe26ffd87c5993126d894fe48a120396a \ - --hash=sha256:09e25909c4297d71d97612f04f41cea8fa8510096864f2835ad2f3b3df5a5559 \ - --hash=sha256:18e34a10ae10d458b027d7638a599c964b030c1739ebd035a1dfc0e22baa3bfe \ - --hash=sha256:291fb4307094bf5ccc29f424b42268640e00d5240bf0d9b86bf3079f7576474d \ - --hash=sha256:2c0b040d0b5d5d207936ca2d02f00f765906622c07d3fa19c23a16a8ca71873f \ - --hash=sha256:384164994727f274cc34b8abd41a9e7e0562801361ee77437099ff6dfedd024b \ - --hash=sha256:3cb608e5a0eb61b8e00fe641d9f0282cd0eedb603be372f91f163cbfbca0ded0 \ - --hash=sha256:5d9402bf27d11e37801d1743eada54372f986a372ec9679673bfcc5c60441151 \ - --hash=sha256:712dca319eee507a1e7df3591e639a2b112a2f4a62d40fe7832a16fd19151750 \ - --hash=sha256:7a5037af4e76c975b88c3becdf53922b5ffa3f2cddf657574a4920a3b33b80f3 \ - --hash=sha256:8228e56a865c27163d5d1d1771d94b98194aa6917bcfb6ce139cbfa8e3c27334 \ - --hash=sha256:84a1544252a933ef07bb0b5ef13afe7c36232a774affa673fc3636f7cee1db6c \ - --hash=sha256:84fe5953b18a383fd4495d375fe16e1e55e0a3afe7b4f7b4d01a3a0649fcda9d \ - --hash=sha256:9c673c8bfdf52f903081816b9e0e612186684f4eb4c17eeb729133022d6032e3 \ - --hash=sha256:9f876a69ca55aed879b43c295a328970306e8e80a263ec91cf6e9189243c613b \ - --hash=sha256:a9e5ae5a8e8985c67e8944c23035a0dff2c26b0f5070b2f55b217a1c33bbe8b1 \ - --hash=sha256:b4fdb29c5a7406e3f7ef176b2a7079baa68b5b854f364c21abe327bbeec01cdb \ - --hash=sha256:c184485e0dfba4dfd451c3bd348c2e685d6523543a0f91b9fd4ae90eb09e8422 \ - --hash=sha256:c9cdf251c582c16fd6a9f5e95836c90828d51b0069ad22f463761d27c6c19019 \ - --hash=sha256:e39cf61bb8582bda88cdfebc0db163b774e7e03364bbf9ce1ead13863e81e359 \ - --hash=sha256:e8fbc522303e09036c752a0afcc5c0603e917222d8bedc02813fd73b4b4ed804 \ - --hash=sha256:f34464ab1207114e73bba0794d1257c150a2b89b7a9faf504e00af7c9fd58978 \ - --hash=sha256:f52dabc96ca99ebd2169dadbe018824ebda08a795c7684a0b7d203a290f3adb0 +protobuf==3.20.3 \ + --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ + --hash=sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c \ + --hash=sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2 \ + --hash=sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b \ + --hash=sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050 \ + --hash=sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9 \ + --hash=sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7 \ + --hash=sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454 \ + --hash=sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480 \ + --hash=sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469 \ + --hash=sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c \ + --hash=sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e \ + --hash=sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db \ + --hash=sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905 \ + --hash=sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b \ + --hash=sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86 \ + --hash=sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4 \ + --hash=sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402 \ + --hash=sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7 \ + --hash=sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4 \ + --hash=sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99 \ + --hash=sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee # via # gcp-docuploader # gcp-releasetool @@ -377,9 +409,9 @@ pygments==2.13.0 \ # via # readme-renderer # rich -pyjwt==2.4.0 \ - --hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \ - --hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba +pyjwt==2.6.0 \ + --hash=sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd \ + --hash=sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14 # via gcp-releasetool pyparsing==3.0.9 \ --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ @@ -392,9 +424,9 @@ python-dateutil==2.8.2 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 # via gcp-releasetool -readme-renderer==37.0 \ - --hash=sha256:07b7ea234e03e58f77cc222e206e6abb8f4c0435becce5104794ee591f9301c5 \ - --hash=sha256:9fa416704703e509eeb900696751c908ddeb2011319d93700d8f18baff887a69 +readme-renderer==37.3 \ + --hash=sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273 \ + --hash=sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343 # via twine requests==2.28.1 \ --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ @@ -405,17 +437,17 @@ requests==2.28.1 \ # google-cloud-storage # requests-toolbelt # twine -requests-toolbelt==0.9.1 \ - --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ - --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 +requests-toolbelt==0.10.1 \ + --hash=sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7 \ + --hash=sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==12.5.1 \ - --hash=sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb \ - --hash=sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca +rich==12.6.0 \ + --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ + --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 # via twine rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ @@ -437,9 +469,9 @@ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 # via -r requirements.in -typing-extensions==4.3.0 \ - --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ - --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 +typing-extensions==4.4.0 \ + --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ + --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via -r requirements.in urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ @@ -447,25 +479,25 @@ urllib3==1.26.12 \ # via # requests # twine -virtualenv==20.16.4 \ - --hash=sha256:014f766e4134d0008dcaa1f95bafa0fb0f575795d07cae50b1bee514185d6782 \ - --hash=sha256:035ed57acce4ac35c82c9d8802202b0e71adac011a511ff650cbcf9635006a22 +virtualenv==20.16.7 \ + --hash=sha256:8691e3ff9387f743e00f6bb20f70121f5e4f596cae754531f2b3b3a1b1ac696e \ + --hash=sha256:efd66b00386fdb7dbe4822d172303f40cd05e50e01740b19ea42425cbe653e29 # via nox webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach -wheel==0.37.1 \ - --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ - --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 +wheel==0.38.4 \ + --hash=sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac \ + --hash=sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8 # via -r requirements.in -zipp==3.8.1 \ - --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ - --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 +zipp==3.10.0 \ + --hash=sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1 \ + --hash=sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: -setuptools==65.2.0 \ - --hash=sha256:7f4bc85450898a09f76ebf28b72fa25bc7111f6c7d665d514a60bba9c75ef2a9 \ - --hash=sha256:a3ca5857c89f82f5c9410e8508cb32f4872a3bafd4aa7ae122a24ca33bccc750 +setuptools==65.5.1 \ + --hash=sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31 \ + --hash=sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f # via -r requirements.in diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 46d2371..5405cc8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: rev: 22.3.0 hooks: - id: black -- repo: https://gitlab.com/pycqa/flake8 +- repo: https://github.com/pycqa/flake8 rev: 3.9.2 hooks: - id: flake8 diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..f1c1e58 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.5.0" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index c926cbd..7512e60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## [0.5.0](https://github.com/googleapis/python-run/compare/v0.4.2...v0.5.0) (2022-12-14) + + +### Features + +* Add support for `google.cloud.run.__version__` ([a19c445](https://github.com/googleapis/python-run/commit/a19c445b86b4b5897bbf171369a9b674f90cf803)) +* Add typing to proto.Message based class attributes ([a19c445](https://github.com/googleapis/python-run/commit/a19c445b86b4b5897bbf171369a9b674f90cf803)) +* Adds Cloud Run Jobs v2 API client libraries ([a19c445](https://github.com/googleapis/python-run/commit/a19c445b86b4b5897bbf171369a9b674f90cf803)) +* Adds Startup and Liveness probes to Cloud Run v2 API client libraries ([#60](https://github.com/googleapis/python-run/issues/60)) ([d4d22ec](https://github.com/googleapis/python-run/commit/d4d22ecf187d7b370f10d627ece28255cbe9c804)) + + +### Bug Fixes + +* Add dict typing for client_options ([a19c445](https://github.com/googleapis/python-run/commit/a19c445b86b4b5897bbf171369a9b674f90cf803)) +* **deps:** Require google-api-core >=1.34.0, >=2.11.0 ([cfedfb2](https://github.com/googleapis/python-run/commit/cfedfb23c599bc010efdfd4d2f435f5d4861020a)) +* Drop usage of pkg_resources ([cfedfb2](https://github.com/googleapis/python-run/commit/cfedfb23c599bc010efdfd4d2f435f5d4861020a)) +* Fix timeout default values ([cfedfb2](https://github.com/googleapis/python-run/commit/cfedfb23c599bc010efdfd4d2f435f5d4861020a)) + + +### Documentation + +* **samples:** Snippetgen handling of repeated enum field ([a19c445](https://github.com/googleapis/python-run/commit/a19c445b86b4b5897bbf171369a9b674f90cf803)) +* **samples:** Snippetgen should call await on the operation coroutine before calling result ([cfedfb2](https://github.com/googleapis/python-run/commit/cfedfb23c599bc010efdfd4d2f435f5d4861020a)) + ## [0.4.2](https://github.com/googleapis/python-run/compare/v0.4.1...v0.4.2) (2022-10-10) diff --git a/docs/conf.py b/docs/conf.py index 2af9b52..7563314 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,9 +24,9 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os import shlex +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the diff --git a/docs/run_v2/executions.rst b/docs/run_v2/executions.rst new file mode 100644 index 0000000..f27d4a7 --- /dev/null +++ b/docs/run_v2/executions.rst @@ -0,0 +1,10 @@ +Executions +---------------------------- + +.. automodule:: google.cloud.run_v2.services.executions + :members: + :inherited-members: + +.. automodule:: google.cloud.run_v2.services.executions.pagers + :members: + :inherited-members: diff --git a/docs/run_v2/jobs.rst b/docs/run_v2/jobs.rst new file mode 100644 index 0000000..423b784 --- /dev/null +++ b/docs/run_v2/jobs.rst @@ -0,0 +1,10 @@ +Jobs +---------------------- + +.. automodule:: google.cloud.run_v2.services.jobs + :members: + :inherited-members: + +.. automodule:: google.cloud.run_v2.services.jobs.pagers + :members: + :inherited-members: diff --git a/docs/run_v2/services_.rst b/docs/run_v2/services_.rst index 533d18a..c4c4ad8 100644 --- a/docs/run_v2/services_.rst +++ b/docs/run_v2/services_.rst @@ -3,5 +3,8 @@ Services for Google Cloud Run v2 API .. toctree:: :maxdepth: 2 + executions + jobs revisions services + tasks diff --git a/docs/run_v2/tasks.rst b/docs/run_v2/tasks.rst new file mode 100644 index 0000000..7bb96f7 --- /dev/null +++ b/docs/run_v2/tasks.rst @@ -0,0 +1,10 @@ +Tasks +----------------------- + +.. automodule:: google.cloud.run_v2.services.tasks + :members: + :inherited-members: + +.. automodule:: google.cloud.run_v2.services.tasks.pagers + :members: + :inherited-members: diff --git a/docs/run_v2/types.rst b/docs/run_v2/types.rst index a45661d..887d323 100644 --- a/docs/run_v2/types.rst +++ b/docs/run_v2/types.rst @@ -3,5 +3,4 @@ Types for Google Cloud Run v2 API .. automodule:: google.cloud.run_v2.types :members: - :undoc-members: :show-inheritance: diff --git a/google/cloud/run/__init__.py b/google/cloud/run/__init__.py new file mode 100644 index 0000000..8155e18 --- /dev/null +++ b/google/cloud/run/__init__.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 google.cloud.run import gapic_version as package_version + +__version__ = package_version.__version__ + + +from google.cloud.run_v2.services.executions.async_client import ExecutionsAsyncClient +from google.cloud.run_v2.services.executions.client import ExecutionsClient +from google.cloud.run_v2.services.jobs.async_client import JobsAsyncClient +from google.cloud.run_v2.services.jobs.client import JobsClient +from google.cloud.run_v2.services.revisions.async_client import RevisionsAsyncClient +from google.cloud.run_v2.services.revisions.client import RevisionsClient +from google.cloud.run_v2.services.services.async_client import ServicesAsyncClient +from google.cloud.run_v2.services.services.client import ServicesClient +from google.cloud.run_v2.services.tasks.async_client import TasksAsyncClient +from google.cloud.run_v2.services.tasks.client import TasksClient +from google.cloud.run_v2.types.condition import Condition +from google.cloud.run_v2.types.execution import ( + DeleteExecutionRequest, + Execution, + GetExecutionRequest, + ListExecutionsRequest, + ListExecutionsResponse, +) +from google.cloud.run_v2.types.execution_template import ExecutionTemplate +from google.cloud.run_v2.types.job import ( + CreateJobRequest, + DeleteJobRequest, + ExecutionReference, + GetJobRequest, + Job, + ListJobsRequest, + ListJobsResponse, + RunJobRequest, + UpdateJobRequest, +) +from google.cloud.run_v2.types.k8s_min import ( + CloudSqlInstance, + Container, + ContainerPort, + EnvVar, + EnvVarSource, + GRPCAction, + HTTPGetAction, + HTTPHeader, + Probe, + ResourceRequirements, + SecretKeySelector, + SecretVolumeSource, + TCPSocketAction, + VersionToPath, + Volume, + VolumeMount, +) +from google.cloud.run_v2.types.revision import ( + DeleteRevisionRequest, + GetRevisionRequest, + ListRevisionsRequest, + ListRevisionsResponse, + Revision, +) +from google.cloud.run_v2.types.revision_template import RevisionTemplate +from google.cloud.run_v2.types.service import ( + CreateServiceRequest, + DeleteServiceRequest, + GetServiceRequest, + ListServicesRequest, + ListServicesResponse, + Service, + UpdateServiceRequest, +) +from google.cloud.run_v2.types.task import ( + GetTaskRequest, + ListTasksRequest, + ListTasksResponse, + Task, + TaskAttemptResult, +) +from google.cloud.run_v2.types.task_template import TaskTemplate +from google.cloud.run_v2.types.traffic_target import ( + TrafficTarget, + TrafficTargetAllocationType, + TrafficTargetStatus, +) +from google.cloud.run_v2.types.vendor_settings import ( + BinaryAuthorization, + ExecutionEnvironment, + IngressTraffic, + RevisionScaling, + VpcAccess, +) + +__all__ = ( + "ExecutionsClient", + "ExecutionsAsyncClient", + "JobsClient", + "JobsAsyncClient", + "RevisionsClient", + "RevisionsAsyncClient", + "ServicesClient", + "ServicesAsyncClient", + "TasksClient", + "TasksAsyncClient", + "Condition", + "DeleteExecutionRequest", + "Execution", + "GetExecutionRequest", + "ListExecutionsRequest", + "ListExecutionsResponse", + "ExecutionTemplate", + "CreateJobRequest", + "DeleteJobRequest", + "ExecutionReference", + "GetJobRequest", + "Job", + "ListJobsRequest", + "ListJobsResponse", + "RunJobRequest", + "UpdateJobRequest", + "CloudSqlInstance", + "Container", + "ContainerPort", + "EnvVar", + "EnvVarSource", + "GRPCAction", + "HTTPGetAction", + "HTTPHeader", + "Probe", + "ResourceRequirements", + "SecretKeySelector", + "SecretVolumeSource", + "TCPSocketAction", + "VersionToPath", + "Volume", + "VolumeMount", + "DeleteRevisionRequest", + "GetRevisionRequest", + "ListRevisionsRequest", + "ListRevisionsResponse", + "Revision", + "RevisionTemplate", + "CreateServiceRequest", + "DeleteServiceRequest", + "GetServiceRequest", + "ListServicesRequest", + "ListServicesResponse", + "Service", + "UpdateServiceRequest", + "GetTaskRequest", + "ListTasksRequest", + "ListTasksResponse", + "Task", + "TaskAttemptResult", + "TaskTemplate", + "TrafficTarget", + "TrafficTargetStatus", + "TrafficTargetAllocationType", + "BinaryAuthorization", + "RevisionScaling", + "VpcAccess", + "ExecutionEnvironment", + "IngressTraffic", +) diff --git a/google/cloud/run/gapic_version.py b/google/cloud/run/gapic_version.py new file mode 100644 index 0000000..371eb6b --- /dev/null +++ b/google/cloud/run/gapic_version.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +__version__ = "0.5.0" # {x-release-please-version} diff --git a/google/cloud/run/py.typed b/google/cloud/run/py.typed new file mode 100644 index 0000000..a94ba23 --- /dev/null +++ b/google/cloud/run/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-run package uses inline types. diff --git a/google/cloud/run_v2/__init__.py b/google/cloud/run_v2/__init__.py index a0d9033..ba62b9f 100644 --- a/google/cloud/run_v2/__init__.py +++ b/google/cloud/run_v2/__init__.py @@ -13,79 +13,157 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from google.cloud.run import gapic_version as package_version -from .services.revisions import RevisionsClient -from .services.revisions import RevisionsAsyncClient -from .services.services import ServicesClient -from .services.services import ServicesAsyncClient +__version__ = package_version.__version__ + +from .services.executions import ExecutionsAsyncClient, ExecutionsClient +from .services.jobs import JobsAsyncClient, JobsClient +from .services.revisions import RevisionsAsyncClient, RevisionsClient +from .services.services import ServicesAsyncClient, ServicesClient +from .services.tasks import TasksAsyncClient, TasksClient from .types.condition import Condition -from .types.k8s_min import CloudSqlInstance -from .types.k8s_min import Container -from .types.k8s_min import ContainerPort -from .types.k8s_min import EnvVar -from .types.k8s_min import EnvVarSource -from .types.k8s_min import ResourceRequirements -from .types.k8s_min import SecretKeySelector -from .types.k8s_min import SecretVolumeSource -from .types.k8s_min import VersionToPath -from .types.k8s_min import Volume -from .types.k8s_min import VolumeMount -from .types.revision import DeleteRevisionRequest -from .types.revision import GetRevisionRequest -from .types.revision import ListRevisionsRequest -from .types.revision import ListRevisionsResponse -from .types.revision import Revision +from .types.execution import ( + DeleteExecutionRequest, + Execution, + GetExecutionRequest, + ListExecutionsRequest, + ListExecutionsResponse, +) +from .types.execution_template import ExecutionTemplate +from .types.job import ( + CreateJobRequest, + DeleteJobRequest, + ExecutionReference, + GetJobRequest, + Job, + ListJobsRequest, + ListJobsResponse, + RunJobRequest, + UpdateJobRequest, +) +from .types.k8s_min import ( + CloudSqlInstance, + Container, + ContainerPort, + EnvVar, + EnvVarSource, + GRPCAction, + HTTPGetAction, + HTTPHeader, + Probe, + ResourceRequirements, + SecretKeySelector, + SecretVolumeSource, + TCPSocketAction, + VersionToPath, + Volume, + VolumeMount, +) +from .types.revision import ( + DeleteRevisionRequest, + GetRevisionRequest, + ListRevisionsRequest, + ListRevisionsResponse, + Revision, +) from .types.revision_template import RevisionTemplate -from .types.service import CreateServiceRequest -from .types.service import DeleteServiceRequest -from .types.service import GetServiceRequest -from .types.service import ListServicesRequest -from .types.service import ListServicesResponse -from .types.service import Service -from .types.service import UpdateServiceRequest -from .types.traffic_target import TrafficTarget -from .types.traffic_target import TrafficTargetStatus -from .types.traffic_target import TrafficTargetAllocationType -from .types.vendor_settings import BinaryAuthorization -from .types.vendor_settings import RevisionScaling -from .types.vendor_settings import VpcAccess -from .types.vendor_settings import ExecutionEnvironment -from .types.vendor_settings import IngressTraffic +from .types.service import ( + CreateServiceRequest, + DeleteServiceRequest, + GetServiceRequest, + ListServicesRequest, + ListServicesResponse, + Service, + UpdateServiceRequest, +) +from .types.task import ( + GetTaskRequest, + ListTasksRequest, + ListTasksResponse, + Task, + TaskAttemptResult, +) +from .types.task_template import TaskTemplate +from .types.traffic_target import ( + TrafficTarget, + TrafficTargetAllocationType, + TrafficTargetStatus, +) +from .types.vendor_settings import ( + BinaryAuthorization, + ExecutionEnvironment, + IngressTraffic, + RevisionScaling, + VpcAccess, +) __all__ = ( + "ExecutionsAsyncClient", + "JobsAsyncClient", "RevisionsAsyncClient", "ServicesAsyncClient", + "TasksAsyncClient", "BinaryAuthorization", "CloudSqlInstance", "Condition", "Container", "ContainerPort", + "CreateJobRequest", "CreateServiceRequest", + "DeleteExecutionRequest", + "DeleteJobRequest", "DeleteRevisionRequest", "DeleteServiceRequest", "EnvVar", "EnvVarSource", + "Execution", "ExecutionEnvironment", + "ExecutionReference", + "ExecutionTemplate", + "ExecutionsClient", + "GRPCAction", + "GetExecutionRequest", + "GetJobRequest", "GetRevisionRequest", "GetServiceRequest", + "GetTaskRequest", + "HTTPGetAction", + "HTTPHeader", "IngressTraffic", + "Job", + "JobsClient", + "ListExecutionsRequest", + "ListExecutionsResponse", + "ListJobsRequest", + "ListJobsResponse", "ListRevisionsRequest", "ListRevisionsResponse", "ListServicesRequest", "ListServicesResponse", + "ListTasksRequest", + "ListTasksResponse", + "Probe", "ResourceRequirements", "Revision", "RevisionScaling", "RevisionTemplate", "RevisionsClient", + "RunJobRequest", "SecretKeySelector", "SecretVolumeSource", "Service", "ServicesClient", + "TCPSocketAction", + "Task", + "TaskAttemptResult", + "TaskTemplate", + "TasksClient", "TrafficTarget", "TrafficTargetAllocationType", "TrafficTargetStatus", + "UpdateJobRequest", "UpdateServiceRequest", "VersionToPath", "Volume", diff --git a/google/cloud/run_v2/gapic_metadata.json b/google/cloud/run_v2/gapic_metadata.json index e8920ee..35162df 100644 --- a/google/cloud/run_v2/gapic_metadata.json +++ b/google/cloud/run_v2/gapic_metadata.json @@ -5,6 +5,224 @@ "protoPackage": "google.cloud.run.v2", "schema": "1.0", "services": { + "Executions": { + "clients": { + "grpc": { + "libraryClient": "ExecutionsClient", + "rpcs": { + "DeleteExecution": { + "methods": [ + "delete_execution" + ] + }, + "GetExecution": { + "methods": [ + "get_execution" + ] + }, + "ListExecutions": { + "methods": [ + "list_executions" + ] + } + } + }, + "grpc-async": { + "libraryClient": "ExecutionsAsyncClient", + "rpcs": { + "DeleteExecution": { + "methods": [ + "delete_execution" + ] + }, + "GetExecution": { + "methods": [ + "get_execution" + ] + }, + "ListExecutions": { + "methods": [ + "list_executions" + ] + } + } + }, + "rest": { + "libraryClient": "ExecutionsClient", + "rpcs": { + "DeleteExecution": { + "methods": [ + "delete_execution" + ] + }, + "GetExecution": { + "methods": [ + "get_execution" + ] + }, + "ListExecutions": { + "methods": [ + "list_executions" + ] + } + } + } + } + }, + "Jobs": { + "clients": { + "grpc": { + "libraryClient": "JobsClient", + "rpcs": { + "CreateJob": { + "methods": [ + "create_job" + ] + }, + "DeleteJob": { + "methods": [ + "delete_job" + ] + }, + "GetIamPolicy": { + "methods": [ + "get_iam_policy" + ] + }, + "GetJob": { + "methods": [ + "get_job" + ] + }, + "ListJobs": { + "methods": [ + "list_jobs" + ] + }, + "RunJob": { + "methods": [ + "run_job" + ] + }, + "SetIamPolicy": { + "methods": [ + "set_iam_policy" + ] + }, + "TestIamPermissions": { + "methods": [ + "test_iam_permissions" + ] + }, + "UpdateJob": { + "methods": [ + "update_job" + ] + } + } + }, + "grpc-async": { + "libraryClient": "JobsAsyncClient", + "rpcs": { + "CreateJob": { + "methods": [ + "create_job" + ] + }, + "DeleteJob": { + "methods": [ + "delete_job" + ] + }, + "GetIamPolicy": { + "methods": [ + "get_iam_policy" + ] + }, + "GetJob": { + "methods": [ + "get_job" + ] + }, + "ListJobs": { + "methods": [ + "list_jobs" + ] + }, + "RunJob": { + "methods": [ + "run_job" + ] + }, + "SetIamPolicy": { + "methods": [ + "set_iam_policy" + ] + }, + "TestIamPermissions": { + "methods": [ + "test_iam_permissions" + ] + }, + "UpdateJob": { + "methods": [ + "update_job" + ] + } + } + }, + "rest": { + "libraryClient": "JobsClient", + "rpcs": { + "CreateJob": { + "methods": [ + "create_job" + ] + }, + "DeleteJob": { + "methods": [ + "delete_job" + ] + }, + "GetIamPolicy": { + "methods": [ + "get_iam_policy" + ] + }, + "GetJob": { + "methods": [ + "get_job" + ] + }, + "ListJobs": { + "methods": [ + "list_jobs" + ] + }, + "RunJob": { + "methods": [ + "run_job" + ] + }, + "SetIamPolicy": { + "methods": [ + "set_iam_policy" + ] + }, + "TestIamPermissions": { + "methods": [ + "test_iam_permissions" + ] + }, + "UpdateJob": { + "methods": [ + "update_job" + ] + } + } + } + } + }, "Revisions": { "clients": { "grpc": { @@ -207,6 +425,55 @@ } } } + }, + "Tasks": { + "clients": { + "grpc": { + "libraryClient": "TasksClient", + "rpcs": { + "GetTask": { + "methods": [ + "get_task" + ] + }, + "ListTasks": { + "methods": [ + "list_tasks" + ] + } + } + }, + "grpc-async": { + "libraryClient": "TasksAsyncClient", + "rpcs": { + "GetTask": { + "methods": [ + "get_task" + ] + }, + "ListTasks": { + "methods": [ + "list_tasks" + ] + } + } + }, + "rest": { + "libraryClient": "TasksClient", + "rpcs": { + "GetTask": { + "methods": [ + "get_task" + ] + }, + "ListTasks": { + "methods": [ + "list_tasks" + ] + } + } + } + } } } } diff --git a/google/cloud/run_v2/gapic_version.py b/google/cloud/run_v2/gapic_version.py new file mode 100644 index 0000000..371eb6b --- /dev/null +++ b/google/cloud/run_v2/gapic_version.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +__version__ = "0.5.0" # {x-release-please-version} diff --git a/google/cloud/run_v2/services/executions/__init__.py b/google/cloud/run_v2/services/executions/__init__.py new file mode 100644 index 0000000..f92fc71 --- /dev/null +++ b/google/cloud/run_v2/services/executions/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 .async_client import ExecutionsAsyncClient +from .client import ExecutionsClient + +__all__ = ( + "ExecutionsClient", + "ExecutionsAsyncClient", +) diff --git a/google/cloud/run_v2/services/executions/async_client.py b/google/cloud/run_v2/services/executions/async_client.py new file mode 100644 index 0000000..4a0b7d6 --- /dev/null +++ b/google/cloud/run_v2/services/executions/async_client.py @@ -0,0 +1,751 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +import functools +import re +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.api import launch_stage_pb2 # type: ignore +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.run_v2.services.executions import pagers +from google.cloud.run_v2.types import condition, execution, task_template + +from .client import ExecutionsClient +from .transports.base import DEFAULT_CLIENT_INFO, ExecutionsTransport +from .transports.grpc_asyncio import ExecutionsGrpcAsyncIOTransport + + +class ExecutionsAsyncClient: + """Cloud Run Execution Control Plane API.""" + + _client: ExecutionsClient + + DEFAULT_ENDPOINT = ExecutionsClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = ExecutionsClient.DEFAULT_MTLS_ENDPOINT + + connector_path = staticmethod(ExecutionsClient.connector_path) + parse_connector_path = staticmethod(ExecutionsClient.parse_connector_path) + crypto_key_path = staticmethod(ExecutionsClient.crypto_key_path) + parse_crypto_key_path = staticmethod(ExecutionsClient.parse_crypto_key_path) + execution_path = staticmethod(ExecutionsClient.execution_path) + parse_execution_path = staticmethod(ExecutionsClient.parse_execution_path) + job_path = staticmethod(ExecutionsClient.job_path) + parse_job_path = staticmethod(ExecutionsClient.parse_job_path) + secret_path = staticmethod(ExecutionsClient.secret_path) + parse_secret_path = staticmethod(ExecutionsClient.parse_secret_path) + secret_version_path = staticmethod(ExecutionsClient.secret_version_path) + parse_secret_version_path = staticmethod(ExecutionsClient.parse_secret_version_path) + common_billing_account_path = staticmethod( + ExecutionsClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + ExecutionsClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(ExecutionsClient.common_folder_path) + parse_common_folder_path = staticmethod(ExecutionsClient.parse_common_folder_path) + common_organization_path = staticmethod(ExecutionsClient.common_organization_path) + parse_common_organization_path = staticmethod( + ExecutionsClient.parse_common_organization_path + ) + common_project_path = staticmethod(ExecutionsClient.common_project_path) + parse_common_project_path = staticmethod(ExecutionsClient.parse_common_project_path) + common_location_path = staticmethod(ExecutionsClient.common_location_path) + parse_common_location_path = staticmethod( + ExecutionsClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + ExecutionsAsyncClient: The constructed client. + """ + return ExecutionsClient.from_service_account_info.__func__(ExecutionsAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + ExecutionsAsyncClient: The constructed client. + """ + return ExecutionsClient.from_service_account_file.__func__(ExecutionsAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return ExecutionsClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> ExecutionsTransport: + """Returns the transport used by the client instance. + + Returns: + ExecutionsTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(ExecutionsClient).get_transport_class, type(ExecutionsClient) + ) + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, ExecutionsTransport] = "grpc_asyncio", + client_options: Optional[ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the executions client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.ExecutionsTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = ExecutionsClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def get_execution( + self, + request: Optional[Union[execution.GetExecutionRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> execution.Execution: + r"""Gets information about an Execution. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_get_execution(): + # Create a client + client = run_v2.ExecutionsAsyncClient() + + # Initialize request argument(s) + request = run_v2.GetExecutionRequest( + name="name_value", + ) + + # Make the request + response = await client.get_execution(request=request) + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.GetExecutionRequest, dict]]): + The request object. Request message for obtaining a + Execution by its full name. + name (:class:`str`): + Required. The full name of the + Execution. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.types.Execution: + Execution represents the + configuration of a single execution. A + execution an immutable resource that + references a container image which is + run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = execution.GetExecutionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_execution, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_executions( + self, + request: Optional[Union[execution.ListExecutionsRequest, dict]] = None, + *, + parent: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListExecutionsAsyncPager: + r"""Lists Executions from a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_list_executions(): + # Create a client + client = run_v2.ExecutionsAsyncClient() + + # Initialize request argument(s) + request = run_v2.ListExecutionsRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_executions(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.ListExecutionsRequest, dict]]): + The request object. Request message for retrieving a + list of Executions. + parent (:class:`str`): + Required. The Execution from which + the Executions should be listed. To list + all Executions across Jobs, use "-" + instead of Job name. Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.services.executions.pagers.ListExecutionsAsyncPager: + Response message containing a list of + Executions. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = execution.ListExecutionsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_executions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListExecutionsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_execution( + self, + request: Optional[Union[execution.DeleteExecutionRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Deletes an Execution. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_delete_execution(): + # Create a client + client = run_v2.ExecutionsAsyncClient() + + # Initialize request argument(s) + request = run_v2.DeleteExecutionRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_execution(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.DeleteExecutionRequest, dict]]): + The request object. Request message for deleting an + Execution. + name (:class:`str`): + Required. The name of the Execution + to delete. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Execution` Execution represents the configuration of a single execution. A execution an + immutable resource that references a container image + which is run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = execution.DeleteExecutionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_execution, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + execution.Execution, + metadata_type=execution.Execution, + ) + + # Done; return the response. + return response + + async def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +__all__ = ("ExecutionsAsyncClient",) diff --git a/google/cloud/run_v2/services/executions/client.py b/google/cloud/run_v2/services/executions/client.py new file mode 100644 index 0000000..a16cce7 --- /dev/null +++ b/google/cloud/run_v2/services/executions/client.py @@ -0,0 +1,1090 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +import os +import re +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.api import launch_stage_pb2 # type: ignore +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.run_v2.services.executions import pagers +from google.cloud.run_v2.types import condition, execution, task_template + +from .transports.base import DEFAULT_CLIENT_INFO, ExecutionsTransport +from .transports.grpc import ExecutionsGrpcTransport +from .transports.grpc_asyncio import ExecutionsGrpcAsyncIOTransport +from .transports.rest import ExecutionsRestTransport + + +class ExecutionsClientMeta(type): + """Metaclass for the Executions client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[ExecutionsTransport]] + _transport_registry["grpc"] = ExecutionsGrpcTransport + _transport_registry["grpc_asyncio"] = ExecutionsGrpcAsyncIOTransport + _transport_registry["rest"] = ExecutionsRestTransport + + def get_transport_class( + cls, + label: Optional[str] = None, + ) -> Type[ExecutionsTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class ExecutionsClient(metaclass=ExecutionsClientMeta): + """Cloud Run Execution Control Plane API.""" + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "run.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + ExecutionsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + ExecutionsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> ExecutionsTransport: + """Returns the transport used by the client instance. + + Returns: + ExecutionsTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def connector_path( + project: str, + location: str, + connector: str, + ) -> str: + """Returns a fully-qualified connector string.""" + return "projects/{project}/locations/{location}/connectors/{connector}".format( + project=project, + location=location, + connector=connector, + ) + + @staticmethod + def parse_connector_path(path: str) -> Dict[str, str]: + """Parses a connector path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/connectors/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def crypto_key_path( + project: str, + location: str, + key_ring: str, + crypto_key: str, + ) -> str: + """Returns a fully-qualified crypto_key string.""" + return "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + + @staticmethod + def parse_crypto_key_path(path: str) -> Dict[str, str]: + """Parses a crypto_key path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/keyRings/(?P.+?)/cryptoKeys/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def execution_path( + project: str, + location: str, + job: str, + execution: str, + ) -> str: + """Returns a fully-qualified execution string.""" + return "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}".format( + project=project, + location=location, + job=job, + execution=execution, + ) + + @staticmethod + def parse_execution_path(path: str) -> Dict[str, str]: + """Parses a execution path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)/executions/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def job_path( + project: str, + location: str, + job: str, + ) -> str: + """Returns a fully-qualified job string.""" + return "projects/{project}/locations/{location}/jobs/{job}".format( + project=project, + location=location, + job=job, + ) + + @staticmethod + def parse_job_path(path: str) -> Dict[str, str]: + """Parses a job path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def secret_path( + project: str, + secret: str, + ) -> str: + """Returns a fully-qualified secret string.""" + return "projects/{project}/secrets/{secret}".format( + project=project, + secret=secret, + ) + + @staticmethod + def parse_secret_path(path: str) -> Dict[str, str]: + """Parses a secret path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/secrets/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def secret_version_path( + project: str, + secret: str, + version: str, + ) -> str: + """Returns a fully-qualified secret_version string.""" + return "projects/{project}/secrets/{secret}/versions/{version}".format( + project=project, + secret=secret, + version=version, + ) + + @staticmethod + def parse_secret_version_path(path: str) -> Dict[str, str]: + """Parses a secret_version path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/secrets/(?P.+?)/versions/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Optional[Union[str, ExecutionsTransport]] = None, + client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the executions client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ExecutionsTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + client_options = cast(client_options_lib.ClientOptions, client_options) + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, ExecutionsTransport): + # transport is a ExecutionsTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def get_execution( + self, + request: Optional[Union[execution.GetExecutionRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> execution.Execution: + r"""Gets information about an Execution. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_get_execution(): + # Create a client + client = run_v2.ExecutionsClient() + + # Initialize request argument(s) + request = run_v2.GetExecutionRequest( + name="name_value", + ) + + # Make the request + response = client.get_execution(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.GetExecutionRequest, dict]): + The request object. Request message for obtaining a + Execution by its full name. + name (str): + Required. The full name of the + Execution. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.types.Execution: + Execution represents the + configuration of a single execution. A + execution an immutable resource that + references a container image which is + run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a execution.GetExecutionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, execution.GetExecutionRequest): + request = execution.GetExecutionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_execution] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_executions( + self, + request: Optional[Union[execution.ListExecutionsRequest, dict]] = None, + *, + parent: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListExecutionsPager: + r"""Lists Executions from a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_list_executions(): + # Create a client + client = run_v2.ExecutionsClient() + + # Initialize request argument(s) + request = run_v2.ListExecutionsRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_executions(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.cloud.run_v2.types.ListExecutionsRequest, dict]): + The request object. Request message for retrieving a + list of Executions. + parent (str): + Required. The Execution from which + the Executions should be listed. To list + all Executions across Jobs, use "-" + instead of Job name. Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.services.executions.pagers.ListExecutionsPager: + Response message containing a list of + Executions. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a execution.ListExecutionsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, execution.ListExecutionsRequest): + request = execution.ListExecutionsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_executions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListExecutionsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_execution( + self, + request: Optional[Union[execution.DeleteExecutionRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Deletes an Execution. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_delete_execution(): + # Create a client + client = run_v2.ExecutionsClient() + + # Initialize request argument(s) + request = run_v2.DeleteExecutionRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_execution(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.DeleteExecutionRequest, dict]): + The request object. Request message for deleting an + Execution. + name (str): + Required. The name of the Execution + to delete. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Execution` Execution represents the configuration of a single execution. A execution an + immutable resource that references a container image + which is run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a execution.DeleteExecutionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, execution.DeleteExecutionRequest): + request = execution.DeleteExecutionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_execution] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + execution.Execution, + metadata_type=execution.Execution, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +__all__ = ("ExecutionsClient",) diff --git a/google/cloud/run_v2/services/executions/pagers.py b/google/cloud/run_v2/services/executions/pagers.py new file mode 100644 index 0000000..c0d6510 --- /dev/null +++ b/google/cloud/run_v2/services/executions/pagers.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Iterator, + Optional, + Sequence, + Tuple, +) + +from google.cloud.run_v2.types import execution + + +class ListExecutionsPager: + """A pager for iterating through ``list_executions`` requests. + + This class thinly wraps an initial + :class:`google.cloud.run_v2.types.ListExecutionsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``executions`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListExecutions`` requests and continue to iterate + through the ``executions`` field on the + corresponding responses. + + All the usual :class:`google.cloud.run_v2.types.ListExecutionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., execution.ListExecutionsResponse], + request: execution.ListExecutionsRequest, + response: execution.ListExecutionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.run_v2.types.ListExecutionsRequest): + The initial request object. + response (google.cloud.run_v2.types.ListExecutionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = execution.ListExecutionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[execution.ListExecutionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[execution.Execution]: + for page in self.pages: + yield from page.executions + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListExecutionsAsyncPager: + """A pager for iterating through ``list_executions`` requests. + + This class thinly wraps an initial + :class:`google.cloud.run_v2.types.ListExecutionsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``executions`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListExecutions`` requests and continue to iterate + through the ``executions`` field on the + corresponding responses. + + All the usual :class:`google.cloud.run_v2.types.ListExecutionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[execution.ListExecutionsResponse]], + request: execution.ListExecutionsRequest, + response: execution.ListExecutionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.run_v2.types.ListExecutionsRequest): + The initial request object. + response (google.cloud.run_v2.types.ListExecutionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = execution.ListExecutionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[execution.ListExecutionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[execution.Execution]: + async def async_generator(): + async for page in self.pages: + for response in page.executions: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/run_v2/services/executions/transports/__init__.py b/google/cloud/run_v2/services/executions/transports/__init__.py new file mode 100644 index 0000000..d231e58 --- /dev/null +++ b/google/cloud/run_v2/services/executions/transports/__init__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +from typing import Dict, Type + +from .base import ExecutionsTransport +from .grpc import ExecutionsGrpcTransport +from .grpc_asyncio import ExecutionsGrpcAsyncIOTransport +from .rest import ExecutionsRestInterceptor, ExecutionsRestTransport + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[ExecutionsTransport]] +_transport_registry["grpc"] = ExecutionsGrpcTransport +_transport_registry["grpc_asyncio"] = ExecutionsGrpcAsyncIOTransport +_transport_registry["rest"] = ExecutionsRestTransport + +__all__ = ( + "ExecutionsTransport", + "ExecutionsGrpcTransport", + "ExecutionsGrpcAsyncIOTransport", + "ExecutionsRestTransport", + "ExecutionsRestInterceptor", +) diff --git a/google/cloud/run_v2/services/executions/transports/base.py b/google/cloud/run_v2/services/executions/transports/base.py new file mode 100644 index 0000000..3d8005c --- /dev/null +++ b/google/cloud/run_v2/services/executions/transports/base.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union + +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1, operations_v1 +from google.api_core import retry as retries +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version +from google.cloud.run_v2.types import execution + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +class ExecutionsTransport(abc.ABC): + """Abstract transport class for Executions.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + DEFAULT_HOST: str = "run.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.get_execution: gapic_v1.method.wrap_method( + self.get_execution, + default_timeout=None, + client_info=client_info, + ), + self.list_executions: gapic_v1.method.wrap_method( + self.list_executions, + default_timeout=None, + client_info=client_info, + ), + self.delete_execution: gapic_v1.method.wrap_method( + self.delete_execution, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def operations_client(self): + """Return the client designed to process long-running operations.""" + raise NotImplementedError() + + @property + def get_execution( + self, + ) -> Callable[ + [execution.GetExecutionRequest], + Union[execution.Execution, Awaitable[execution.Execution]], + ]: + raise NotImplementedError() + + @property + def list_executions( + self, + ) -> Callable[ + [execution.ListExecutionsRequest], + Union[ + execution.ListExecutionsResponse, + Awaitable[execution.ListExecutionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def delete_execution( + self, + ) -> Callable[ + [execution.DeleteExecutionRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], + Union[ + operations_pb2.ListOperationsResponse, + Awaitable[operations_pb2.ListOperationsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("ExecutionsTransport",) diff --git a/google/cloud/run_v2/services/executions/transports/grpc.py b/google/cloud/run_v2/services/executions/transports/grpc.py new file mode 100644 index 0000000..cb26b6a --- /dev/null +++ b/google/cloud/run_v2/services/executions/transports/grpc.py @@ -0,0 +1,387 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers, operations_v1 +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore +import grpc # type: ignore + +from google.cloud.run_v2.types import execution + +from .base import DEFAULT_CLIENT_INFO, ExecutionsTransport + + +class ExecutionsGrpcTransport(ExecutionsTransport): + """gRPC backend transport for Executions. + + Cloud Run Execution Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[grpc.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client: Optional[operations_v1.OperationsClient] = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Quick check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsClient(self.grpc_channel) + + # Return the client from cache. + return self._operations_client + + @property + def get_execution( + self, + ) -> Callable[[execution.GetExecutionRequest], execution.Execution]: + r"""Return a callable for the get execution method over gRPC. + + Gets information about an Execution. + + Returns: + Callable[[~.GetExecutionRequest], + ~.Execution]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_execution" not in self._stubs: + self._stubs["get_execution"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Executions/GetExecution", + request_serializer=execution.GetExecutionRequest.serialize, + response_deserializer=execution.Execution.deserialize, + ) + return self._stubs["get_execution"] + + @property + def list_executions( + self, + ) -> Callable[[execution.ListExecutionsRequest], execution.ListExecutionsResponse]: + r"""Return a callable for the list executions method over gRPC. + + Lists Executions from a Job. + + Returns: + Callable[[~.ListExecutionsRequest], + ~.ListExecutionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_executions" not in self._stubs: + self._stubs["list_executions"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Executions/ListExecutions", + request_serializer=execution.ListExecutionsRequest.serialize, + response_deserializer=execution.ListExecutionsResponse.deserialize, + ) + return self._stubs["list_executions"] + + @property + def delete_execution( + self, + ) -> Callable[[execution.DeleteExecutionRequest], operations_pb2.Operation]: + r"""Return a callable for the delete execution method over gRPC. + + Deletes an Execution. + + Returns: + Callable[[~.DeleteExecutionRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_execution" not in self._stubs: + self._stubs["delete_execution"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Executions/DeleteExecution", + request_serializer=execution.DeleteExecutionRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["delete_execution"] + + def close(self): + self.grpc_channel.close() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("ExecutionsGrpcTransport",) diff --git a/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py b/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py new file mode 100644 index 0000000..41fd7a9 --- /dev/null +++ b/google/cloud/run_v2/services/executions/transports/grpc_asyncio.py @@ -0,0 +1,392 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers_async, operations_v1 +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.run_v2.types import execution + +from .base import DEFAULT_CLIENT_INFO, ExecutionsTransport +from .grpc import ExecutionsGrpcTransport + + +class ExecutionsGrpcAsyncIOTransport(ExecutionsTransport): + """gRPC AsyncIO backend transport for Executions. + + Cloud Run Execution Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[aio.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client: Optional[operations_v1.OperationsAsyncClient] = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsAsyncClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Quick check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsAsyncClient( + self.grpc_channel + ) + + # Return the client from cache. + return self._operations_client + + @property + def get_execution( + self, + ) -> Callable[[execution.GetExecutionRequest], Awaitable[execution.Execution]]: + r"""Return a callable for the get execution method over gRPC. + + Gets information about an Execution. + + Returns: + Callable[[~.GetExecutionRequest], + Awaitable[~.Execution]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_execution" not in self._stubs: + self._stubs["get_execution"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Executions/GetExecution", + request_serializer=execution.GetExecutionRequest.serialize, + response_deserializer=execution.Execution.deserialize, + ) + return self._stubs["get_execution"] + + @property + def list_executions( + self, + ) -> Callable[ + [execution.ListExecutionsRequest], Awaitable[execution.ListExecutionsResponse] + ]: + r"""Return a callable for the list executions method over gRPC. + + Lists Executions from a Job. + + Returns: + Callable[[~.ListExecutionsRequest], + Awaitable[~.ListExecutionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_executions" not in self._stubs: + self._stubs["list_executions"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Executions/ListExecutions", + request_serializer=execution.ListExecutionsRequest.serialize, + response_deserializer=execution.ListExecutionsResponse.deserialize, + ) + return self._stubs["list_executions"] + + @property + def delete_execution( + self, + ) -> Callable[ + [execution.DeleteExecutionRequest], Awaitable[operations_pb2.Operation] + ]: + r"""Return a callable for the delete execution method over gRPC. + + Deletes an Execution. + + Returns: + Callable[[~.DeleteExecutionRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_execution" not in self._stubs: + self._stubs["delete_execution"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Executions/DeleteExecution", + request_serializer=execution.DeleteExecutionRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["delete_execution"] + + def close(self): + return self.grpc_channel.close() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + + +__all__ = ("ExecutionsGrpcAsyncIOTransport",) diff --git a/google/cloud/run_v2/services/executions/transports/rest.py b/google/cloud/run_v2/services/executions/transports/rest.py new file mode 100644 index 0000000..8455972 --- /dev/null +++ b/google/cloud/run_v2/services/executions/transports/rest.py @@ -0,0 +1,889 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 dataclasses +import json # type: ignore +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore + +from google.cloud.run_v2.types import execution + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import ExecutionsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ExecutionsRestInterceptor: + """Interceptor for Executions. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ExecutionsRestTransport. + + .. code-block:: python + class MyCustomExecutionsInterceptor(ExecutionsRestInterceptor): + def pre_delete_execution(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_delete_execution(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_execution(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_execution(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_executions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_executions(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ExecutionsRestTransport(interceptor=MyCustomExecutionsInterceptor()) + client = ExecutionsClient(transport=transport) + + + """ + + def pre_delete_execution( + self, + request: execution.DeleteExecutionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[execution.DeleteExecutionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_execution + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_delete_execution( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for delete_execution + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + + def pre_get_execution( + self, + request: execution.GetExecutionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[execution.GetExecutionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_execution + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_get_execution(self, response: execution.Execution) -> execution.Execution: + """Post-rpc interceptor for get_execution + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + + def pre_list_executions( + self, + request: execution.ListExecutionsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[execution.ListExecutionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_executions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_list_executions( + self, response: execution.ListExecutionsResponse + ) -> execution.ListExecutionsResponse: + """Post-rpc interceptor for list_executions + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + + def pre_delete_operation( + self, + request: operations_pb2.DeleteOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> None: + """Pre-rpc interceptor for delete_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_delete_operation( + self, response: operations_pb2.DeleteOperationRequest + ) -> None: + """Post-rpc interceptor for delete_operation + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.GetOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.ListOperationsResponse: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Executions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsRequest + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Executions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ExecutionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ExecutionsRestInterceptor + + +class ExecutionsRestTransport(ExecutionsTransport): + """REST backend transport for Executions. + + Cloud Run Execution Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ExecutionsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ExecutionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.DeleteOperation": [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _DeleteExecution(ExecutionsRestStub): + def __hash__(self): + return hash("DeleteExecution") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: execution.DeleteExecutionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the delete execution method over HTTP. + + Args: + request (~.execution.DeleteExecutionRequest): + The request object. Request message for deleting an + Execution. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/jobs/*/executions/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_execution( + request, metadata + ) + pb_request = execution.DeleteExecutionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_delete_execution(resp) + return resp + + class _GetExecution(ExecutionsRestStub): + def __hash__(self): + return hash("GetExecution") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: execution.GetExecutionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> execution.Execution: + r"""Call the get execution method over HTTP. + + Args: + request (~.execution.GetExecutionRequest): + The request object. Request message for obtaining a + Execution by its full name. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.execution.Execution: + Execution represents the + configuration of a single execution. A + execution an immutable resource that + references a container image which is + run to completion. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/jobs/*/executions/*}", + }, + ] + request, metadata = self._interceptor.pre_get_execution(request, metadata) + pb_request = execution.GetExecutionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = execution.Execution() + pb_resp = execution.Execution.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_execution(resp) + return resp + + class _ListExecutions(ExecutionsRestStub): + def __hash__(self): + return hash("ListExecutions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: execution.ListExecutionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> execution.ListExecutionsResponse: + r"""Call the list executions method over HTTP. + + Args: + request (~.execution.ListExecutionsRequest): + The request object. Request message for retrieving a list + of Executions. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.execution.ListExecutionsResponse: + Response message containing a list of + Executions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/jobs/*}/executions", + }, + ] + request, metadata = self._interceptor.pre_list_executions(request, metadata) + pb_request = execution.ListExecutionsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = execution.ListExecutionsResponse() + pb_resp = execution.ListExecutionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_executions(resp) + return resp + + @property + def delete_execution( + self, + ) -> Callable[[execution.DeleteExecutionRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteExecution(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_execution( + self, + ) -> Callable[[execution.GetExecutionRequest], execution.Execution]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetExecution(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_executions( + self, + ) -> Callable[[execution.ListExecutionsRequest], execution.ListExecutionsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListExecutions(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_operation(self): + return self._DeleteOperation(self._session, self._host, self._interceptor) # type: ignore + + class _DeleteOperation(ExecutionsRestStub): + def __call__( + self, + request: operations_pb2.DeleteOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the delete operation method over HTTP. + + Args: + request (operations_pb2.DeleteOperationRequest): + The request object for DeleteOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_delete_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_delete_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ExecutionsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ExecutionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ExecutionsRestTransport",) diff --git a/google/cloud/run_v2/services/jobs/__init__.py b/google/cloud/run_v2/services/jobs/__init__.py new file mode 100644 index 0000000..c6a4e7a --- /dev/null +++ b/google/cloud/run_v2/services/jobs/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 .async_client import JobsAsyncClient +from .client import JobsClient + +__all__ = ( + "JobsClient", + "JobsAsyncClient", +) diff --git a/google/cloud/run_v2/services/jobs/async_client.py b/google/cloud/run_v2/services/jobs/async_client.py new file mode 100644 index 0000000..1371f90 --- /dev/null +++ b/google/cloud/run_v2/services/jobs/async_client.py @@ -0,0 +1,1504 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +import functools +import re +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.api import launch_stage_pb2 # type: ignore +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.run_v2.services.jobs import pagers +from google.cloud.run_v2.types import condition, execution, execution_template +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job +from google.cloud.run_v2.types import vendor_settings + +from .client import JobsClient +from .transports.base import DEFAULT_CLIENT_INFO, JobsTransport +from .transports.grpc_asyncio import JobsGrpcAsyncIOTransport + + +class JobsAsyncClient: + """Cloud Run Job Control Plane API.""" + + _client: JobsClient + + DEFAULT_ENDPOINT = JobsClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = JobsClient.DEFAULT_MTLS_ENDPOINT + + connector_path = staticmethod(JobsClient.connector_path) + parse_connector_path = staticmethod(JobsClient.parse_connector_path) + crypto_key_path = staticmethod(JobsClient.crypto_key_path) + parse_crypto_key_path = staticmethod(JobsClient.parse_crypto_key_path) + execution_path = staticmethod(JobsClient.execution_path) + parse_execution_path = staticmethod(JobsClient.parse_execution_path) + job_path = staticmethod(JobsClient.job_path) + parse_job_path = staticmethod(JobsClient.parse_job_path) + secret_path = staticmethod(JobsClient.secret_path) + parse_secret_path = staticmethod(JobsClient.parse_secret_path) + secret_version_path = staticmethod(JobsClient.secret_version_path) + parse_secret_version_path = staticmethod(JobsClient.parse_secret_version_path) + common_billing_account_path = staticmethod(JobsClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod( + JobsClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(JobsClient.common_folder_path) + parse_common_folder_path = staticmethod(JobsClient.parse_common_folder_path) + common_organization_path = staticmethod(JobsClient.common_organization_path) + parse_common_organization_path = staticmethod( + JobsClient.parse_common_organization_path + ) + common_project_path = staticmethod(JobsClient.common_project_path) + parse_common_project_path = staticmethod(JobsClient.parse_common_project_path) + common_location_path = staticmethod(JobsClient.common_location_path) + parse_common_location_path = staticmethod(JobsClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + JobsAsyncClient: The constructed client. + """ + return JobsClient.from_service_account_info.__func__(JobsAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + JobsAsyncClient: The constructed client. + """ + return JobsClient.from_service_account_file.__func__(JobsAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return JobsClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> JobsTransport: + """Returns the transport used by the client instance. + + Returns: + JobsTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(JobsClient).get_transport_class, type(JobsClient) + ) + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, JobsTransport] = "grpc_asyncio", + client_options: Optional[ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the jobs client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.JobsTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = JobsClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def create_job( + self, + request: Optional[Union[gcr_job.CreateJobRequest, dict]] = None, + *, + parent: Optional[str] = None, + job: Optional[gcr_job.Job] = None, + job_id: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Creates a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_create_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.CreateJobRequest( + parent="parent_value", + job=job, + job_id="job_id_value", + ) + + # Make the request + operation = client.create_job(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.CreateJobRequest, dict]]): + The request object. Request message for creating a Job. + parent (:class:`str`): + Required. The location and project in + which this Job should be created. + Format: + projects/{project}/locations/{location}, + where {project} can be project id or + number. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + job (:class:`google.cloud.run_v2.types.Job`): + Required. The Job instance to create. + This corresponds to the ``job`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + job_id (:class:`str`): + Required. The unique identifier for the Job. The name of + the job becomes {parent}/jobs/{job_id}. + + This corresponds to the ``job_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource + that references a container image which is run to + completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, job, job_id]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gcr_job.CreateJobRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if job is not None: + request.job = job + if job_id is not None: + request.job_id = job_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_job, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + gcr_job.Job, + metadata_type=gcr_job.Job, + ) + + # Done; return the response. + return response + + async def get_job( + self, + request: Optional[Union[job.GetJobRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> job.Job: + r"""Gets information about a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_get_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = run_v2.GetJobRequest( + name="name_value", + ) + + # Make the request + response = await client.get_job(request=request) + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.GetJobRequest, dict]]): + The request object. Request message for obtaining a Job + by its full name. + name (:class:`str`): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.types.Job: + Job represents the configuration of a + single job. A job an immutable resource + that references a container image which + is run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = job.GetJobRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_job, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_jobs( + self, + request: Optional[Union[job.ListJobsRequest, dict]] = None, + *, + parent: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListJobsAsyncPager: + r"""Lists Jobs. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_list_jobs(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = run_v2.ListJobsRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_jobs(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.ListJobsRequest, dict]]): + The request object. Request message for retrieving a + list of Jobs. + parent (:class:`str`): + Required. The location and project to + list resources on. Format: + projects/{project}/locations/{location}, + where {project} can be project id or + number. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.services.jobs.pagers.ListJobsAsyncPager: + Response message containing a list of + Jobs. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = job.ListJobsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_jobs, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListJobsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_job( + self, + request: Optional[Union[gcr_job.UpdateJobRequest, dict]] = None, + *, + job: Optional[gcr_job.Job] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Updates a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_update_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.UpdateJobRequest( + job=job, + ) + + # Make the request + operation = client.update_job(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.UpdateJobRequest, dict]]): + The request object. Request message for updating a Job. + job (:class:`google.cloud.run_v2.types.Job`): + Required. The Job to be updated. + This corresponds to the ``job`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource + that references a container image which is run to + completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([job]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gcr_job.UpdateJobRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if job is not None: + request.job = job + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_job, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("job.name", request.job.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + gcr_job.Job, + metadata_type=gcr_job.Job, + ) + + # Done; return the response. + return response + + async def delete_job( + self, + request: Optional[Union[job.DeleteJobRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Deletes a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_delete_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = run_v2.DeleteJobRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_job(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.DeleteJobRequest, dict]]): + The request object. Request message to delete a Job by + its full name. + name (:class:`str`): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource + that references a container image which is run to + completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = job.DeleteJobRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_job, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + job.Job, + metadata_type=job.Job, + ) + + # Done; return the response. + return response + + async def run_job( + self, + request: Optional[Union[job.RunJobRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Triggers creation of a new Execution of this Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_run_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = run_v2.RunJobRequest( + name="name_value", + ) + + # Make the request + operation = client.run_job(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.RunJobRequest, dict]]): + The request object. Request message to create a new + Execution of a Job. + name (:class:`str`): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Execution` Execution represents the configuration of a single execution. A execution an + immutable resource that references a container image + which is run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = job.RunJobRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.run_job, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + execution.Execution, + metadata_type=execution.Execution, + ) + + # Done; return the response. + return response + + async def get_iam_policy( + self, + request: Optional[Union[iam_policy_pb2.GetIamPolicyRequest, dict]] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM Access Control policy currently in + effect for the given Job. This result does not include + any inherited policies. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + from google.iam.v1 import iam_policy_pb2 # type: ignore + + async def sample_get_iam_policy(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = iam_policy_pb2.GetIamPolicyRequest( + resource="resource_value", + ) + + # Make the request + response = await client.get_iam_policy(request=request) + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.iam.v1.iam_policy_pb2.GetIamPolicyRequest, dict]]): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.iam.v1.policy_pb2.Policy: + An Identity and Access Management (IAM) policy, which specifies access + controls for Google Cloud resources. + + A Policy is a collection of bindings. A binding binds + one or more members, or principals, to a single role. + Principals can be user accounts, service accounts, + Google groups, and domains (such as G Suite). A role + is a named list of permissions; each role can be an + IAM predefined role or a user-created custom role. + + For some types of Google Cloud resources, a binding + can also specify a condition, which is a logical + expression that allows access to a resource only if + the expression evaluates to true. A condition can add + constraints based on attributes of the request, the + resource, or both. To learn which resources support + conditions in their IAM policies, see the [IAM + documentation](\ https://cloud.google.com/iam/help/conditions/resource-policies). + + **JSON example:** + + { + "bindings": [ + { + "role": + "roles/resourcemanager.organizationAdmin", + "members": [ "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + + }, { "role": + "roles/resourcemanager.organizationViewer", + "members": [ "user:eve@example.com" ], + "condition": { "title": "expirable access", + "description": "Does not grant access after + Sep 2020", "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", } } + + ], "etag": "BwWWja0YfJA=", "version": 3 + + } + + **YAML example:** + + bindings: - members: - user:\ mike@example.com - + group:\ admins@example.com - domain:google.com - + serviceAccount:\ my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin - + members: - user:\ eve@example.com role: + roles/resourcemanager.organizationViewer + condition: title: expirable access description: + Does not grant access after Sep 2020 expression: + request.time < + timestamp('2020-10-01T00:00:00.000Z') etag: + BwWWja0YfJA= version: 3 + + For a description of IAM and its features, see the + [IAM + documentation](\ https://cloud.google.com/iam/docs/). + + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def set_iam_policy( + self, + request: Optional[Union[iam_policy_pb2.SetIamPolicyRequest, dict]] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM Access control policy for the specified + Job. Overwrites any existing policy. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + from google.iam.v1 import iam_policy_pb2 # type: ignore + + async def sample_set_iam_policy(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = iam_policy_pb2.SetIamPolicyRequest( + resource="resource_value", + ) + + # Make the request + response = await client.set_iam_policy(request=request) + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.iam.v1.iam_policy_pb2.SetIamPolicyRequest, dict]]): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.iam.v1.policy_pb2.Policy: + An Identity and Access Management (IAM) policy, which specifies access + controls for Google Cloud resources. + + A Policy is a collection of bindings. A binding binds + one or more members, or principals, to a single role. + Principals can be user accounts, service accounts, + Google groups, and domains (such as G Suite). A role + is a named list of permissions; each role can be an + IAM predefined role or a user-created custom role. + + For some types of Google Cloud resources, a binding + can also specify a condition, which is a logical + expression that allows access to a resource only if + the expression evaluates to true. A condition can add + constraints based on attributes of the request, the + resource, or both. To learn which resources support + conditions in their IAM policies, see the [IAM + documentation](\ https://cloud.google.com/iam/help/conditions/resource-policies). + + **JSON example:** + + { + "bindings": [ + { + "role": + "roles/resourcemanager.organizationAdmin", + "members": [ "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + + }, { "role": + "roles/resourcemanager.organizationViewer", + "members": [ "user:eve@example.com" ], + "condition": { "title": "expirable access", + "description": "Does not grant access after + Sep 2020", "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", } } + + ], "etag": "BwWWja0YfJA=", "version": 3 + + } + + **YAML example:** + + bindings: - members: - user:\ mike@example.com - + group:\ admins@example.com - domain:google.com - + serviceAccount:\ my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin - + members: - user:\ eve@example.com role: + roles/resourcemanager.organizationViewer + condition: title: expirable access description: + Does not grant access after Sep 2020 expression: + request.time < + timestamp('2020-10-01T00:00:00.000Z') etag: + BwWWja0YfJA= version: 3 + + For a description of IAM and its features, see the + [IAM + documentation](\ https://cloud.google.com/iam/docs/). + + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def test_iam_permissions( + self, + request: Optional[Union[iam_policy_pb2.TestIamPermissionsRequest, dict]] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Returns permissions that a caller has on the + specified Project. + There are no permissions required for making this API + call. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + from google.iam.v1 import iam_policy_pb2 # type: ignore + + async def sample_test_iam_permissions(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = iam_policy_pb2.TestIamPermissionsRequest( + resource="resource_value", + permissions=['permissions_value1', 'permissions_value2'], + ) + + # Make the request + response = await client.test_iam_permissions(request=request) + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest, dict]]): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.iam.v1.iam_policy_pb2.TestIamPermissionsResponse: + Response message for TestIamPermissions method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +__all__ = ("JobsAsyncClient",) diff --git a/google/cloud/run_v2/services/jobs/client.py b/google/cloud/run_v2/services/jobs/client.py new file mode 100644 index 0000000..fdd516a --- /dev/null +++ b/google/cloud/run_v2/services/jobs/client.py @@ -0,0 +1,1844 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +import os +import re +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.api import launch_stage_pb2 # type: ignore +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.run_v2.services.jobs import pagers +from google.cloud.run_v2.types import condition, execution, execution_template +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job +from google.cloud.run_v2.types import vendor_settings + +from .transports.base import DEFAULT_CLIENT_INFO, JobsTransport +from .transports.grpc import JobsGrpcTransport +from .transports.grpc_asyncio import JobsGrpcAsyncIOTransport +from .transports.rest import JobsRestTransport + + +class JobsClientMeta(type): + """Metaclass for the Jobs client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[JobsTransport]] + _transport_registry["grpc"] = JobsGrpcTransport + _transport_registry["grpc_asyncio"] = JobsGrpcAsyncIOTransport + _transport_registry["rest"] = JobsRestTransport + + def get_transport_class( + cls, + label: Optional[str] = None, + ) -> Type[JobsTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class JobsClient(metaclass=JobsClientMeta): + """Cloud Run Job Control Plane API.""" + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "run.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + JobsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + JobsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> JobsTransport: + """Returns the transport used by the client instance. + + Returns: + JobsTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def connector_path( + project: str, + location: str, + connector: str, + ) -> str: + """Returns a fully-qualified connector string.""" + return "projects/{project}/locations/{location}/connectors/{connector}".format( + project=project, + location=location, + connector=connector, + ) + + @staticmethod + def parse_connector_path(path: str) -> Dict[str, str]: + """Parses a connector path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/connectors/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def crypto_key_path( + project: str, + location: str, + key_ring: str, + crypto_key: str, + ) -> str: + """Returns a fully-qualified crypto_key string.""" + return "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + + @staticmethod + def parse_crypto_key_path(path: str) -> Dict[str, str]: + """Parses a crypto_key path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/keyRings/(?P.+?)/cryptoKeys/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def execution_path( + project: str, + location: str, + job: str, + execution: str, + ) -> str: + """Returns a fully-qualified execution string.""" + return "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}".format( + project=project, + location=location, + job=job, + execution=execution, + ) + + @staticmethod + def parse_execution_path(path: str) -> Dict[str, str]: + """Parses a execution path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)/executions/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def job_path( + project: str, + location: str, + job: str, + ) -> str: + """Returns a fully-qualified job string.""" + return "projects/{project}/locations/{location}/jobs/{job}".format( + project=project, + location=location, + job=job, + ) + + @staticmethod + def parse_job_path(path: str) -> Dict[str, str]: + """Parses a job path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def secret_path( + project: str, + secret: str, + ) -> str: + """Returns a fully-qualified secret string.""" + return "projects/{project}/secrets/{secret}".format( + project=project, + secret=secret, + ) + + @staticmethod + def parse_secret_path(path: str) -> Dict[str, str]: + """Parses a secret path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/secrets/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def secret_version_path( + project: str, + secret: str, + version: str, + ) -> str: + """Returns a fully-qualified secret_version string.""" + return "projects/{project}/secrets/{secret}/versions/{version}".format( + project=project, + secret=secret, + version=version, + ) + + @staticmethod + def parse_secret_version_path(path: str) -> Dict[str, str]: + """Parses a secret_version path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/secrets/(?P.+?)/versions/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Optional[Union[str, JobsTransport]] = None, + client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the jobs client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, JobsTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + client_options = cast(client_options_lib.ClientOptions, client_options) + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, JobsTransport): + # transport is a JobsTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def create_job( + self, + request: Optional[Union[gcr_job.CreateJobRequest, dict]] = None, + *, + parent: Optional[str] = None, + job: Optional[gcr_job.Job] = None, + job_id: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Creates a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_create_job(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.CreateJobRequest( + parent="parent_value", + job=job, + job_id="job_id_value", + ) + + # Make the request + operation = client.create_job(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.CreateJobRequest, dict]): + The request object. Request message for creating a Job. + parent (str): + Required. The location and project in + which this Job should be created. + Format: + projects/{project}/locations/{location}, + where {project} can be project id or + number. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + job (google.cloud.run_v2.types.Job): + Required. The Job instance to create. + This corresponds to the ``job`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + job_id (str): + Required. The unique identifier for the Job. The name of + the job becomes {parent}/jobs/{job_id}. + + This corresponds to the ``job_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource + that references a container image which is run to + completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, job, job_id]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gcr_job.CreateJobRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gcr_job.CreateJobRequest): + request = gcr_job.CreateJobRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if job is not None: + request.job = job + if job_id is not None: + request.job_id = job_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_job] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + gcr_job.Job, + metadata_type=gcr_job.Job, + ) + + # Done; return the response. + return response + + def get_job( + self, + request: Optional[Union[job.GetJobRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> job.Job: + r"""Gets information about a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_get_job(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = run_v2.GetJobRequest( + name="name_value", + ) + + # Make the request + response = client.get_job(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.GetJobRequest, dict]): + The request object. Request message for obtaining a Job + by its full name. + name (str): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.types.Job: + Job represents the configuration of a + single job. A job an immutable resource + that references a container image which + is run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a job.GetJobRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, job.GetJobRequest): + request = job.GetJobRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_job] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_jobs( + self, + request: Optional[Union[job.ListJobsRequest, dict]] = None, + *, + parent: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListJobsPager: + r"""Lists Jobs. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_list_jobs(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = run_v2.ListJobsRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_jobs(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.cloud.run_v2.types.ListJobsRequest, dict]): + The request object. Request message for retrieving a + list of Jobs. + parent (str): + Required. The location and project to + list resources on. Format: + projects/{project}/locations/{location}, + where {project} can be project id or + number. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.services.jobs.pagers.ListJobsPager: + Response message containing a list of + Jobs. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a job.ListJobsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, job.ListJobsRequest): + request = job.ListJobsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_jobs] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListJobsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_job( + self, + request: Optional[Union[gcr_job.UpdateJobRequest, dict]] = None, + *, + job: Optional[gcr_job.Job] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Updates a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_update_job(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.UpdateJobRequest( + job=job, + ) + + # Make the request + operation = client.update_job(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.UpdateJobRequest, dict]): + The request object. Request message for updating a Job. + job (google.cloud.run_v2.types.Job): + Required. The Job to be updated. + This corresponds to the ``job`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource + that references a container image which is run to + completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([job]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gcr_job.UpdateJobRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gcr_job.UpdateJobRequest): + request = gcr_job.UpdateJobRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if job is not None: + request.job = job + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_job] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("job.name", request.job.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + gcr_job.Job, + metadata_type=gcr_job.Job, + ) + + # Done; return the response. + return response + + def delete_job( + self, + request: Optional[Union[job.DeleteJobRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Deletes a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_delete_job(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = run_v2.DeleteJobRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_job(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.DeleteJobRequest, dict]): + The request object. Request message to delete a Job by + its full name. + name (str): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Job` Job represents the configuration of a single job. A job an immutable resource + that references a container image which is run to + completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a job.DeleteJobRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, job.DeleteJobRequest): + request = job.DeleteJobRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_job] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + job.Job, + metadata_type=job.Job, + ) + + # Done; return the response. + return response + + def run_job( + self, + request: Optional[Union[job.RunJobRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Triggers creation of a new Execution of this Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_run_job(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = run_v2.RunJobRequest( + name="name_value", + ) + + # Make the request + operation = client.run_job(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.RunJobRequest, dict]): + The request object. Request message to create a new + Execution of a Job. + name (str): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or + number. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.run_v2.types.Execution` Execution represents the configuration of a single execution. A execution an + immutable resource that references a container image + which is run to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a job.RunJobRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, job.RunJobRequest): + request = job.RunJobRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.run_job] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + execution.Execution, + metadata_type=execution.Execution, + ) + + # Done; return the response. + return response + + def get_iam_policy( + self, + request: Optional[Union[iam_policy_pb2.GetIamPolicyRequest, dict]] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM Access Control policy currently in + effect for the given Job. This result does not include + any inherited policies. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + from google.iam.v1 import iam_policy_pb2 # type: ignore + + def sample_get_iam_policy(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = iam_policy_pb2.GetIamPolicyRequest( + resource="resource_value", + ) + + # Make the request + response = client.get_iam_policy(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.iam.v1.iam_policy_pb2.GetIamPolicyRequest, dict]): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.iam.v1.policy_pb2.Policy: + An Identity and Access Management (IAM) policy, which specifies access + controls for Google Cloud resources. + + A Policy is a collection of bindings. A binding binds + one or more members, or principals, to a single role. + Principals can be user accounts, service accounts, + Google groups, and domains (such as G Suite). A role + is a named list of permissions; each role can be an + IAM predefined role or a user-created custom role. + + For some types of Google Cloud resources, a binding + can also specify a condition, which is a logical + expression that allows access to a resource only if + the expression evaluates to true. A condition can add + constraints based on attributes of the request, the + resource, or both. To learn which resources support + conditions in their IAM policies, see the [IAM + documentation](\ https://cloud.google.com/iam/help/conditions/resource-policies). + + **JSON example:** + + { + "bindings": [ + { + "role": + "roles/resourcemanager.organizationAdmin", + "members": [ "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + + }, { "role": + "roles/resourcemanager.organizationViewer", + "members": [ "user:eve@example.com" ], + "condition": { "title": "expirable access", + "description": "Does not grant access after + Sep 2020", "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", } } + + ], "etag": "BwWWja0YfJA=", "version": 3 + + } + + **YAML example:** + + bindings: - members: - user:\ mike@example.com - + group:\ admins@example.com - domain:google.com - + serviceAccount:\ my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin - + members: - user:\ eve@example.com role: + roles/resourcemanager.organizationViewer + condition: title: expirable access description: + Does not grant access after Sep 2020 expression: + request.time < + timestamp('2020-10-01T00:00:00.000Z') etag: + BwWWja0YfJA= version: 3 + + For a description of IAM and its features, see the + [IAM + documentation](\ https://cloud.google.com/iam/docs/). + + """ + # Create or coerce a protobuf request object. + if isinstance(request, dict): + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + request = iam_policy_pb2.GetIamPolicyRequest(**request) + elif not request: + # Null request, just make one. + request = iam_policy_pb2.GetIamPolicyRequest() + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_iam_policy] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def set_iam_policy( + self, + request: Optional[Union[iam_policy_pb2.SetIamPolicyRequest, dict]] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM Access control policy for the specified + Job. Overwrites any existing policy. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + from google.iam.v1 import iam_policy_pb2 # type: ignore + + def sample_set_iam_policy(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = iam_policy_pb2.SetIamPolicyRequest( + resource="resource_value", + ) + + # Make the request + response = client.set_iam_policy(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.iam.v1.iam_policy_pb2.SetIamPolicyRequest, dict]): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.iam.v1.policy_pb2.Policy: + An Identity and Access Management (IAM) policy, which specifies access + controls for Google Cloud resources. + + A Policy is a collection of bindings. A binding binds + one or more members, or principals, to a single role. + Principals can be user accounts, service accounts, + Google groups, and domains (such as G Suite). A role + is a named list of permissions; each role can be an + IAM predefined role or a user-created custom role. + + For some types of Google Cloud resources, a binding + can also specify a condition, which is a logical + expression that allows access to a resource only if + the expression evaluates to true. A condition can add + constraints based on attributes of the request, the + resource, or both. To learn which resources support + conditions in their IAM policies, see the [IAM + documentation](\ https://cloud.google.com/iam/help/conditions/resource-policies). + + **JSON example:** + + { + "bindings": [ + { + "role": + "roles/resourcemanager.organizationAdmin", + "members": [ "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + + }, { "role": + "roles/resourcemanager.organizationViewer", + "members": [ "user:eve@example.com" ], + "condition": { "title": "expirable access", + "description": "Does not grant access after + Sep 2020", "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", } } + + ], "etag": "BwWWja0YfJA=", "version": 3 + + } + + **YAML example:** + + bindings: - members: - user:\ mike@example.com - + group:\ admins@example.com - domain:google.com - + serviceAccount:\ my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin - + members: - user:\ eve@example.com role: + roles/resourcemanager.organizationViewer + condition: title: expirable access description: + Does not grant access after Sep 2020 expression: + request.time < + timestamp('2020-10-01T00:00:00.000Z') etag: + BwWWja0YfJA= version: 3 + + For a description of IAM and its features, see the + [IAM + documentation](\ https://cloud.google.com/iam/docs/). + + """ + # Create or coerce a protobuf request object. + if isinstance(request, dict): + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + request = iam_policy_pb2.SetIamPolicyRequest(**request) + elif not request: + # Null request, just make one. + request = iam_policy_pb2.SetIamPolicyRequest() + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.set_iam_policy] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def test_iam_permissions( + self, + request: Optional[Union[iam_policy_pb2.TestIamPermissionsRequest, dict]] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Returns permissions that a caller has on the + specified Project. + There are no permissions required for making this API + call. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + from google.iam.v1 import iam_policy_pb2 # type: ignore + + def sample_test_iam_permissions(): + # Create a client + client = run_v2.JobsClient() + + # Initialize request argument(s) + request = iam_policy_pb2.TestIamPermissionsRequest( + resource="resource_value", + permissions=['permissions_value1', 'permissions_value2'], + ) + + # Make the request + response = client.test_iam_permissions(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest, dict]): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.iam.v1.iam_policy_pb2.TestIamPermissionsResponse: + Response message for TestIamPermissions method. + """ + # Create or coerce a protobuf request object. + if isinstance(request, dict): + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + elif not request: + # Null request, just make one. + request = iam_policy_pb2.TestIamPermissionsRequest() + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.test_iam_permissions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +__all__ = ("JobsClient",) diff --git a/google/cloud/run_v2/services/jobs/pagers.py b/google/cloud/run_v2/services/jobs/pagers.py new file mode 100644 index 0000000..8ed23d9 --- /dev/null +++ b/google/cloud/run_v2/services/jobs/pagers.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Iterator, + Optional, + Sequence, + Tuple, +) + +from google.cloud.run_v2.types import job + + +class ListJobsPager: + """A pager for iterating through ``list_jobs`` requests. + + This class thinly wraps an initial + :class:`google.cloud.run_v2.types.ListJobsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``jobs`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListJobs`` requests and continue to iterate + through the ``jobs`` field on the + corresponding responses. + + All the usual :class:`google.cloud.run_v2.types.ListJobsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., job.ListJobsResponse], + request: job.ListJobsRequest, + response: job.ListJobsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.run_v2.types.ListJobsRequest): + The initial request object. + response (google.cloud.run_v2.types.ListJobsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = job.ListJobsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[job.ListJobsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[job.Job]: + for page in self.pages: + yield from page.jobs + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListJobsAsyncPager: + """A pager for iterating through ``list_jobs`` requests. + + This class thinly wraps an initial + :class:`google.cloud.run_v2.types.ListJobsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``jobs`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListJobs`` requests and continue to iterate + through the ``jobs`` field on the + corresponding responses. + + All the usual :class:`google.cloud.run_v2.types.ListJobsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[job.ListJobsResponse]], + request: job.ListJobsRequest, + response: job.ListJobsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.run_v2.types.ListJobsRequest): + The initial request object. + response (google.cloud.run_v2.types.ListJobsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = job.ListJobsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[job.ListJobsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[job.Job]: + async def async_generator(): + async for page in self.pages: + for response in page.jobs: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/run_v2/services/jobs/transports/__init__.py b/google/cloud/run_v2/services/jobs/transports/__init__.py new file mode 100644 index 0000000..25ea4a3 --- /dev/null +++ b/google/cloud/run_v2/services/jobs/transports/__init__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +from typing import Dict, Type + +from .base import JobsTransport +from .grpc import JobsGrpcTransport +from .grpc_asyncio import JobsGrpcAsyncIOTransport +from .rest import JobsRestInterceptor, JobsRestTransport + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[JobsTransport]] +_transport_registry["grpc"] = JobsGrpcTransport +_transport_registry["grpc_asyncio"] = JobsGrpcAsyncIOTransport +_transport_registry["rest"] = JobsRestTransport + +__all__ = ( + "JobsTransport", + "JobsGrpcTransport", + "JobsGrpcAsyncIOTransport", + "JobsRestTransport", + "JobsRestInterceptor", +) diff --git a/google/cloud/run_v2/services/jobs/transports/base.py b/google/cloud/run_v2/services/jobs/transports/base.py new file mode 100644 index 0000000..a8a90fa --- /dev/null +++ b/google/cloud/run_v2/services/jobs/transports/base.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union + +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1, operations_v1 +from google.api_core import retry as retries +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +class JobsTransport(abc.ABC): + """Abstract transport class for Jobs.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + DEFAULT_HOST: str = "run.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_job: gapic_v1.method.wrap_method( + self.create_job, + default_timeout=None, + client_info=client_info, + ), + self.get_job: gapic_v1.method.wrap_method( + self.get_job, + default_timeout=None, + client_info=client_info, + ), + self.list_jobs: gapic_v1.method.wrap_method( + self.list_jobs, + default_timeout=None, + client_info=client_info, + ), + self.update_job: gapic_v1.method.wrap_method( + self.update_job, + default_timeout=None, + client_info=client_info, + ), + self.delete_job: gapic_v1.method.wrap_method( + self.delete_job, + default_timeout=None, + client_info=client_info, + ), + self.run_job: gapic_v1.method.wrap_method( + self.run_job, + default_timeout=None, + client_info=client_info, + ), + self.get_iam_policy: gapic_v1.method.wrap_method( + self.get_iam_policy, + default_timeout=None, + client_info=client_info, + ), + self.set_iam_policy: gapic_v1.method.wrap_method( + self.set_iam_policy, + default_timeout=None, + client_info=client_info, + ), + self.test_iam_permissions: gapic_v1.method.wrap_method( + self.test_iam_permissions, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def operations_client(self): + """Return the client designed to process long-running operations.""" + raise NotImplementedError() + + @property + def create_job( + self, + ) -> Callable[ + [gcr_job.CreateJobRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def get_job( + self, + ) -> Callable[[job.GetJobRequest], Union[job.Job, Awaitable[job.Job]]]: + raise NotImplementedError() + + @property + def list_jobs( + self, + ) -> Callable[ + [job.ListJobsRequest], + Union[job.ListJobsResponse, Awaitable[job.ListJobsResponse]], + ]: + raise NotImplementedError() + + @property + def update_job( + self, + ) -> Callable[ + [gcr_job.UpdateJobRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_job( + self, + ) -> Callable[ + [job.DeleteJobRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def run_job( + self, + ) -> Callable[ + [job.RunJobRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def get_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.GetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def set_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.SetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Union[ + iam_policy_pb2.TestIamPermissionsResponse, + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], + Union[ + operations_pb2.ListOperationsResponse, + Awaitable[operations_pb2.ListOperationsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("JobsTransport",) diff --git a/google/cloud/run_v2/services/jobs/transports/grpc.py b/google/cloud/run_v2/services/jobs/transports/grpc.py new file mode 100644 index 0000000..aaaff2c --- /dev/null +++ b/google/cloud/run_v2/services/jobs/transports/grpc.py @@ -0,0 +1,547 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers, operations_v1 +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore +import grpc # type: ignore + +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job + +from .base import DEFAULT_CLIENT_INFO, JobsTransport + + +class JobsGrpcTransport(JobsTransport): + """gRPC backend transport for Jobs. + + Cloud Run Job Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[grpc.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client: Optional[operations_v1.OperationsClient] = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Quick check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsClient(self.grpc_channel) + + # Return the client from cache. + return self._operations_client + + @property + def create_job( + self, + ) -> Callable[[gcr_job.CreateJobRequest], operations_pb2.Operation]: + r"""Return a callable for the create job method over gRPC. + + Creates a Job. + + Returns: + Callable[[~.CreateJobRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_job" not in self._stubs: + self._stubs["create_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/CreateJob", + request_serializer=gcr_job.CreateJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["create_job"] + + @property + def get_job(self) -> Callable[[job.GetJobRequest], job.Job]: + r"""Return a callable for the get job method over gRPC. + + Gets information about a Job. + + Returns: + Callable[[~.GetJobRequest], + ~.Job]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_job" not in self._stubs: + self._stubs["get_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/GetJob", + request_serializer=job.GetJobRequest.serialize, + response_deserializer=job.Job.deserialize, + ) + return self._stubs["get_job"] + + @property + def list_jobs(self) -> Callable[[job.ListJobsRequest], job.ListJobsResponse]: + r"""Return a callable for the list jobs method over gRPC. + + Lists Jobs. + + Returns: + Callable[[~.ListJobsRequest], + ~.ListJobsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_jobs" not in self._stubs: + self._stubs["list_jobs"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/ListJobs", + request_serializer=job.ListJobsRequest.serialize, + response_deserializer=job.ListJobsResponse.deserialize, + ) + return self._stubs["list_jobs"] + + @property + def update_job( + self, + ) -> Callable[[gcr_job.UpdateJobRequest], operations_pb2.Operation]: + r"""Return a callable for the update job method over gRPC. + + Updates a Job. + + Returns: + Callable[[~.UpdateJobRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_job" not in self._stubs: + self._stubs["update_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/UpdateJob", + request_serializer=gcr_job.UpdateJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["update_job"] + + @property + def delete_job(self) -> Callable[[job.DeleteJobRequest], operations_pb2.Operation]: + r"""Return a callable for the delete job method over gRPC. + + Deletes a Job. + + Returns: + Callable[[~.DeleteJobRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_job" not in self._stubs: + self._stubs["delete_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/DeleteJob", + request_serializer=job.DeleteJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["delete_job"] + + @property + def run_job(self) -> Callable[[job.RunJobRequest], operations_pb2.Operation]: + r"""Return a callable for the run job method over gRPC. + + Triggers creation of a new Execution of this Job. + + Returns: + Callable[[~.RunJobRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_job" not in self._stubs: + self._stubs["run_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/RunJob", + request_serializer=job.RunJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["run_job"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the get iam policy method over gRPC. + + Gets the IAM Access Control policy currently in + effect for the given Job. This result does not include + any inherited policies. + + Returns: + Callable[[~.GetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the set iam policy method over gRPC. + + Sets the IAM Access control policy for the specified + Job. Overwrites any existing policy. + + Returns: + Callable[[~.SetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + iam_policy_pb2.TestIamPermissionsResponse, + ]: + r"""Return a callable for the test iam permissions method over gRPC. + + Returns permissions that a caller has on the + specified Project. + There are no permissions required for making this API + call. + + Returns: + Callable[[~.TestIamPermissionsRequest], + ~.TestIamPermissionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + self.grpc_channel.close() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("JobsGrpcTransport",) diff --git a/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py b/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py new file mode 100644 index 0000000..dfbeac2 --- /dev/null +++ b/google/cloud/run_v2/services/jobs/transports/grpc_asyncio.py @@ -0,0 +1,554 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers_async, operations_v1 +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job + +from .base import DEFAULT_CLIENT_INFO, JobsTransport +from .grpc import JobsGrpcTransport + + +class JobsGrpcAsyncIOTransport(JobsTransport): + """gRPC AsyncIO backend transport for Jobs. + + Cloud Run Job Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[aio.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client: Optional[operations_v1.OperationsAsyncClient] = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsAsyncClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Quick check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsAsyncClient( + self.grpc_channel + ) + + # Return the client from cache. + return self._operations_client + + @property + def create_job( + self, + ) -> Callable[[gcr_job.CreateJobRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the create job method over gRPC. + + Creates a Job. + + Returns: + Callable[[~.CreateJobRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_job" not in self._stubs: + self._stubs["create_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/CreateJob", + request_serializer=gcr_job.CreateJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["create_job"] + + @property + def get_job(self) -> Callable[[job.GetJobRequest], Awaitable[job.Job]]: + r"""Return a callable for the get job method over gRPC. + + Gets information about a Job. + + Returns: + Callable[[~.GetJobRequest], + Awaitable[~.Job]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_job" not in self._stubs: + self._stubs["get_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/GetJob", + request_serializer=job.GetJobRequest.serialize, + response_deserializer=job.Job.deserialize, + ) + return self._stubs["get_job"] + + @property + def list_jobs( + self, + ) -> Callable[[job.ListJobsRequest], Awaitable[job.ListJobsResponse]]: + r"""Return a callable for the list jobs method over gRPC. + + Lists Jobs. + + Returns: + Callable[[~.ListJobsRequest], + Awaitable[~.ListJobsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_jobs" not in self._stubs: + self._stubs["list_jobs"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/ListJobs", + request_serializer=job.ListJobsRequest.serialize, + response_deserializer=job.ListJobsResponse.deserialize, + ) + return self._stubs["list_jobs"] + + @property + def update_job( + self, + ) -> Callable[[gcr_job.UpdateJobRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the update job method over gRPC. + + Updates a Job. + + Returns: + Callable[[~.UpdateJobRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_job" not in self._stubs: + self._stubs["update_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/UpdateJob", + request_serializer=gcr_job.UpdateJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["update_job"] + + @property + def delete_job( + self, + ) -> Callable[[job.DeleteJobRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the delete job method over gRPC. + + Deletes a Job. + + Returns: + Callable[[~.DeleteJobRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_job" not in self._stubs: + self._stubs["delete_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/DeleteJob", + request_serializer=job.DeleteJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["delete_job"] + + @property + def run_job( + self, + ) -> Callable[[job.RunJobRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the run job method over gRPC. + + Triggers creation of a new Execution of this Job. + + Returns: + Callable[[~.RunJobRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_job" not in self._stubs: + self._stubs["run_job"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/RunJob", + request_serializer=job.RunJobRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["run_job"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the get iam policy method over gRPC. + + Gets the IAM Access Control policy currently in + effect for the given Job. This result does not include + any inherited policies. + + Returns: + Callable[[~.GetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the set iam policy method over gRPC. + + Sets the IAM Access control policy for the specified + Job. Overwrites any existing policy. + + Returns: + Callable[[~.SetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ]: + r"""Return a callable for the test iam permissions method over gRPC. + + Returns permissions that a caller has on the + specified Project. + There are no permissions required for making this API + call. + + Returns: + Callable[[~.TestIamPermissionsRequest], + Awaitable[~.TestIamPermissionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Jobs/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + return self.grpc_channel.close() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + + +__all__ = ("JobsGrpcAsyncIOTransport",) diff --git a/google/cloud/run_v2/services/jobs/transports/rest.py b/google/cloud/run_v2/services/jobs/transports/rest.py new file mode 100644 index 0000000..494ab09 --- /dev/null +++ b/google/cloud/run_v2/services/jobs/transports/rest.py @@ -0,0 +1,1818 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 dataclasses +import json # type: ignore +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore + +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import JobsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class JobsRestInterceptor: + """Interceptor for Jobs. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the JobsRestTransport. + + .. code-block:: python + class MyCustomJobsInterceptor(JobsRestInterceptor): + def pre_create_job(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_job(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_job(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_delete_job(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_iam_policy(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_iam_policy(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_job(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_job(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_jobs(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_jobs(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_run_job(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_run_job(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_set_iam_policy(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_set_iam_policy(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_test_iam_permissions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_test_iam_permissions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_job(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_job(self, response): + logging.log(f"Received response: {response}") + return response + + transport = JobsRestTransport(interceptor=MyCustomJobsInterceptor()) + client = JobsClient(transport=transport) + + + """ + + def pre_create_job( + self, request: gcr_job.CreateJobRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcr_job.CreateJobRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_job + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_create_job( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_job + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_delete_job( + self, request: job.DeleteJobRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[job.DeleteJobRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_job + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_delete_job( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for delete_job + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[iam_policy_pb2.GetIamPolicyRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_iam_policy + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_get_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: + """Post-rpc interceptor for get_iam_policy + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_get_job( + self, request: job.GetJobRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[job.GetJobRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_job + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_get_job(self, response: job.Job) -> job.Job: + """Post-rpc interceptor for get_job + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_list_jobs( + self, request: job.ListJobsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[job.ListJobsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_jobs + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_list_jobs(self, response: job.ListJobsResponse) -> job.ListJobsResponse: + """Post-rpc interceptor for list_jobs + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_run_job( + self, request: job.RunJobRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[job.RunJobRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for run_job + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_run_job( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for run_job + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[iam_policy_pb2.SetIamPolicyRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for set_iam_policy + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_set_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: + """Post-rpc interceptor for set_iam_policy + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[iam_policy_pb2.TestIamPermissionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for test_iam_permissions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_test_iam_permissions( + self, response: iam_policy_pb2.TestIamPermissionsResponse + ) -> iam_policy_pb2.TestIamPermissionsResponse: + """Post-rpc interceptor for test_iam_permissions + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_update_job( + self, request: gcr_job.UpdateJobRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcr_job.UpdateJobRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_job + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_update_job( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for update_job + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_delete_operation( + self, + request: operations_pb2.DeleteOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> None: + """Pre-rpc interceptor for delete_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_delete_operation( + self, response: operations_pb2.DeleteOperationRequest + ) -> None: + """Post-rpc interceptor for delete_operation + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.GetOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.ListOperationsResponse: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Jobs server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsRequest + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Jobs server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class JobsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: JobsRestInterceptor + + +class JobsRestTransport(JobsTransport): + """REST backend transport for Jobs. + + Cloud Run Job Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[JobsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or JobsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.DeleteOperation": [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateJob(JobsRestStub): + def __hash__(self): + return hash("CreateJob") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "jobId": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcr_job.CreateJobRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create job method over HTTP. + + Args: + request (~.gcr_job.CreateJobRequest): + The request object. Request message for creating a Job. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/jobs", + "body": "job", + }, + ] + request, metadata = self._interceptor.pre_create_job(request, metadata) + pb_request = gcr_job.CreateJobRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_job(resp) + return resp + + class _DeleteJob(JobsRestStub): + def __hash__(self): + return hash("DeleteJob") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: job.DeleteJobRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the delete job method over HTTP. + + Args: + request (~.job.DeleteJobRequest): + The request object. Request message to delete a Job by + its full name. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/jobs/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_job(request, metadata) + pb_request = job.DeleteJobRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_delete_job(resp) + return resp + + class _GetIamPolicy(JobsRestStub): + def __hash__(self): + return hash("GetIamPolicy") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: iam_policy_pb2.GetIamPolicyRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Call the get iam policy method over HTTP. + + Args: + request (~.iam_policy_pb2.GetIamPolicyRequest): + The request object. Request message for ``GetIamPolicy`` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.policy_pb2.Policy: + An Identity and Access Management (IAM) policy, which + specifies access controls for Google Cloud resources. + + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members``, or + principals, to a single ``role``. Principals can be user + accounts, service accounts, Google groups, and domains + (such as G Suite). A ``role`` is a named list of + permissions; each ``role`` can be an IAM predefined role + or a user-created custom role. + + For some types of Google Cloud resources, a ``binding`` + can also specify a ``condition``, which is a logical + expression that allows access to a resource only if the + expression evaluates to ``true``. A condition can add + constraints based on attributes of the request, the + resource, or both. To learn which resources support + conditions in their IAM policies, see the `IAM + documentation `__. + + **JSON example:** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": [ + "user:eve@example.com" + ], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < timestamp('2020-10-01T00:00:00.000Z')", + } + } + ], + "etag": "BwWWja0YfJA=", + "version": 3 + } + + **YAML example:** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + etag: BwWWja0YfJA= + version: 3 + + For a description of IAM and its features, see the `IAM + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{resource=projects/*/locations/*/jobs/*}:getIamPolicy", + }, + ] + request, metadata = self._interceptor.pre_get_iam_policy(request, metadata) + pb_request = request + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = policy_pb2.Policy() + pb_resp = resp + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_iam_policy(resp) + return resp + + class _GetJob(JobsRestStub): + def __hash__(self): + return hash("GetJob") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: job.GetJobRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> job.Job: + r"""Call the get job method over HTTP. + + Args: + request (~.job.GetJobRequest): + The request object. Request message for obtaining a Job + by its full name. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.job.Job: + Job represents the configuration of a + single job. A job an immutable resource + that references a container image which + is run to completion. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/jobs/*}", + }, + ] + request, metadata = self._interceptor.pre_get_job(request, metadata) + pb_request = job.GetJobRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = job.Job() + pb_resp = job.Job.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_job(resp) + return resp + + class _ListJobs(JobsRestStub): + def __hash__(self): + return hash("ListJobs") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: job.ListJobsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> job.ListJobsResponse: + r"""Call the list jobs method over HTTP. + + Args: + request (~.job.ListJobsRequest): + The request object. Request message for retrieving a list + of Jobs. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.job.ListJobsResponse: + Response message containing a list of + Jobs. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/jobs", + }, + ] + request, metadata = self._interceptor.pre_list_jobs(request, metadata) + pb_request = job.ListJobsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = job.ListJobsResponse() + pb_resp = job.ListJobsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_jobs(resp) + return resp + + class _RunJob(JobsRestStub): + def __hash__(self): + return hash("RunJob") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: job.RunJobRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the run job method over HTTP. + + Args: + request (~.job.RunJobRequest): + The request object. Request message to create a new + Execution of a Job. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/jobs/*}:run", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_run_job(request, metadata) + pb_request = job.RunJobRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_run_job(resp) + return resp + + class _SetIamPolicy(JobsRestStub): + def __hash__(self): + return hash("SetIamPolicy") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: iam_policy_pb2.SetIamPolicyRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Call the set iam policy method over HTTP. + + Args: + request (~.iam_policy_pb2.SetIamPolicyRequest): + The request object. Request message for ``SetIamPolicy`` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.policy_pb2.Policy: + An Identity and Access Management (IAM) policy, which + specifies access controls for Google Cloud resources. + + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members``, or + principals, to a single ``role``. Principals can be user + accounts, service accounts, Google groups, and domains + (such as G Suite). A ``role`` is a named list of + permissions; each ``role`` can be an IAM predefined role + or a user-created custom role. + + For some types of Google Cloud resources, a ``binding`` + can also specify a ``condition``, which is a logical + expression that allows access to a resource only if the + expression evaluates to ``true``. A condition can add + constraints based on attributes of the request, the + resource, or both. To learn which resources support + conditions in their IAM policies, see the `IAM + documentation `__. + + **JSON example:** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": [ + "user:eve@example.com" + ], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < timestamp('2020-10-01T00:00:00.000Z')", + } + } + ], + "etag": "BwWWja0YfJA=", + "version": 3 + } + + **YAML example:** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + etag: BwWWja0YfJA= + version: 3 + + For a description of IAM and its features, see the `IAM + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{resource=projects/*/locations/*/jobs/*}:setIamPolicy", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_set_iam_policy(request, metadata) + pb_request = request + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = policy_pb2.Policy() + pb_resp = resp + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_set_iam_policy(resp) + return resp + + class _TestIamPermissions(JobsRestStub): + def __hash__(self): + return hash("TestIamPermissions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: iam_policy_pb2.TestIamPermissionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Call the test iam permissions method over HTTP. + + Args: + request (~.iam_policy_pb2.TestIamPermissionsRequest): + The request object. Request message for ``TestIamPermissions`` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.iam_policy_pb2.TestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{resource=projects/*/locations/*/jobs/*}:testIamPermissions", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_test_iam_permissions( + request, metadata + ) + pb_request = request + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = iam_policy_pb2.TestIamPermissionsResponse() + pb_resp = resp + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_test_iam_permissions(resp) + return resp + + class _UpdateJob(JobsRestStub): + def __hash__(self): + return hash("UpdateJob") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcr_job.UpdateJobRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the update job method over HTTP. + + Args: + request (~.gcr_job.UpdateJobRequest): + The request object. Request message for updating a Job. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{job.name=projects/*/locations/*/jobs/*}", + "body": "job", + }, + ] + request, metadata = self._interceptor.pre_update_job(request, metadata) + pb_request = gcr_job.UpdateJobRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_job(resp) + return resp + + @property + def create_job( + self, + ) -> Callable[[gcr_job.CreateJobRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateJob(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_job(self) -> Callable[[job.DeleteJobRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteJob(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], policy_pb2.Policy]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetIamPolicy(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_job(self) -> Callable[[job.GetJobRequest], job.Job]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetJob(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_jobs(self) -> Callable[[job.ListJobsRequest], job.ListJobsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListJobs(self._session, self._host, self._interceptor) # type: ignore + + @property + def run_job(self) -> Callable[[job.RunJobRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._RunJob(self._session, self._host, self._interceptor) # type: ignore + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], policy_pb2.Policy]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SetIamPolicy(self._session, self._host, self._interceptor) # type: ignore + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + iam_policy_pb2.TestIamPermissionsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._TestIamPermissions(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_job( + self, + ) -> Callable[[gcr_job.UpdateJobRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateJob(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_operation(self): + return self._DeleteOperation(self._session, self._host, self._interceptor) # type: ignore + + class _DeleteOperation(JobsRestStub): + def __call__( + self, + request: operations_pb2.DeleteOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the delete operation method over HTTP. + + Args: + request (operations_pb2.DeleteOperationRequest): + The request object for DeleteOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_delete_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_delete_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(JobsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(JobsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("JobsRestTransport",) diff --git a/google/cloud/run_v2/services/revisions/__init__.py b/google/cloud/run_v2/services/revisions/__init__.py index fc04385..e26e089 100644 --- a/google/cloud/run_v2/services/revisions/__init__.py +++ b/google/cloud/run_v2/services/revisions/__init__.py @@ -13,8 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from .client import RevisionsClient from .async_client import RevisionsAsyncClient +from .client import RevisionsClient __all__ = ( "RevisionsClient", diff --git a/google/cloud/run_v2/services/revisions/async_client.py b/google/cloud/run_v2/services/revisions/async_client.py index b00d9a3..b5a33f1 100644 --- a/google/cloud/run_v2/services/revisions/async_client.py +++ b/google/cloud/run_v2/services/revisions/async_client.py @@ -16,16 +16,27 @@ from collections import OrderedDict import functools import re -from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union -import pkg_resources +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, +) -from google.api_core.client_options import ClientOptions from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore +from google.cloud.run_v2 import gapic_version as package_version + try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] except AttributeError: # pragma: NO COVER @@ -34,16 +45,17 @@ from google.api import launch_stage_pb2 # type: ignore from google.api_core import operation # type: ignore from google.api_core import operation_async # type: ignore -from google.cloud.run_v2.services.revisions import pagers -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import k8s_min -from google.cloud.run_v2.types import revision -from google.cloud.run_v2.types import vendor_settings +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import duration_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore -from .transports.base import RevisionsTransport, DEFAULT_CLIENT_INFO -from .transports.grpc_asyncio import RevisionsGrpcAsyncIOTransport + +from google.cloud.run_v2.services.revisions import pagers +from google.cloud.run_v2.types import condition, k8s_min, revision, vendor_settings + from .client import RevisionsClient +from .transports.base import DEFAULT_CLIENT_INFO, RevisionsTransport +from .transports.grpc_asyncio import RevisionsGrpcAsyncIOTransport class RevisionsAsyncClient: @@ -170,9 +182,9 @@ def transport(self) -> RevisionsTransport: def __init__( self, *, - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, transport: Union[str, RevisionsTransport] = "grpc_asyncio", - client_options: ClientOptions = None, + client_options: Optional[ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiates the revisions client. @@ -216,11 +228,11 @@ def __init__( async def get_revision( self, - request: Union[revision.GetRevisionRequest, dict] = None, + request: Optional[Union[revision.GetRevisionRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> revision.Revision: r"""Gets information about a Revision. @@ -252,7 +264,7 @@ async def sample_get_revision(): print(response) Args: - request (Union[google.cloud.run_v2.types.GetRevisionRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.GetRevisionRequest, dict]]): The request object. Request message for obtaining a Revision by its full name. name (:class:`str`): @@ -322,14 +334,14 @@ async def sample_get_revision(): async def list_revisions( self, - request: Union[revision.ListRevisionsRequest, dict] = None, + request: Optional[Union[revision.ListRevisionsRequest, dict]] = None, *, - parent: str = None, + parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> pagers.ListRevisionsAsyncPager: - r"""List Revisions from a given Service, or from a given + r"""Lists Revisions from a given Service, or from a given location. .. code-block:: python @@ -360,7 +372,7 @@ async def sample_list_revisions(): print(response) Args: - request (Union[google.cloud.run_v2.types.ListRevisionsRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.ListRevisionsRequest, dict]]): The request object. Request message for retrieving a list of Revisions. parent (:class:`str`): @@ -441,14 +453,14 @@ async def sample_list_revisions(): async def delete_revision( self, - request: Union[revision.DeleteRevisionRequest, dict] = None, + request: Optional[Union[revision.DeleteRevisionRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation_async.AsyncOperation: - r"""Delete a Revision. + r"""Deletes a Revision. .. code-block:: python @@ -475,13 +487,13 @@ async def sample_delete_revision(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) Args: - request (Union[google.cloud.run_v2.types.DeleteRevisionRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.DeleteRevisionRequest, dict]]): The request object. Request message for deleting a retired Revision. Revision lifecycle is usually managed by making changes to the parent Service. Only retired @@ -559,6 +571,169 @@ async def sample_delete_revision(): # Done; return the response. return response + async def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + async def __aenter__(self): return self @@ -566,14 +741,9 @@ async def __aexit__(self, exc_type, exc, tb): await self.transport.close() -try: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution( - "google-cloud-run", - ).version, - ) -except pkg_resources.DistributionNotFound: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) __all__ = ("RevisionsAsyncClient",) diff --git a/google/cloud/run_v2/services/revisions/client.py b/google/cloud/run_v2/services/revisions/client.py index 2ed4c32..1047fab 100644 --- a/google/cloud/run_v2/services/revisions/client.py +++ b/google/cloud/run_v2/services/revisions/client.py @@ -16,19 +16,31 @@ from collections import OrderedDict import os import re -from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union -import pkg_resources +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.auth.transport import mtls # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore -from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore +from google.cloud.run_v2 import gapic_version as package_version + try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] except AttributeError: # pragma: NO COVER @@ -37,14 +49,15 @@ from google.api import launch_stage_pb2 # type: ignore from google.api_core import operation # type: ignore from google.api_core import operation_async # type: ignore -from google.cloud.run_v2.services.revisions import pagers -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import k8s_min -from google.cloud.run_v2.types import revision -from google.cloud.run_v2.types import vendor_settings +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import duration_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore -from .transports.base import RevisionsTransport, DEFAULT_CLIENT_INFO + +from google.cloud.run_v2.services.revisions import pagers +from google.cloud.run_v2.types import condition, k8s_min, revision, vendor_settings + +from .transports.base import DEFAULT_CLIENT_INFO, RevisionsTransport from .transports.grpc import RevisionsGrpcTransport from .transports.grpc_asyncio import RevisionsGrpcAsyncIOTransport from .transports.rest import RevisionsRestTransport @@ -65,7 +78,7 @@ class RevisionsClientMeta(type): def get_transport_class( cls, - label: str = None, + label: Optional[str] = None, ) -> Type[RevisionsTransport]: """Returns an appropriate transport class. @@ -449,8 +462,8 @@ def __init__( self, *, credentials: Optional[ga_credentials.Credentials] = None, - transport: Union[str, RevisionsTransport, None] = None, - client_options: Optional[client_options_lib.ClientOptions] = None, + transport: Optional[Union[str, RevisionsTransport]] = None, + client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiates the revisions client. @@ -464,10 +477,7 @@ def __init__( transport (Union[str, RevisionsTransport]): The transport to use. If set to None, a transport is chosen automatically. - NOTE: "rest" transport functionality is currently in a - beta state (preview). We welcome your feedback via an - issue in this library's source repository. - client_options (google.api_core.client_options.ClientOptions): Custom options for the + client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT @@ -497,6 +507,7 @@ def __init__( client_options = client_options_lib.from_dict(client_options) if client_options is None: client_options = client_options_lib.ClientOptions() + client_options = cast(client_options_lib.ClientOptions, client_options) api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( client_options @@ -549,11 +560,11 @@ def __init__( def get_revision( self, - request: Union[revision.GetRevisionRequest, dict] = None, + request: Optional[Union[revision.GetRevisionRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> revision.Revision: r"""Gets information about a Revision. @@ -663,14 +674,14 @@ def sample_get_revision(): def list_revisions( self, - request: Union[revision.ListRevisionsRequest, dict] = None, + request: Optional[Union[revision.ListRevisionsRequest, dict]] = None, *, - parent: str = None, + parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> pagers.ListRevisionsPager: - r"""List Revisions from a given Service, or from a given + r"""Lists Revisions from a given Service, or from a given location. .. code-block:: python @@ -790,14 +801,14 @@ def sample_list_revisions(): def delete_revision( self, - request: Union[revision.DeleteRevisionRequest, dict] = None, + request: Optional[Union[revision.DeleteRevisionRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation.Operation: - r"""Delete a Revision. + r"""Deletes a Revision. .. code-block:: python @@ -929,15 +940,173 @@ def __exit__(self, type, value, traceback): """ self.transport.close() + def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. -try: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution( - "google-cloud-run", - ).version, - ) -except pkg_resources.DistributionNotFound: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) __all__ = ("RevisionsClient",) diff --git a/google/cloud/run_v2/services/revisions/pagers.py b/google/cloud/run_v2/services/revisions/pagers.py index 4234c9c..ee449d8 100644 --- a/google/cloud/run_v2/services/revisions/pagers.py +++ b/google/cloud/run_v2/services/revisions/pagers.py @@ -18,10 +18,10 @@ AsyncIterator, Awaitable, Callable, + Iterator, + Optional, Sequence, Tuple, - Optional, - Iterator, ) from google.cloud.run_v2.types import revision diff --git a/google/cloud/run_v2/services/revisions/transports/__init__.py b/google/cloud/run_v2/services/revisions/transports/__init__.py index a67304d..5501b10 100644 --- a/google/cloud/run_v2/services/revisions/transports/__init__.py +++ b/google/cloud/run_v2/services/revisions/transports/__init__.py @@ -19,9 +19,7 @@ from .base import RevisionsTransport from .grpc import RevisionsGrpcTransport from .grpc_asyncio import RevisionsGrpcAsyncIOTransport -from .rest import RevisionsRestTransport -from .rest import RevisionsRestInterceptor - +from .rest import RevisionsRestInterceptor, RevisionsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[RevisionsTransport]] diff --git a/google/cloud/run_v2/services/revisions/transports/base.py b/google/cloud/run_v2/services/revisions/transports/base.py index 6ee1fcb..c1deb55 100644 --- a/google/cloud/run_v2/services/revisions/transports/base.py +++ b/google/cloud/run_v2/services/revisions/transports/base.py @@ -15,28 +15,23 @@ # import abc from typing import Awaitable, Callable, Dict, Optional, Sequence, Union -import pkg_resources -import google.auth # type: ignore import google.api_core from google.api_core import exceptions as core_exceptions -from google.api_core import gapic_v1 +from google.api_core import gapic_v1, operations_v1 from google.api_core import retry as retries -from google.api_core import operations_v1 +import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore from google.oauth2 import service_account # type: ignore +from google.cloud.run_v2 import gapic_version as package_version from google.cloud.run_v2.types import revision -from google.longrunning import operations_pb2 # type: ignore -try: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution( - "google-cloud-run", - ).version, - ) -except pkg_resources.DistributionNotFound: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) class RevisionsTransport(abc.ABC): @@ -50,7 +45,7 @@ def __init__( self, *, host: str = DEFAULT_HOST, - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -189,6 +184,33 @@ def delete_revision( ]: raise NotImplementedError() + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], + Union[ + operations_pb2.ListOperationsResponse, + Awaitable[operations_pb2.ListOperationsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/revisions/transports/grpc.py b/google/cloud/run_v2/services/revisions/transports/grpc.py index ee2217c..50d4179 100644 --- a/google/cloud/run_v2/services/revisions/transports/grpc.py +++ b/google/cloud/run_v2/services/revisions/transports/grpc.py @@ -13,21 +13,20 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import warnings from typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings -from google.api_core import grpc_helpers -from google.api_core import operations_v1 -from google.api_core import gapic_v1 +from google.api_core import gapic_v1, grpc_helpers, operations_v1 import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore import grpc # type: ignore from google.cloud.run_v2.types import revision -from google.longrunning import operations_pb2 # type: ignore -from .base import RevisionsTransport, DEFAULT_CLIENT_INFO + +from .base import DEFAULT_CLIENT_INFO, RevisionsTransport class RevisionsGrpcTransport(RevisionsTransport): @@ -49,14 +48,14 @@ def __init__( self, *, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, - credentials_file: str = None, - scopes: Sequence[str] = None, - channel: grpc.Channel = None, - api_mtls_endpoint: str = None, - client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, - ssl_channel_credentials: grpc.ChannelCredentials = None, - client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[grpc.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, @@ -184,8 +183,8 @@ def __init__( def create_channel( cls, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, - credentials_file: str = None, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, **kwargs, @@ -278,7 +277,7 @@ def list_revisions( ) -> Callable[[revision.ListRevisionsRequest], revision.ListRevisionsResponse]: r"""Return a callable for the list revisions method over gRPC. - List Revisions from a given Service, or from a given + Lists Revisions from a given Service, or from a given location. Returns: @@ -305,7 +304,7 @@ def delete_revision( ) -> Callable[[revision.DeleteRevisionRequest], operations_pb2.Operation]: r"""Return a callable for the delete revision method over gRPC. - Delete a Revision. + Deletes a Revision. Returns: Callable[[~.DeleteRevisionRequest], @@ -328,6 +327,59 @@ def delete_revision( def close(self): self.grpc_channel.close() + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + @property def kind(self) -> str: return "grpc" diff --git a/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py b/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py index cafd158..55ee1fd 100644 --- a/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/revisions/transports/grpc_asyncio.py @@ -13,21 +13,20 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings -from google.api_core import gapic_v1 -from google.api_core import grpc_helpers_async -from google.api_core import operations_v1 +from google.api_core import gapic_v1, grpc_helpers_async, operations_v1 from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore import grpc # type: ignore from grpc.experimental import aio # type: ignore from google.cloud.run_v2.types import revision -from google.longrunning import operations_pb2 # type: ignore -from .base import RevisionsTransport, DEFAULT_CLIENT_INFO + +from .base import DEFAULT_CLIENT_INFO, RevisionsTransport from .grpc import RevisionsGrpcTransport @@ -51,7 +50,7 @@ class RevisionsGrpcAsyncIOTransport(RevisionsTransport): def create_channel( cls, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -94,15 +93,15 @@ def __init__( self, *, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, - channel: aio.Channel = None, - api_mtls_endpoint: str = None, - client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, - ssl_channel_credentials: grpc.ChannelCredentials = None, - client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, - quota_project_id=None, + channel: Optional[aio.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, api_audience: Optional[str] = None, @@ -285,7 +284,7 @@ def list_revisions( ]: r"""Return a callable for the list revisions method over gRPC. - List Revisions from a given Service, or from a given + Lists Revisions from a given Service, or from a given location. Returns: @@ -314,7 +313,7 @@ def delete_revision( ]: r"""Return a callable for the delete revision method over gRPC. - Delete a Revision. + Deletes a Revision. Returns: Callable[[~.DeleteRevisionRequest], @@ -337,5 +336,58 @@ def delete_revision( def close(self): return self.grpc_channel.close() + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + __all__ = ("RevisionsGrpcAsyncIOTransport",) diff --git a/google/cloud/run_v2/services/revisions/transports/rest.py b/google/cloud/run_v2/services/revisions/transports/rest.py index 6472f72..9978220 100644 --- a/google/cloud/run_v2/services/revisions/transports/rest.py +++ b/google/cloud/run_v2/services/revisions/transports/rest.py @@ -14,25 +14,29 @@ # limitations under the License. # -from google.auth.transport.requests import AuthorizedSession # type: ignore +import dataclasses import json # type: ignore -import grpc # type: ignore -from google.auth.transport.grpc import SslCredentials # type: ignore -from google.auth import credentials as ga_credentials # type: ignore +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) from google.api_core import exceptions as core_exceptions from google.api_core import retry as retries -from google.api_core import rest_helpers -from google.api_core import rest_streaming -from google.api_core import path_template -from google.api_core import gapic_v1 - +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import json_format -from google.api_core import operations_v1 +import grpc # type: ignore from requests import __version__ as requests_version -import dataclasses -import re -from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union -import warnings try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] @@ -40,11 +44,12 @@ OptionalRetry = Union[retries.Retry, object] # type: ignore -from google.cloud.run_v2.types import revision from google.longrunning import operations_pb2 # type: ignore -from .base import RevisionsTransport, DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from google.cloud.run_v2.types import revision +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import RevisionsTransport DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, @@ -68,26 +73,29 @@ class RevisionsRestInterceptor: .. code-block:: python class MyCustomRevisionsInterceptor(RevisionsRestInterceptor): - def pre_delete_revision(request, metadata): + def pre_delete_revision(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_delete_revision(response): + def post_delete_revision(self, response): logging.log(f"Received response: {response}") + return response - def pre_get_revision(request, metadata): + def pre_get_revision(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_get_revision(response): + def post_get_revision(self, response): logging.log(f"Received response: {response}") + return response - def pre_list_revisions(request, metadata): + def pre_list_revisions(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_list_revisions(response): + def post_list_revisions(self, response): logging.log(f"Received response: {response}") + return response transport = RevisionsRestTransport(interceptor=MyCustomRevisionsInterceptor()) client = RevisionsClient(transport=transport) @@ -160,6 +168,75 @@ def post_list_revisions( """ return response + def pre_delete_operation( + self, + request: operations_pb2.DeleteOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> None: + """Pre-rpc interceptor for delete_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Revisions server. + """ + return request, metadata + + def post_delete_operation( + self, response: operations_pb2.DeleteOperationRequest + ) -> None: + """Post-rpc interceptor for delete_operation + + Override in a subclass to manipulate the response + after it is returned by the Revisions server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Revisions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.GetOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Revisions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.ListOperationsResponse: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Revisions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsRequest + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Revisions server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class RevisionsRestStub: @@ -179,19 +256,16 @@ class RevisionsRestTransport(RevisionsTransport): It sends JSON representations of protocol buffers over HTTP/1.1 - NOTE: This REST transport functionality is currently in a beta - state (preview). We welcome your feedback via an issue in this - library's source repository. Thank you! """ def __init__( self, *, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, - credentials_file: str = None, - scopes: Sequence[str] = None, - client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, @@ -201,39 +275,35 @@ def __init__( ) -> None: """Instantiate the transport. - NOTE: This REST transport functionality is currently in a beta - state (preview). We welcome your feedback via a GitHub issue in - this library's repository. Thank you! - - Args: - host (Optional[str]): - The hostname to connect to. - credentials (Optional[google.auth.credentials.Credentials]): The - authorization credentials to attach to requests. These - credentials identify the application to the service; if none - are specified, the client will attempt to ascertain the - credentials from the environment. - - credentials_file (Optional[str]): A file with credentials that can - be loaded with :func:`google.auth.load_credentials_from_file`. - This argument is ignored if ``channel`` is provided. - scopes (Optional(Sequence[str])): A list of scopes. This argument is - ignored if ``channel`` is provided. - client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client - certificate to configure mutual TLS HTTP channel. It is ignored - if ``channel`` is provided. - quota_project_id (Optional[str]): An optional project to use for billing - and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you are developing - your own client library. - always_use_jwt_access (Optional[bool]): Whether self signed JWT should - be used for service account credentials. - url_scheme: the protocol scheme for the API endpoint. Normally - "https", but for testing or local servers, - "http" can be specified. + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. """ # Run the base constructor # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. @@ -301,6 +371,7 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: credentials=self._credentials, scopes=self._scopes, http_options=http_options, + path_prefix="v2", ) self._operations_client = operations_v1.AbstractOperationsClient( @@ -329,7 +400,7 @@ def __call__( request: revision.DeleteRevisionRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> operations_pb2.Operation: r"""Call the delete revision method over HTTP. @@ -374,11 +445,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -419,7 +492,7 @@ def __call__( request: revision.GetRevisionRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> revision.Revision: r"""Call the get revision method over HTTP. @@ -463,11 +536,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -510,7 +585,7 @@ def __call__( request: revision.ListRevisionsRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> revision.ListRevisionsResponse: r"""Call the list revisions method over HTTP. @@ -551,11 +626,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -603,6 +680,203 @@ def list_revisions( # In C++ this would require a dynamic_cast return self._ListRevisions(self._session, self._host, self._interceptor) # type: ignore + @property + def delete_operation(self): + return self._DeleteOperation(self._session, self._host, self._interceptor) # type: ignore + + class _DeleteOperation(RevisionsRestStub): + def __call__( + self, + request: operations_pb2.DeleteOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the delete operation method over HTTP. + + Args: + request (operations_pb2.DeleteOperationRequest): + The request object for DeleteOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_delete_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_delete_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(RevisionsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(RevisionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/services/services/__init__.py b/google/cloud/run_v2/services/services/__init__.py index f8e9062..3916f58 100644 --- a/google/cloud/run_v2/services/services/__init__.py +++ b/google/cloud/run_v2/services/services/__init__.py @@ -13,8 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from .client import ServicesClient from .async_client import ServicesAsyncClient +from .client import ServicesClient __all__ = ( "ServicesClient", diff --git a/google/cloud/run_v2/services/services/async_client.py b/google/cloud/run_v2/services/services/async_client.py index d79f716..31c75f7 100644 --- a/google/cloud/run_v2/services/services/async_client.py +++ b/google/cloud/run_v2/services/services/async_client.py @@ -16,16 +16,27 @@ from collections import OrderedDict import functools import re -from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union -import pkg_resources +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, +) -from google.api_core.client_options import ClientOptions from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore +from google.cloud.run_v2 import gapic_version as package_version + try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] except AttributeError: # pragma: NO COVER @@ -34,19 +45,21 @@ from google.api import launch_stage_pb2 # type: ignore from google.api_core import operation # type: ignore from google.api_core import operation_async # type: ignore -from google.cloud.run_v2.services.services import pagers -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import revision_template -from google.cloud.run_v2.types import service -from google.cloud.run_v2.types import service as gcr_service -from google.cloud.run_v2.types import traffic_target -from google.cloud.run_v2.types import vendor_settings +from google.cloud.location import locations_pb2 # type: ignore from google.iam.v1 import iam_policy_pb2 # type: ignore from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import timestamp_pb2 # type: ignore -from .transports.base import ServicesTransport, DEFAULT_CLIENT_INFO -from .transports.grpc_asyncio import ServicesGrpcAsyncIOTransport + +from google.cloud.run_v2.services.services import pagers +from google.cloud.run_v2.types import condition, revision_template +from google.cloud.run_v2.types import service +from google.cloud.run_v2.types import service as gcr_service +from google.cloud.run_v2.types import traffic_target, vendor_settings + from .client import ServicesClient +from .transports.base import DEFAULT_CLIENT_INFO, ServicesTransport +from .transports.grpc_asyncio import ServicesGrpcAsyncIOTransport class ServicesAsyncClient: @@ -171,9 +184,9 @@ def transport(self) -> ServicesTransport: def __init__( self, *, - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, transport: Union[str, ServicesTransport] = "grpc_asyncio", - client_options: ClientOptions = None, + client_options: Optional[ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiates the services client. @@ -217,13 +230,13 @@ def __init__( async def create_service( self, - request: Union[gcr_service.CreateServiceRequest, dict] = None, + request: Optional[Union[gcr_service.CreateServiceRequest, dict]] = None, *, - parent: str = None, - service: gcr_service.Service = None, - service_id: str = None, + parent: Optional[str] = None, + service: Optional[gcr_service.Service] = None, + service_id: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation_async.AsyncOperation: r"""Creates a new Service in a given project and @@ -255,20 +268,23 @@ async def sample_create_service(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) Args: - request (Union[google.cloud.run_v2.types.CreateServiceRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.CreateServiceRequest, dict]]): The request object. Request message for creating a Service. parent (:class:`str`): Required. The location and project in which this service should be created. Format: - projects/{projectnumber}/locations/{location} + projects/{project}/locations/{location}, + where {project} can be project id or + number. Only lowercase characters, + digits, and hyphens. This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this @@ -281,9 +297,10 @@ async def sample_create_service(): on the ``request`` instance; if ``request`` is provided, this should not be set. service_id (:class:`str`): - Required. The unique identifier for the Service. The - name of the service becomes - {parent}/services/{service_id}. + Required. The unique identifier for the Service. It must + begin with letter, and cannot end with hyphen; must + contain fewer than 50 characters. The name of the + service becomes {parent}/services/{service_id}. This corresponds to the ``service_id`` field on the ``request`` instance; if ``request`` is provided, this @@ -363,11 +380,11 @@ async def sample_create_service(): async def get_service( self, - request: Union[service.GetServiceRequest, dict] = None, + request: Optional[Union[service.GetServiceRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> service.Service: r"""Gets information about a Service. @@ -399,13 +416,15 @@ async def sample_get_service(): print(response) Args: - request (Union[google.cloud.run_v2.types.GetServiceRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.GetServiceRequest, dict]]): The request object. Request message for obtaining a Service by its full name. name (:class:`str`): Required. The full name of the Service. Format: - projects/{projectnumber}/locations/{location}/services/{service} + projects/{project}/locations/{location}/services/{service}, + where {project} can be project id or + number. This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this @@ -482,14 +501,14 @@ async def sample_get_service(): async def list_services( self, - request: Union[service.ListServicesRequest, dict] = None, + request: Optional[Union[service.ListServicesRequest, dict]] = None, *, - parent: str = None, + parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> pagers.ListServicesAsyncPager: - r"""List Services. + r"""Lists Services. .. code-block:: python @@ -519,15 +538,17 @@ async def sample_list_services(): print(response) Args: - request (Union[google.cloud.run_v2.types.ListServicesRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.ListServicesRequest, dict]]): The request object. Request message for retrieving a list of Services. parent (:class:`str`): Required. The location and project to list resources on. Location must be a - valid GCP region, and may not be the "-" + valid GCP region, and cannot be the "-" wildcard. Format: - projects/{projectnumber}/locations/{location} + projects/{project}/locations/{location}, + where {project} can be project id or + number. This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this @@ -609,11 +630,11 @@ async def sample_list_services(): async def update_service( self, - request: Union[gcr_service.UpdateServiceRequest, dict] = None, + request: Optional[Union[gcr_service.UpdateServiceRequest, dict]] = None, *, - service: gcr_service.Service = None, + service: Optional[gcr_service.Service] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation_async.AsyncOperation: r"""Updates a Service. @@ -642,13 +663,13 @@ async def sample_update_service(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) Args: - request (Union[google.cloud.run_v2.types.UpdateServiceRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.UpdateServiceRequest, dict]]): The request object. Request message for updating a service. service (:class:`google.cloud.run_v2.types.Service`): @@ -729,11 +750,11 @@ async def sample_update_service(): async def delete_service( self, - request: Union[service.DeleteServiceRequest, dict] = None, + request: Optional[Union[service.DeleteServiceRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation_async.AsyncOperation: r"""Deletes a Service. @@ -765,19 +786,21 @@ async def sample_delete_service(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) Args: - request (Union[google.cloud.run_v2.types.DeleteServiceRequest, dict]): + request (Optional[Union[google.cloud.run_v2.types.DeleteServiceRequest, dict]]): The request object. Request message to delete a Service by its full name. name (:class:`str`): Required. The full name of the Service. Format: - projects/{projectnumber}/locations/{location}/services/{service} + projects/{project}/locations/{location}/services/{service}, + where {project} can be project id or + number. This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this @@ -853,15 +876,15 @@ async def sample_delete_service(): async def get_iam_policy( self, - request: Union[iam_policy_pb2.GetIamPolicyRequest, dict] = None, + request: Optional[Union[iam_policy_pb2.GetIamPolicyRequest, dict]] = None, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> policy_pb2.Policy: - r"""Get the IAM Access Control policy currently in effect - for the given Cloud Run Service. This result does not - include any inherited policies. + r"""Gets the IAM Access Control policy currently in + effect for the given Cloud Run Service. This result does + not include any inherited policies. .. code-block:: python @@ -891,7 +914,7 @@ async def sample_get_iam_policy(): print(response) Args: - request (Union[google.iam.v1.iam_policy_pb2.GetIamPolicyRequest, dict]): + request (Optional[Union[google.iam.v1.iam_policy_pb2.GetIamPolicyRequest, dict]]): The request object. Request message for `GetIamPolicy` method. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -998,10 +1021,10 @@ async def sample_get_iam_policy(): async def set_iam_policy( self, - request: Union[iam_policy_pb2.SetIamPolicyRequest, dict] = None, + request: Optional[Union[iam_policy_pb2.SetIamPolicyRequest, dict]] = None, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> policy_pb2.Policy: r"""Sets the IAM Access control policy for the specified @@ -1035,7 +1058,7 @@ async def sample_set_iam_policy(): print(response) Args: - request (Union[google.iam.v1.iam_policy_pb2.SetIamPolicyRequest, dict]): + request (Optional[Union[google.iam.v1.iam_policy_pb2.SetIamPolicyRequest, dict]]): The request object. Request message for `SetIamPolicy` method. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -1142,10 +1165,10 @@ async def sample_set_iam_policy(): async def test_iam_permissions( self, - request: Union[iam_policy_pb2.TestIamPermissionsRequest, dict] = None, + request: Optional[Union[iam_policy_pb2.TestIamPermissionsRequest, dict]] = None, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> iam_policy_pb2.TestIamPermissionsResponse: r"""Returns permissions that a caller has on the @@ -1182,7 +1205,7 @@ async def sample_test_iam_permissions(): print(response) Args: - request (Union[google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest, dict]): + request (Optional[Union[google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest, dict]]): The request object. Request message for `TestIamPermissions` method. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -1226,6 +1249,169 @@ async def sample_test_iam_permissions(): # Done; return the response. return response + async def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + async def __aenter__(self): return self @@ -1233,14 +1419,9 @@ async def __aexit__(self, exc_type, exc, tb): await self.transport.close() -try: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution( - "google-cloud-run", - ).version, - ) -except pkg_resources.DistributionNotFound: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) __all__ = ("ServicesAsyncClient",) diff --git a/google/cloud/run_v2/services/services/client.py b/google/cloud/run_v2/services/services/client.py index 0ad702c..1a23a43 100644 --- a/google/cloud/run_v2/services/services/client.py +++ b/google/cloud/run_v2/services/services/client.py @@ -16,19 +16,31 @@ from collections import OrderedDict import os import re -from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union -import pkg_resources +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) from google.api_core import client_options as client_options_lib from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.auth.transport import mtls # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore -from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore +from google.cloud.run_v2 import gapic_version as package_version + try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] except AttributeError: # pragma: NO COVER @@ -37,17 +49,19 @@ from google.api import launch_stage_pb2 # type: ignore from google.api_core import operation # type: ignore from google.api_core import operation_async # type: ignore -from google.cloud.run_v2.services.services import pagers -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import revision_template -from google.cloud.run_v2.types import service -from google.cloud.run_v2.types import service as gcr_service -from google.cloud.run_v2.types import traffic_target -from google.cloud.run_v2.types import vendor_settings +from google.cloud.location import locations_pb2 # type: ignore from google.iam.v1 import iam_policy_pb2 # type: ignore from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import timestamp_pb2 # type: ignore -from .transports.base import ServicesTransport, DEFAULT_CLIENT_INFO + +from google.cloud.run_v2.services.services import pagers +from google.cloud.run_v2.types import condition, revision_template +from google.cloud.run_v2.types import service +from google.cloud.run_v2.types import service as gcr_service +from google.cloud.run_v2.types import traffic_target, vendor_settings + +from .transports.base import DEFAULT_CLIENT_INFO, ServicesTransport from .transports.grpc import ServicesGrpcTransport from .transports.grpc_asyncio import ServicesGrpcAsyncIOTransport from .transports.rest import ServicesRestTransport @@ -68,7 +82,7 @@ class ServicesClientMeta(type): def get_transport_class( cls, - label: str = None, + label: Optional[str] = None, ) -> Type[ServicesTransport]: """Returns an appropriate transport class. @@ -452,8 +466,8 @@ def __init__( self, *, credentials: Optional[ga_credentials.Credentials] = None, - transport: Union[str, ServicesTransport, None] = None, - client_options: Optional[client_options_lib.ClientOptions] = None, + transport: Optional[Union[str, ServicesTransport]] = None, + client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiates the services client. @@ -467,10 +481,7 @@ def __init__( transport (Union[str, ServicesTransport]): The transport to use. If set to None, a transport is chosen automatically. - NOTE: "rest" transport functionality is currently in a - beta state (preview). We welcome your feedback via an - issue in this library's source repository. - client_options (google.api_core.client_options.ClientOptions): Custom options for the + client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT @@ -500,6 +511,7 @@ def __init__( client_options = client_options_lib.from_dict(client_options) if client_options is None: client_options = client_options_lib.ClientOptions() + client_options = cast(client_options_lib.ClientOptions, client_options) api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( client_options @@ -552,13 +564,13 @@ def __init__( def create_service( self, - request: Union[gcr_service.CreateServiceRequest, dict] = None, + request: Optional[Union[gcr_service.CreateServiceRequest, dict]] = None, *, - parent: str = None, - service: gcr_service.Service = None, - service_id: str = None, + parent: Optional[str] = None, + service: Optional[gcr_service.Service] = None, + service_id: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation.Operation: r"""Creates a new Service in a given project and @@ -603,7 +615,10 @@ def sample_create_service(): Required. The location and project in which this service should be created. Format: - projects/{projectnumber}/locations/{location} + projects/{project}/locations/{location}, + where {project} can be project id or + number. Only lowercase characters, + digits, and hyphens. This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this @@ -616,9 +631,10 @@ def sample_create_service(): on the ``request`` instance; if ``request`` is provided, this should not be set. service_id (str): - Required. The unique identifier for the Service. The - name of the service becomes - {parent}/services/{service_id}. + Required. The unique identifier for the Service. It must + begin with letter, and cannot end with hyphen; must + contain fewer than 50 characters. The name of the + service becomes {parent}/services/{service_id}. This corresponds to the ``service_id`` field on the ``request`` instance; if ``request`` is provided, this @@ -706,11 +722,11 @@ def sample_create_service(): def get_service( self, - request: Union[service.GetServiceRequest, dict] = None, + request: Optional[Union[service.GetServiceRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> service.Service: r"""Gets information about a Service. @@ -748,7 +764,9 @@ def sample_get_service(): name (str): Required. The full name of the Service. Format: - projects/{projectnumber}/locations/{location}/services/{service} + projects/{project}/locations/{location}/services/{service}, + where {project} can be project id or + number. This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this @@ -824,14 +842,14 @@ def sample_get_service(): def list_services( self, - request: Union[service.ListServicesRequest, dict] = None, + request: Optional[Union[service.ListServicesRequest, dict]] = None, *, - parent: str = None, + parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> pagers.ListServicesPager: - r"""List Services. + r"""Lists Services. .. code-block:: python @@ -867,9 +885,11 @@ def sample_list_services(): parent (str): Required. The location and project to list resources on. Location must be a - valid GCP region, and may not be the "-" + valid GCP region, and cannot be the "-" wildcard. Format: - projects/{projectnumber}/locations/{location} + projects/{project}/locations/{location}, + where {project} can be project id or + number. This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this @@ -950,11 +970,11 @@ def sample_list_services(): def update_service( self, - request: Union[gcr_service.UpdateServiceRequest, dict] = None, + request: Optional[Union[gcr_service.UpdateServiceRequest, dict]] = None, *, - service: gcr_service.Service = None, + service: Optional[gcr_service.Service] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation.Operation: r"""Updates a Service. @@ -1076,11 +1096,11 @@ def sample_update_service(): def delete_service( self, - request: Union[service.DeleteServiceRequest, dict] = None, + request: Optional[Union[service.DeleteServiceRequest, dict]] = None, *, - name: str = None, + name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> operation.Operation: r"""Deletes a Service. @@ -1124,7 +1144,9 @@ def sample_delete_service(): name (str): Required. The full name of the Service. Format: - projects/{projectnumber}/locations/{location}/services/{service} + projects/{project}/locations/{location}/services/{service}, + where {project} can be project id or + number. This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this @@ -1208,15 +1230,15 @@ def sample_delete_service(): def get_iam_policy( self, - request: Union[iam_policy_pb2.GetIamPolicyRequest, dict] = None, + request: Optional[Union[iam_policy_pb2.GetIamPolicyRequest, dict]] = None, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> policy_pb2.Policy: - r"""Get the IAM Access Control policy currently in effect - for the given Cloud Run Service. This result does not - include any inherited policies. + r"""Gets the IAM Access Control policy currently in + effect for the given Cloud Run Service. This result does + not include any inherited policies. .. code-block:: python @@ -1352,10 +1374,10 @@ def sample_get_iam_policy(): def set_iam_policy( self, - request: Union[iam_policy_pb2.SetIamPolicyRequest, dict] = None, + request: Optional[Union[iam_policy_pb2.SetIamPolicyRequest, dict]] = None, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> policy_pb2.Policy: r"""Sets the IAM Access control policy for the specified @@ -1495,10 +1517,10 @@ def sample_set_iam_policy(): def test_iam_permissions( self, - request: Union[iam_policy_pb2.TestIamPermissionsRequest, dict] = None, + request: Optional[Union[iam_policy_pb2.TestIamPermissionsRequest, dict]] = None, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = (), ) -> iam_policy_pb2.TestIamPermissionsResponse: r"""Returns permissions that a caller has on the @@ -1591,15 +1613,173 @@ def __exit__(self, type, value, traceback): """ self.transport.close() + def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) -try: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution( - "google-cloud-run", - ).version, - ) -except pkg_resources.DistributionNotFound: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) __all__ = ("ServicesClient",) diff --git a/google/cloud/run_v2/services/services/pagers.py b/google/cloud/run_v2/services/services/pagers.py index e2c408a..43e8321 100644 --- a/google/cloud/run_v2/services/services/pagers.py +++ b/google/cloud/run_v2/services/services/pagers.py @@ -18,10 +18,10 @@ AsyncIterator, Awaitable, Callable, + Iterator, + Optional, Sequence, Tuple, - Optional, - Iterator, ) from google.cloud.run_v2.types import service diff --git a/google/cloud/run_v2/services/services/transports/__init__.py b/google/cloud/run_v2/services/services/transports/__init__.py index 9c2d606..94ca3b8 100644 --- a/google/cloud/run_v2/services/services/transports/__init__.py +++ b/google/cloud/run_v2/services/services/transports/__init__.py @@ -19,9 +19,7 @@ from .base import ServicesTransport from .grpc import ServicesGrpcTransport from .grpc_asyncio import ServicesGrpcAsyncIOTransport -from .rest import ServicesRestTransport -from .rest import ServicesRestInterceptor - +from .rest import ServicesRestInterceptor, ServicesRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ServicesTransport]] diff --git a/google/cloud/run_v2/services/services/transports/base.py b/google/cloud/run_v2/services/services/transports/base.py index 6c0c1c6..2010b3a 100644 --- a/google/cloud/run_v2/services/services/transports/base.py +++ b/google/cloud/run_v2/services/services/transports/base.py @@ -15,31 +15,26 @@ # import abc from typing import Awaitable, Callable, Dict, Optional, Sequence, Union -import pkg_resources -import google.auth # type: ignore import google.api_core from google.api_core import exceptions as core_exceptions -from google.api_core import gapic_v1 +from google.api_core import gapic_v1, operations_v1 from google.api_core import retry as retries -from google.api_core import operations_v1 +import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore from google.oauth2 import service_account # type: ignore +from google.cloud.run_v2 import gapic_version as package_version from google.cloud.run_v2.types import service from google.cloud.run_v2.types import service as gcr_service -from google.iam.v1 import iam_policy_pb2 # type: ignore -from google.iam.v1 import policy_pb2 # type: ignore -from google.longrunning import operations_pb2 # type: ignore -try: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution( - "google-cloud-run", - ).version, - ) -except pkg_resources.DistributionNotFound: - DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) class ServicesTransport(abc.ABC): @@ -53,7 +48,7 @@ def __init__( self, *, host: str = DEFAULT_HOST, - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -280,6 +275,33 @@ def test_iam_permissions( ]: raise NotImplementedError() + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], + Union[ + operations_pb2.ListOperationsResponse, + Awaitable[operations_pb2.ListOperationsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/run_v2/services/services/transports/grpc.py b/google/cloud/run_v2/services/services/transports/grpc.py index 622a46b..47cddd6 100644 --- a/google/cloud/run_v2/services/services/transports/grpc.py +++ b/google/cloud/run_v2/services/services/transports/grpc.py @@ -13,24 +13,23 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import warnings from typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings -from google.api_core import grpc_helpers -from google.api_core import operations_v1 -from google.api_core import gapic_v1 +from google.api_core import gapic_v1, grpc_helpers, operations_v1 import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore import grpc # type: ignore from google.cloud.run_v2.types import service from google.cloud.run_v2.types import service as gcr_service -from google.iam.v1 import iam_policy_pb2 # type: ignore -from google.iam.v1 import policy_pb2 # type: ignore -from google.longrunning import operations_pb2 # type: ignore -from .base import ServicesTransport, DEFAULT_CLIENT_INFO + +from .base import DEFAULT_CLIENT_INFO, ServicesTransport class ServicesGrpcTransport(ServicesTransport): @@ -52,14 +51,14 @@ def __init__( self, *, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, - credentials_file: str = None, - scopes: Sequence[str] = None, - channel: grpc.Channel = None, - api_mtls_endpoint: str = None, - client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, - ssl_channel_credentials: grpc.ChannelCredentials = None, - client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[grpc.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, @@ -187,8 +186,8 @@ def __init__( def create_channel( cls, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, - credentials_file: str = None, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, **kwargs, @@ -306,7 +305,7 @@ def list_services( ) -> Callable[[service.ListServicesRequest], service.ListServicesResponse]: r"""Return a callable for the list services method over gRPC. - List Services. + Lists Services. Returns: Callable[[~.ListServicesRequest], @@ -386,9 +385,9 @@ def get_iam_policy( ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], policy_pb2.Policy]: r"""Return a callable for the get iam policy method over gRPC. - Get the IAM Access Control policy currently in effect - for the given Cloud Run Service. This result does not - include any inherited policies. + Gets the IAM Access Control policy currently in + effect for the given Cloud Run Service. This result does + not include any inherited policies. Returns: Callable[[~.GetIamPolicyRequest], @@ -470,6 +469,59 @@ def test_iam_permissions( def close(self): self.grpc_channel.close() + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + @property def kind(self) -> str: return "grpc" diff --git a/google/cloud/run_v2/services/services/transports/grpc_asyncio.py b/google/cloud/run_v2/services/services/transports/grpc_asyncio.py index 538fe94..848c7f8 100644 --- a/google/cloud/run_v2/services/services/transports/grpc_asyncio.py +++ b/google/cloud/run_v2/services/services/transports/grpc_asyncio.py @@ -13,24 +13,23 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings -from google.api_core import gapic_v1 -from google.api_core import grpc_helpers_async -from google.api_core import operations_v1 +from google.api_core import gapic_v1, grpc_helpers_async, operations_v1 from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - +from google.cloud.location import locations_pb2 # type: ignore +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 # type: ignore import grpc # type: ignore from grpc.experimental import aio # type: ignore from google.cloud.run_v2.types import service from google.cloud.run_v2.types import service as gcr_service -from google.iam.v1 import iam_policy_pb2 # type: ignore -from google.iam.v1 import policy_pb2 # type: ignore -from google.longrunning import operations_pb2 # type: ignore -from .base import ServicesTransport, DEFAULT_CLIENT_INFO + +from .base import DEFAULT_CLIENT_INFO, ServicesTransport from .grpc import ServicesGrpcTransport @@ -54,7 +53,7 @@ class ServicesGrpcAsyncIOTransport(ServicesTransport): def create_channel( cls, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -97,15 +96,15 @@ def __init__( self, *, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, + credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, - channel: aio.Channel = None, - api_mtls_endpoint: str = None, - client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, - ssl_channel_credentials: grpc.ChannelCredentials = None, - client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, - quota_project_id=None, + channel: Optional[aio.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, api_audience: Optional[str] = None, @@ -317,7 +316,7 @@ def list_services( ]: r"""Return a callable for the list services method over gRPC. - List Services. + Lists Services. Returns: Callable[[~.ListServicesRequest], @@ -399,9 +398,9 @@ def get_iam_policy( ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: r"""Return a callable for the get iam policy method over gRPC. - Get the IAM Access Control policy currently in effect - for the given Cloud Run Service. This result does not - include any inherited policies. + Gets the IAM Access Control policy currently in + effect for the given Cloud Run Service. This result does + not include any inherited policies. Returns: Callable[[~.GetIamPolicyRequest], @@ -483,5 +482,58 @@ def test_iam_permissions( def close(self): return self.grpc_channel.close() + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + __all__ = ("ServicesGrpcAsyncIOTransport",) diff --git a/google/cloud/run_v2/services/services/transports/rest.py b/google/cloud/run_v2/services/services/transports/rest.py index 1eb89e6..90605af 100644 --- a/google/cloud/run_v2/services/services/transports/rest.py +++ b/google/cloud/run_v2/services/services/transports/rest.py @@ -14,25 +14,29 @@ # limitations under the License. # -from google.auth.transport.requests import AuthorizedSession # type: ignore +import dataclasses import json # type: ignore -import grpc # type: ignore -from google.auth.transport.grpc import SslCredentials # type: ignore -from google.auth import credentials as ga_credentials # type: ignore +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) from google.api_core import exceptions as core_exceptions from google.api_core import retry as retries -from google.api_core import rest_helpers -from google.api_core import rest_streaming -from google.api_core import path_template -from google.api_core import gapic_v1 - +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import json_format -from google.api_core import operations_v1 +import grpc # type: ignore from requests import __version__ as requests_version -import dataclasses -import re -from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union -import warnings try: OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] @@ -40,14 +44,15 @@ OptionalRetry = Union[retries.Retry, object] # type: ignore -from google.cloud.run_v2.types import service -from google.cloud.run_v2.types import service as gcr_service from google.iam.v1 import iam_policy_pb2 # type: ignore from google.iam.v1 import policy_pb2 # type: ignore from google.longrunning import operations_pb2 # type: ignore -from .base import ServicesTransport, DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from google.cloud.run_v2.types import service +from google.cloud.run_v2.types import service as gcr_service +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import ServicesTransport DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, @@ -71,61 +76,69 @@ class ServicesRestInterceptor: .. code-block:: python class MyCustomServicesInterceptor(ServicesRestInterceptor): - def pre_create_service(request, metadata): + def pre_create_service(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_create_service(response): + def post_create_service(self, response): logging.log(f"Received response: {response}") + return response - def pre_delete_service(request, metadata): + def pre_delete_service(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_delete_service(response): + def post_delete_service(self, response): logging.log(f"Received response: {response}") + return response - def pre_get_iam_policy(request, metadata): + def pre_get_iam_policy(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_get_iam_policy(response): + def post_get_iam_policy(self, response): logging.log(f"Received response: {response}") + return response - def pre_get_service(request, metadata): + def pre_get_service(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_get_service(response): + def post_get_service(self, response): logging.log(f"Received response: {response}") + return response - def pre_list_services(request, metadata): + def pre_list_services(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_list_services(response): + def post_list_services(self, response): logging.log(f"Received response: {response}") + return response - def pre_set_iam_policy(request, metadata): + def pre_set_iam_policy(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_set_iam_policy(response): + def post_set_iam_policy(self, response): logging.log(f"Received response: {response}") + return response - def pre_test_iam_permissions(request, metadata): + def pre_test_iam_permissions(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_test_iam_permissions(response): + def post_test_iam_permissions(self, response): logging.log(f"Received response: {response}") + return response - def pre_update_service(request, metadata): + def pre_update_service(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata - def post_update_service(response): + def post_update_service(self, response): logging.log(f"Received response: {response}") + return response transport = ServicesRestTransport(interceptor=MyCustomServicesInterceptor()) client = ServicesClient(transport=transport) @@ -305,6 +318,75 @@ def post_update_service( """ return response + def pre_delete_operation( + self, + request: operations_pb2.DeleteOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> None: + """Pre-rpc interceptor for delete_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Services server. + """ + return request, metadata + + def post_delete_operation( + self, response: operations_pb2.DeleteOperationRequest + ) -> None: + """Post-rpc interceptor for delete_operation + + Override in a subclass to manipulate the response + after it is returned by the Services server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Services server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.GetOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Services server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.ListOperationsResponse: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Services server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsRequest + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Services server but before + it is returned to user code. + """ + return response + @dataclasses.dataclass class ServicesRestStub: @@ -324,19 +406,16 @@ class ServicesRestTransport(ServicesTransport): It sends JSON representations of protocol buffers over HTTP/1.1 - NOTE: This REST transport functionality is currently in a beta - state (preview). We welcome your feedback via an issue in this - library's source repository. Thank you! """ def __init__( self, *, host: str = "run.googleapis.com", - credentials: ga_credentials.Credentials = None, - credentials_file: str = None, - scopes: Sequence[str] = None, - client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, @@ -346,39 +425,35 @@ def __init__( ) -> None: """Instantiate the transport. - NOTE: This REST transport functionality is currently in a beta - state (preview). We welcome your feedback via a GitHub issue in - this library's repository. Thank you! - - Args: - host (Optional[str]): - The hostname to connect to. - credentials (Optional[google.auth.credentials.Credentials]): The - authorization credentials to attach to requests. These - credentials identify the application to the service; if none - are specified, the client will attempt to ascertain the - credentials from the environment. - - credentials_file (Optional[str]): A file with credentials that can - be loaded with :func:`google.auth.load_credentials_from_file`. - This argument is ignored if ``channel`` is provided. - scopes (Optional(Sequence[str])): A list of scopes. This argument is - ignored if ``channel`` is provided. - client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client - certificate to configure mutual TLS HTTP channel. It is ignored - if ``channel`` is provided. - quota_project_id (Optional[str]): An optional project to use for billing - and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you are developing - your own client library. - always_use_jwt_access (Optional[bool]): Whether self signed JWT should - be used for service account credentials. - url_scheme: the protocol scheme for the API endpoint. Normally - "https", but for testing or local servers, - "http" can be specified. + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. """ # Run the base constructor # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. @@ -446,6 +521,7 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: credentials=self._credentials, scopes=self._scopes, http_options=http_options, + path_prefix="v2", ) self._operations_client = operations_v1.AbstractOperationsClient( @@ -476,7 +552,7 @@ def __call__( request: gcr_service.CreateServiceRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> operations_pb2.Operation: r"""Call the create service method over HTTP. @@ -516,7 +592,7 @@ def __call__( body = json_format.MessageToJson( transcoded_request["body"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) uri = transcoded_request["uri"] method = transcoded_request["method"] @@ -526,11 +602,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -572,7 +650,7 @@ def __call__( request: service.DeleteServiceRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> operations_pb2.Operation: r"""Call the delete service method over HTTP. @@ -614,11 +692,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -659,7 +739,7 @@ def __call__( request: iam_policy_pb2.GetIamPolicyRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> policy_pb2.Policy: r"""Call the get iam policy method over HTTP. @@ -770,11 +850,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -817,7 +899,7 @@ def __call__( request: service.GetServiceRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> service.Service: r"""Call the get service method over HTTP. @@ -865,11 +947,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -912,7 +996,7 @@ def __call__( request: service.ListServicesRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> service.ListServicesResponse: r"""Call the list services method over HTTP. @@ -953,11 +1037,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -1000,7 +1086,7 @@ def __call__( request: iam_policy_pb2.SetIamPolicyRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> policy_pb2.Policy: r"""Call the set iam policy method over HTTP. @@ -1109,7 +1195,7 @@ def __call__( body = json_format.MessageToJson( transcoded_request["body"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) uri = transcoded_request["uri"] method = transcoded_request["method"] @@ -1119,11 +1205,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -1167,7 +1255,7 @@ def __call__( request: iam_policy_pb2.TestIamPermissionsRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> iam_policy_pb2.TestIamPermissionsResponse: r"""Call the test iam permissions method over HTTP. @@ -1204,7 +1292,7 @@ def __call__( body = json_format.MessageToJson( transcoded_request["body"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) uri = transcoded_request["uri"] method = transcoded_request["method"] @@ -1214,11 +1302,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -1262,7 +1352,7 @@ def __call__( request: gcr_service.UpdateServiceRequest, *, retry: OptionalRetry = gapic_v1.method.DEFAULT, - timeout: float = None, + timeout: Optional[float] = None, metadata: Sequence[Tuple[str, str]] = (), ) -> operations_pb2.Operation: r"""Call the update service method over HTTP. @@ -1302,7 +1392,7 @@ def __call__( body = json_format.MessageToJson( transcoded_request["body"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) uri = transcoded_request["uri"] method = transcoded_request["method"] @@ -1312,11 +1402,13 @@ def __call__( json_format.MessageToJson( transcoded_request["query_params"], including_default_value_fields=False, - use_integers_for_enums=False, + use_integers_for_enums=True, ) ) query_params.update(self._get_unset_required_fields(query_params)) + query_params["$alt"] = "json;enum-encoding=int" + # Send the request headers = dict(metadata) headers["Content-Type"] = "application/json" @@ -1404,6 +1496,203 @@ def update_service( # In C++ this would require a dynamic_cast return self._UpdateService(self._session, self._host, self._interceptor) # type: ignore + @property + def delete_operation(self): + return self._DeleteOperation(self._session, self._host, self._interceptor) # type: ignore + + class _DeleteOperation(ServicesRestStub): + def __call__( + self, + request: operations_pb2.DeleteOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the delete operation method over HTTP. + + Args: + request (operations_pb2.DeleteOperationRequest): + The request object for DeleteOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_delete_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_delete_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ServicesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ServicesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + @property def kind(self) -> str: return "rest" diff --git a/google/cloud/run_v2/services/tasks/__init__.py b/google/cloud/run_v2/services/tasks/__init__.py new file mode 100644 index 0000000..fdbb36c --- /dev/null +++ b/google/cloud/run_v2/services/tasks/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 .async_client import TasksAsyncClient +from .client import TasksClient + +__all__ = ( + "TasksClient", + "TasksAsyncClient", +) diff --git a/google/cloud/run_v2/services/tasks/async_client.py b/google/cloud/run_v2/services/tasks/async_client.py new file mode 100644 index 0000000..8bed92d --- /dev/null +++ b/google/cloud/run_v2/services/tasks/async_client.py @@ -0,0 +1,622 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +import functools +import re +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.run_v2.services.tasks import pagers +from google.cloud.run_v2.types import condition, k8s_min, task, vendor_settings + +from .client import TasksClient +from .transports.base import DEFAULT_CLIENT_INFO, TasksTransport +from .transports.grpc_asyncio import TasksGrpcAsyncIOTransport + + +class TasksAsyncClient: + """Cloud Run Task Control Plane API.""" + + _client: TasksClient + + DEFAULT_ENDPOINT = TasksClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = TasksClient.DEFAULT_MTLS_ENDPOINT + + connector_path = staticmethod(TasksClient.connector_path) + parse_connector_path = staticmethod(TasksClient.parse_connector_path) + crypto_key_path = staticmethod(TasksClient.crypto_key_path) + parse_crypto_key_path = staticmethod(TasksClient.parse_crypto_key_path) + execution_path = staticmethod(TasksClient.execution_path) + parse_execution_path = staticmethod(TasksClient.parse_execution_path) + job_path = staticmethod(TasksClient.job_path) + parse_job_path = staticmethod(TasksClient.parse_job_path) + secret_path = staticmethod(TasksClient.secret_path) + parse_secret_path = staticmethod(TasksClient.parse_secret_path) + secret_version_path = staticmethod(TasksClient.secret_version_path) + parse_secret_version_path = staticmethod(TasksClient.parse_secret_version_path) + task_path = staticmethod(TasksClient.task_path) + parse_task_path = staticmethod(TasksClient.parse_task_path) + common_billing_account_path = staticmethod(TasksClient.common_billing_account_path) + parse_common_billing_account_path = staticmethod( + TasksClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(TasksClient.common_folder_path) + parse_common_folder_path = staticmethod(TasksClient.parse_common_folder_path) + common_organization_path = staticmethod(TasksClient.common_organization_path) + parse_common_organization_path = staticmethod( + TasksClient.parse_common_organization_path + ) + common_project_path = staticmethod(TasksClient.common_project_path) + parse_common_project_path = staticmethod(TasksClient.parse_common_project_path) + common_location_path = staticmethod(TasksClient.common_location_path) + parse_common_location_path = staticmethod(TasksClient.parse_common_location_path) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TasksAsyncClient: The constructed client. + """ + return TasksClient.from_service_account_info.__func__(TasksAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TasksAsyncClient: The constructed client. + """ + return TasksClient.from_service_account_file.__func__(TasksAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return TasksClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> TasksTransport: + """Returns the transport used by the client instance. + + Returns: + TasksTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(TasksClient).get_transport_class, type(TasksClient) + ) + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, TasksTransport] = "grpc_asyncio", + client_options: Optional[ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the tasks client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.TasksTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = TasksClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def get_task( + self, + request: Optional[Union[task.GetTaskRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> task.Task: + r"""Gets information about a Task. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_get_task(): + # Create a client + client = run_v2.TasksAsyncClient() + + # Initialize request argument(s) + request = run_v2.GetTaskRequest( + name="name_value", + ) + + # Make the request + response = await client.get_task(request=request) + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.GetTaskRequest, dict]]): + The request object. Request message for obtaining a Task + by its full name. + name (:class:`str`): + Required. The full name of the Task. + Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}/tasks/{task} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.types.Task: + Task represents a single run of a + container to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = task.GetTaskRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_task, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_tasks( + self, + request: Optional[Union[task.ListTasksRequest, dict]] = None, + *, + parent: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTasksAsyncPager: + r"""Lists Tasks from an Execution of a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + async def sample_list_tasks(): + # Create a client + client = run_v2.TasksAsyncClient() + + # Initialize request argument(s) + request = run_v2.ListTasksRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_tasks(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Optional[Union[google.cloud.run_v2.types.ListTasksRequest, dict]]): + The request object. Request message for retrieving a + list of Tasks. + parent (:class:`str`): + Required. The Execution from which + the Tasks should be listed. To list all + Tasks across Executions of a Job, use + "-" instead of Execution name. To list + all Tasks across Jobs, use "-" instead + of Job name. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution} + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.services.tasks.pagers.ListTasksAsyncPager: + Response message containing a list of + Tasks. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = task.ListTasksRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_tasks, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTasksAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +__all__ = ("TasksAsyncClient",) diff --git a/google/cloud/run_v2/services/tasks/client.py b/google/cloud/run_v2/services/tasks/client.py new file mode 100644 index 0000000..d3c77b6 --- /dev/null +++ b/google/cloud/run_v2/services/tasks/client.py @@ -0,0 +1,989 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +import os +import re +from typing import ( + Dict, + Mapping, + MutableMapping, + MutableSequence, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.run_v2.services.tasks import pagers +from google.cloud.run_v2.types import condition, k8s_min, task, vendor_settings + +from .transports.base import DEFAULT_CLIENT_INFO, TasksTransport +from .transports.grpc import TasksGrpcTransport +from .transports.grpc_asyncio import TasksGrpcAsyncIOTransport +from .transports.rest import TasksRestTransport + + +class TasksClientMeta(type): + """Metaclass for the Tasks client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[TasksTransport]] + _transport_registry["grpc"] = TasksGrpcTransport + _transport_registry["grpc_asyncio"] = TasksGrpcAsyncIOTransport + _transport_registry["rest"] = TasksRestTransport + + def get_transport_class( + cls, + label: Optional[str] = None, + ) -> Type[TasksTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class TasksClient(metaclass=TasksClientMeta): + """Cloud Run Task Control Plane API.""" + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "run.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TasksClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TasksClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TasksTransport: + """Returns the transport used by the client instance. + + Returns: + TasksTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def connector_path( + project: str, + location: str, + connector: str, + ) -> str: + """Returns a fully-qualified connector string.""" + return "projects/{project}/locations/{location}/connectors/{connector}".format( + project=project, + location=location, + connector=connector, + ) + + @staticmethod + def parse_connector_path(path: str) -> Dict[str, str]: + """Parses a connector path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/connectors/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def crypto_key_path( + project: str, + location: str, + key_ring: str, + crypto_key: str, + ) -> str: + """Returns a fully-qualified crypto_key string.""" + return "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + + @staticmethod + def parse_crypto_key_path(path: str) -> Dict[str, str]: + """Parses a crypto_key path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/keyRings/(?P.+?)/cryptoKeys/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def execution_path( + project: str, + location: str, + job: str, + execution: str, + ) -> str: + """Returns a fully-qualified execution string.""" + return "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}".format( + project=project, + location=location, + job=job, + execution=execution, + ) + + @staticmethod + def parse_execution_path(path: str) -> Dict[str, str]: + """Parses a execution path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)/executions/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def job_path( + project: str, + location: str, + job: str, + ) -> str: + """Returns a fully-qualified job string.""" + return "projects/{project}/locations/{location}/jobs/{job}".format( + project=project, + location=location, + job=job, + ) + + @staticmethod + def parse_job_path(path: str) -> Dict[str, str]: + """Parses a job path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def secret_path( + project: str, + secret: str, + ) -> str: + """Returns a fully-qualified secret string.""" + return "projects/{project}/secrets/{secret}".format( + project=project, + secret=secret, + ) + + @staticmethod + def parse_secret_path(path: str) -> Dict[str, str]: + """Parses a secret path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/secrets/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def secret_version_path( + project: str, + secret: str, + version: str, + ) -> str: + """Returns a fully-qualified secret_version string.""" + return "projects/{project}/secrets/{secret}/versions/{version}".format( + project=project, + secret=secret, + version=version, + ) + + @staticmethod + def parse_secret_version_path(path: str) -> Dict[str, str]: + """Parses a secret_version path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/secrets/(?P.+?)/versions/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def task_path( + project: str, + location: str, + job: str, + execution: str, + task: str, + ) -> str: + """Returns a fully-qualified task string.""" + return "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}/tasks/{task}".format( + project=project, + location=location, + job=job, + execution=execution, + task=task, + ) + + @staticmethod + def parse_task_path(path: str) -> Dict[str, str]: + """Parses a task path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/jobs/(?P.+?)/executions/(?P.+?)/tasks/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Optional[Union[str, TasksTransport]] = None, + client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the tasks client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, TasksTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + client_options = cast(client_options_lib.ClientOptions, client_options) + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, TasksTransport): + # transport is a TasksTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def get_task( + self, + request: Optional[Union[task.GetTaskRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> task.Task: + r"""Gets information about a Task. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_get_task(): + # Create a client + client = run_v2.TasksClient() + + # Initialize request argument(s) + request = run_v2.GetTaskRequest( + name="name_value", + ) + + # Make the request + response = client.get_task(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.run_v2.types.GetTaskRequest, dict]): + The request object. Request message for obtaining a Task + by its full name. + name (str): + Required. The full name of the Task. + Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}/tasks/{task} + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.types.Task: + Task represents a single run of a + container to completion. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a task.GetTaskRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, task.GetTaskRequest): + request = task.GetTaskRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_task] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_tasks( + self, + request: Optional[Union[task.ListTasksRequest, dict]] = None, + *, + parent: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTasksPager: + r"""Lists Tasks from an Execution of a Job. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import run_v2 + + def sample_list_tasks(): + # Create a client + client = run_v2.TasksClient() + + # Initialize request argument(s) + request = run_v2.ListTasksRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_tasks(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.cloud.run_v2.types.ListTasksRequest, dict]): + The request object. Request message for retrieving a + list of Tasks. + parent (str): + Required. The Execution from which + the Tasks should be listed. To list all + Tasks across Executions of a Job, use + "-" instead of Execution name. To list + all Tasks across Jobs, use "-" instead + of Job name. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution} + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.run_v2.services.tasks.pagers.ListTasksPager: + Response message containing a list of + Tasks. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a task.ListTasksRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, task.ListTasksRequest): + request = task.ListTasksRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_tasks] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTasksPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + def list_operations( + self, + request: Optional[operations_pb2.ListOperationsRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message for + `ListOperations` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.ListOperationsResponse: + Response message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_operation( + self, + request: Optional[operations_pb2.DeleteOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +__all__ = ("TasksClient",) diff --git a/google/cloud/run_v2/services/tasks/pagers.py b/google/cloud/run_v2/services/tasks/pagers.py new file mode 100644 index 0000000..7febfaf --- /dev/null +++ b/google/cloud/run_v2/services/tasks/pagers.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Iterator, + Optional, + Sequence, + Tuple, +) + +from google.cloud.run_v2.types import task + + +class ListTasksPager: + """A pager for iterating through ``list_tasks`` requests. + + This class thinly wraps an initial + :class:`google.cloud.run_v2.types.ListTasksResponse` object, and + provides an ``__iter__`` method to iterate through its + ``tasks`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTasks`` requests and continue to iterate + through the ``tasks`` field on the + corresponding responses. + + All the usual :class:`google.cloud.run_v2.types.ListTasksResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., task.ListTasksResponse], + request: task.ListTasksRequest, + response: task.ListTasksResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.run_v2.types.ListTasksRequest): + The initial request object. + response (google.cloud.run_v2.types.ListTasksResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = task.ListTasksRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[task.ListTasksResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[task.Task]: + for page in self.pages: + yield from page.tasks + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTasksAsyncPager: + """A pager for iterating through ``list_tasks`` requests. + + This class thinly wraps an initial + :class:`google.cloud.run_v2.types.ListTasksResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``tasks`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTasks`` requests and continue to iterate + through the ``tasks`` field on the + corresponding responses. + + All the usual :class:`google.cloud.run_v2.types.ListTasksResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[task.ListTasksResponse]], + request: task.ListTasksRequest, + response: task.ListTasksResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.run_v2.types.ListTasksRequest): + The initial request object. + response (google.cloud.run_v2.types.ListTasksResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = task.ListTasksRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[task.ListTasksResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[task.Task]: + async def async_generator(): + async for page in self.pages: + for response in page.tasks: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/run_v2/services/tasks/transports/__init__.py b/google/cloud/run_v2/services/tasks/transports/__init__.py new file mode 100644 index 0000000..7a5c9c2 --- /dev/null +++ b/google/cloud/run_v2/services/tasks/transports/__init__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 collections import OrderedDict +from typing import Dict, Type + +from .base import TasksTransport +from .grpc import TasksGrpcTransport +from .grpc_asyncio import TasksGrpcAsyncIOTransport +from .rest import TasksRestInterceptor, TasksRestTransport + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[TasksTransport]] +_transport_registry["grpc"] = TasksGrpcTransport +_transport_registry["grpc_asyncio"] = TasksGrpcAsyncIOTransport +_transport_registry["rest"] = TasksRestTransport + +__all__ = ( + "TasksTransport", + "TasksGrpcTransport", + "TasksGrpcAsyncIOTransport", + "TasksRestTransport", + "TasksRestInterceptor", +) diff --git a/google/cloud/run_v2/services/tasks/transports/base.py b/google/cloud/run_v2/services/tasks/transports/base.py new file mode 100644 index 0000000..b7034c2 --- /dev/null +++ b/google/cloud/run_v2/services/tasks/transports/base.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union + +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.oauth2 import service_account # type: ignore + +from google.cloud.run_v2 import gapic_version as package_version +from google.cloud.run_v2.types import task + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=package_version.__version__ +) + + +class TasksTransport(abc.ABC): + """Abstract transport class for Tasks.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + DEFAULT_HOST: str = "run.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.get_task: gapic_v1.method.wrap_method( + self.get_task, + default_timeout=None, + client_info=client_info, + ), + self.list_tasks: gapic_v1.method.wrap_method( + self.list_tasks, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def get_task( + self, + ) -> Callable[[task.GetTaskRequest], Union[task.Task, Awaitable[task.Task]]]: + raise NotImplementedError() + + @property + def list_tasks( + self, + ) -> Callable[ + [task.ListTasksRequest], + Union[task.ListTasksResponse, Awaitable[task.ListTasksResponse]], + ]: + raise NotImplementedError() + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], + Union[ + operations_pb2.ListOperationsResponse, + Awaitable[operations_pb2.ListOperationsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("TasksTransport",) diff --git a/google/cloud/run_v2/services/tasks/transports/grpc.py b/google/cloud/run_v2/services/tasks/transports/grpc.py new file mode 100644 index 0000000..e38f42b --- /dev/null +++ b/google/cloud/run_v2/services/tasks/transports/grpc.py @@ -0,0 +1,342 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +import grpc # type: ignore + +from google.cloud.run_v2.types import task + +from .base import DEFAULT_CLIENT_INFO, TasksTransport + + +class TasksGrpcTransport(TasksTransport): + """gRPC backend transport for Tasks. + + Cloud Run Task Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[grpc.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def get_task(self) -> Callable[[task.GetTaskRequest], task.Task]: + r"""Return a callable for the get task method over gRPC. + + Gets information about a Task. + + Returns: + Callable[[~.GetTaskRequest], + ~.Task]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_task" not in self._stubs: + self._stubs["get_task"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Tasks/GetTask", + request_serializer=task.GetTaskRequest.serialize, + response_deserializer=task.Task.deserialize, + ) + return self._stubs["get_task"] + + @property + def list_tasks(self) -> Callable[[task.ListTasksRequest], task.ListTasksResponse]: + r"""Return a callable for the list tasks method over gRPC. + + Lists Tasks from an Execution of a Job. + + Returns: + Callable[[~.ListTasksRequest], + ~.ListTasksResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_tasks" not in self._stubs: + self._stubs["list_tasks"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Tasks/ListTasks", + request_serializer=task.ListTasksRequest.serialize, + response_deserializer=task.ListTasksResponse.deserialize, + ) + return self._stubs["list_tasks"] + + def close(self): + self.grpc_channel.close() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("TasksGrpcTransport",) diff --git a/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py b/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py new file mode 100644 index 0000000..43c85e6 --- /dev/null +++ b/google/cloud/run_v2/services/tasks/transports/grpc_asyncio.py @@ -0,0 +1,343 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers_async +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.run_v2.types import task + +from .base import DEFAULT_CLIENT_INFO, TasksTransport +from .grpc import TasksGrpcTransport + + +class TasksGrpcAsyncIOTransport(TasksTransport): + """gRPC AsyncIO backend transport for Tasks. + + Cloud Run Task Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: Optional[aio.Channel] = None, + api_mtls_endpoint: Optional[str] = None, + client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def get_task(self) -> Callable[[task.GetTaskRequest], Awaitable[task.Task]]: + r"""Return a callable for the get task method over gRPC. + + Gets information about a Task. + + Returns: + Callable[[~.GetTaskRequest], + Awaitable[~.Task]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_task" not in self._stubs: + self._stubs["get_task"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Tasks/GetTask", + request_serializer=task.GetTaskRequest.serialize, + response_deserializer=task.Task.deserialize, + ) + return self._stubs["get_task"] + + @property + def list_tasks( + self, + ) -> Callable[[task.ListTasksRequest], Awaitable[task.ListTasksResponse]]: + r"""Return a callable for the list tasks method over gRPC. + + Lists Tasks from an Execution of a Job. + + Returns: + Callable[[~.ListTasksRequest], + Awaitable[~.ListTasksResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_tasks" not in self._stubs: + self._stubs["list_tasks"] = self.grpc_channel.unary_unary( + "/google.cloud.run.v2.Tasks/ListTasks", + request_serializer=task.ListTasksRequest.serialize, + response_deserializer=task.ListTasksResponse.deserialize, + ) + return self._stubs["list_tasks"] + + def close(self): + return self.grpc_channel.close() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + + +__all__ = ("TasksGrpcAsyncIOTransport",) diff --git a/google/cloud/run_v2/services/tasks/transports/rest.py b/google/cloud/run_v2/services/tasks/transports/rest.py new file mode 100644 index 0000000..7c339f3 --- /dev/null +++ b/google/cloud/run_v2/services/tasks/transports/rest.py @@ -0,0 +1,693 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 dataclasses +import json # type: ignore +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.run_v2.types import task + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import TasksTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class TasksRestInterceptor: + """Interceptor for Tasks. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the TasksRestTransport. + + .. code-block:: python + class MyCustomTasksInterceptor(TasksRestInterceptor): + def pre_get_task(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_task(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_tasks(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_tasks(self, response): + logging.log(f"Received response: {response}") + return response + + transport = TasksRestTransport(interceptor=MyCustomTasksInterceptor()) + client = TasksClient(transport=transport) + + + """ + + def pre_get_task( + self, request: task.GetTaskRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[task.GetTaskRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_task + + Override in a subclass to manipulate the request or metadata + before they are sent to the Tasks server. + """ + return request, metadata + + def post_get_task(self, response: task.Task) -> task.Task: + """Post-rpc interceptor for get_task + + Override in a subclass to manipulate the response + after it is returned by the Tasks server but before + it is returned to user code. + """ + return response + + def pre_list_tasks( + self, request: task.ListTasksRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[task.ListTasksRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_tasks + + Override in a subclass to manipulate the request or metadata + before they are sent to the Tasks server. + """ + return request, metadata + + def post_list_tasks( + self, response: task.ListTasksResponse + ) -> task.ListTasksResponse: + """Post-rpc interceptor for list_tasks + + Override in a subclass to manipulate the response + after it is returned by the Tasks server but before + it is returned to user code. + """ + return response + + def pre_delete_operation( + self, + request: operations_pb2.DeleteOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> None: + """Pre-rpc interceptor for delete_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Tasks server. + """ + return request, metadata + + def post_delete_operation( + self, response: operations_pb2.DeleteOperationRequest + ) -> None: + """Post-rpc interceptor for delete_operation + + Override in a subclass to manipulate the response + after it is returned by the Tasks server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Tasks server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.GetOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Tasks server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.ListOperationsResponse: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Tasks server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsRequest + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Tasks server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class TasksRestStub: + _session: AuthorizedSession + _host: str + _interceptor: TasksRestInterceptor + + +class TasksRestTransport(TasksTransport): + """REST backend transport for Tasks. + + Cloud Run Task Control Plane API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "run.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[TasksRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or TasksRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetTask(TasksRestStub): + def __hash__(self): + return hash("GetTask") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: task.GetTaskRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> task.Task: + r"""Call the get task method over HTTP. + + Args: + request (~.task.GetTaskRequest): + The request object. Request message for obtaining a Task + by its full name. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.task.Task: + Task represents a single run of a + container to completion. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/jobs/*/executions/*/tasks/*}", + }, + ] + request, metadata = self._interceptor.pre_get_task(request, metadata) + pb_request = task.GetTaskRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = task.Task() + pb_resp = task.Task.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_task(resp) + return resp + + class _ListTasks(TasksRestStub): + def __hash__(self): + return hash("ListTasks") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: task.ListTasksRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> task.ListTasksResponse: + r"""Call the list tasks method over HTTP. + + Args: + request (~.task.ListTasksRequest): + The request object. Request message for retrieving a list + of Tasks. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.task.ListTasksResponse: + Response message containing a list of + Tasks. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/jobs/*/executions/*}/tasks", + }, + ] + request, metadata = self._interceptor.pre_list_tasks(request, metadata) + pb_request = task.ListTasksRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = task.ListTasksResponse() + pb_resp = task.ListTasksResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_tasks(resp) + return resp + + @property + def get_task(self) -> Callable[[task.GetTaskRequest], task.Task]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetTask(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_tasks(self) -> Callable[[task.ListTasksRequest], task.ListTasksResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListTasks(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_operation(self): + return self._DeleteOperation(self._session, self._host, self._interceptor) # type: ignore + + class _DeleteOperation(TasksRestStub): + def __call__( + self, + request: operations_pb2.DeleteOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the delete operation method over HTTP. + + Args: + request (operations_pb2.DeleteOperationRequest): + The request object for DeleteOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_delete_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_delete_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(TasksRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(TasksRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("TasksRestTransport",) diff --git a/google/cloud/run_v2/types/__init__.py b/google/cloud/run_v2/types/__init__.py index 5a6b804..6dd1c06 100644 --- a/google/cloud/run_v2/types/__init__.py +++ b/google/cloud/run_v2/types/__init__.py @@ -13,8 +13,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from .condition import ( - Condition, +from .condition import Condition +from .execution import ( + DeleteExecutionRequest, + Execution, + GetExecutionRequest, + ListExecutionsRequest, + ListExecutionsResponse, +) +from .execution_template import ExecutionTemplate +from .job import ( + CreateJobRequest, + DeleteJobRequest, + ExecutionReference, + GetJobRequest, + Job, + ListJobsRequest, + ListJobsResponse, + RunJobRequest, + UpdateJobRequest, ) from .k8s_min import ( CloudSqlInstance, @@ -22,9 +39,14 @@ ContainerPort, EnvVar, EnvVarSource, + GRPCAction, + HTTPGetAction, + HTTPHeader, + Probe, ResourceRequirements, SecretKeySelector, SecretVolumeSource, + TCPSocketAction, VersionToPath, Volume, VolumeMount, @@ -36,9 +58,7 @@ ListRevisionsResponse, Revision, ) -from .revision_template import ( - RevisionTemplate, -) +from .revision_template import RevisionTemplate from .service import ( CreateServiceRequest, DeleteServiceRequest, @@ -48,29 +68,57 @@ Service, UpdateServiceRequest, ) +from .task import ( + GetTaskRequest, + ListTasksRequest, + ListTasksResponse, + Task, + TaskAttemptResult, +) +from .task_template import TaskTemplate from .traffic_target import ( TrafficTarget, - TrafficTargetStatus, TrafficTargetAllocationType, + TrafficTargetStatus, ) from .vendor_settings import ( BinaryAuthorization, - RevisionScaling, - VpcAccess, ExecutionEnvironment, IngressTraffic, + RevisionScaling, + VpcAccess, ) __all__ = ( "Condition", + "DeleteExecutionRequest", + "Execution", + "GetExecutionRequest", + "ListExecutionsRequest", + "ListExecutionsResponse", + "ExecutionTemplate", + "CreateJobRequest", + "DeleteJobRequest", + "ExecutionReference", + "GetJobRequest", + "Job", + "ListJobsRequest", + "ListJobsResponse", + "RunJobRequest", + "UpdateJobRequest", "CloudSqlInstance", "Container", "ContainerPort", "EnvVar", "EnvVarSource", + "GRPCAction", + "HTTPGetAction", + "HTTPHeader", + "Probe", "ResourceRequirements", "SecretKeySelector", "SecretVolumeSource", + "TCPSocketAction", "VersionToPath", "Volume", "VolumeMount", @@ -87,6 +135,12 @@ "ListServicesResponse", "Service", "UpdateServiceRequest", + "GetTaskRequest", + "ListTasksRequest", + "ListTasksResponse", + "Task", + "TaskAttemptResult", + "TaskTemplate", "TrafficTarget", "TrafficTargetStatus", "TrafficTargetAllocationType", diff --git a/google/cloud/run_v2/types/condition.py b/google/cloud/run_v2/types/condition.py index 9ded5b5..4285975 100644 --- a/google/cloud/run_v2/types/condition.py +++ b/google/cloud/run_v2/types/condition.py @@ -13,10 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence from google.protobuf import timestamp_pb2 # type: ignore - +import proto # type: ignore __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -123,43 +123,44 @@ class ExecutionReason(proto.Enum): EXECUTION_REASON_UNDEFINED = 0 JOB_STATUS_SERVICE_POLLING_ERROR = 1 NON_ZERO_EXIT_CODE = 2 + CANCELLED = 3 - type_ = proto.Field( + type_: str = proto.Field( proto.STRING, number=1, ) - state = proto.Field( + state: State = proto.Field( proto.ENUM, number=2, enum=State, ) - message = proto.Field( + message: str = proto.Field( proto.STRING, number=3, ) - last_transition_time = proto.Field( + last_transition_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=4, message=timestamp_pb2.Timestamp, ) - severity = proto.Field( + severity: Severity = proto.Field( proto.ENUM, number=5, enum=Severity, ) - reason = proto.Field( + reason: CommonReason = proto.Field( proto.ENUM, number=6, oneof="reasons", enum=CommonReason, ) - revision_reason = proto.Field( + revision_reason: RevisionReason = proto.Field( proto.ENUM, number=9, oneof="reasons", enum=RevisionReason, ) - execution_reason = proto.Field( + execution_reason: ExecutionReason = proto.Field( proto.ENUM, number=11, oneof="reasons", diff --git a/google/cloud/run_v2/types/execution.py b/google/cloud/run_v2/types/execution.py new file mode 100644 index 0000000..8d0377d --- /dev/null +++ b/google/cloud/run_v2/types/execution.py @@ -0,0 +1,372 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import MutableMapping, MutableSequence + +from google.api import launch_stage_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore + +from google.cloud.run_v2.types import condition, task_template + +__protobuf__ = proto.module( + package="google.cloud.run.v2", + manifest={ + "GetExecutionRequest", + "ListExecutionsRequest", + "ListExecutionsResponse", + "DeleteExecutionRequest", + "Execution", + }, +) + + +class GetExecutionRequest(proto.Message): + r"""Request message for obtaining a Execution by its full name. + + Attributes: + name (str): + Required. The full name of the Execution. + Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}, + where {project} can be project id or number. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + + +class ListExecutionsRequest(proto.Message): + r"""Request message for retrieving a list of Executions. + + Attributes: + parent (str): + Required. The Execution from which the + Executions should be listed. To list all + Executions across Jobs, use "-" instead of Job + name. Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or number. + page_size (int): + Maximum number of Executions to return in + this call. + page_token (str): + A page token received from a previous call to + ListExecutions. All other parameters must match. + show_deleted (bool): + If true, returns deleted (but unexpired) + resources along with active ones. + """ + + parent: str = proto.Field( + proto.STRING, + number=1, + ) + page_size: int = proto.Field( + proto.INT32, + number=2, + ) + page_token: str = proto.Field( + proto.STRING, + number=3, + ) + show_deleted: bool = proto.Field( + proto.BOOL, + number=4, + ) + + +class ListExecutionsResponse(proto.Message): + r"""Response message containing a list of Executions. + + Attributes: + executions (MutableSequence[google.cloud.run_v2.types.Execution]): + The resulting list of Executions. + next_page_token (str): + A token indicating there are more items than page_size. Use + it in the next ListExecutions request to continue. + """ + + @property + def raw_page(self): + return self + + executions: MutableSequence["Execution"] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Execution", + ) + next_page_token: str = proto.Field( + proto.STRING, + number=2, + ) + + +class DeleteExecutionRequest(proto.Message): + r"""Request message for deleting an Execution. + + Attributes: + name (str): + Required. The name of the Execution to + delete. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}, + where {project} can be project id or number. + validate_only (bool): + Indicates that the request should be + validated without actually deleting any + resources. + etag (str): + A system-generated fingerprint for this + version of the resource. This may be used to + detect modification conflict during updates. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + validate_only: bool = proto.Field( + proto.BOOL, + number=2, + ) + etag: str = proto.Field( + proto.STRING, + number=3, + ) + + +class Execution(proto.Message): + r"""Execution represents the configuration of a single execution. + A execution an immutable resource that references a container + image which is run to completion. + + Attributes: + name (str): + Output only. The unique name of this + Execution. + uid (str): + Output only. Server assigned unique + identifier for the Execution. The value is a + UUID4 string and guaranteed to remain unchanged + until the resource is deleted. + generation (int): + Output only. A number that monotonically + increases every time the user modifies the + desired state. + labels (MutableMapping[str, str]): + KRM-style labels for the resource. + User-provided labels are shared with Google's + billing system, so they can be used to filter, + or break down billing charges by team, + component, environment, state, etc. For more + information, visit + https://cloud.google.com/resource-manager/docs/creating-managing-labels + or + https://cloud.google.com/run/docs/configuring/labels + Cloud Run will populate some labels with + 'run.googleapis.com' or 'serving.knative.dev' + namespaces. Those labels are read-only, and user + changes will not be preserved. + annotations (MutableMapping[str, str]): + KRM-style annotations for the resource. + create_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. Represents time when the + execution was acknowledged by the execution + controller. It is not guaranteed to be set in + happens-before order across separate operations. + start_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. Represents time when the + execution started to run. It is not guaranteed + to be set in happens-before order across + separate operations. + completion_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. Represents time when the + execution was completed. It is not guaranteed to + be set in happens-before order across separate + operations. + update_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The last-modified time. + delete_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. For a deleted resource, the + deletion time. It is only populated as a + response to a Delete request. + expire_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. For a deleted resource, the time + after which it will be permamently deleted. It + is only populated as a response to a Delete + request. + launch_stage (google.api.launch_stage_pb2.LaunchStage): + Set the launch stage to a preview stage on write to allow + use of preview features in that stage. On read, describes + whether the resource uses preview features. Launch Stages + are defined at `Google Cloud Platform Launch + Stages `__. + job (str): + Output only. The name of the parent Job. + parallelism (int): + Output only. Specifies the maximum desired number of tasks + the execution should run at any given time. Must be <= + task_count. The actual number of tasks running in steady + state will be less than this number when ((.spec.task_count + - .status.successful) < .spec.parallelism), i.e. when the + work left to do is less than max parallelism. More info: + https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + task_count (int): + Output only. Specifies the desired number of + tasks the execution should run. Setting to 1 + means that parallelism is limited to 1 and the + success of that task signals the success of the + execution. More info: + https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + template (google.cloud.run_v2.types.TaskTemplate): + Output only. The template used to create + tasks for this execution. + reconciling (bool): + Output only. Indicates whether the resource's reconciliation + is still in progress. See comments in ``Job.reconciling`` + for additional information on reconciliation process in + Cloud Run. + conditions (MutableSequence[google.cloud.run_v2.types.Condition]): + Output only. The Condition of this Execution, + containing its readiness status, and detailed + error information in case it did not reach the + desired state. + observed_generation (int): + Output only. The generation of this Execution. See comments + in ``reconciling`` for additional information on + reconciliation process in Cloud Run. + running_count (int): + Output only. The number of actively running + tasks. + succeeded_count (int): + Output only. The number of tasks which + reached phase Succeeded. + failed_count (int): + Output only. The number of tasks which + reached phase Failed. + etag (str): + Output only. A system-generated fingerprint + for this version of the resource. May be used to + detect modification conflict during updates. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + uid: str = proto.Field( + proto.STRING, + number=2, + ) + generation: int = proto.Field( + proto.INT64, + number=3, + ) + labels: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=4, + ) + annotations: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=5, + ) + create_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=6, + message=timestamp_pb2.Timestamp, + ) + start_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=22, + message=timestamp_pb2.Timestamp, + ) + completion_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=7, + message=timestamp_pb2.Timestamp, + ) + update_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=8, + message=timestamp_pb2.Timestamp, + ) + delete_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=9, + message=timestamp_pb2.Timestamp, + ) + expire_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=10, + message=timestamp_pb2.Timestamp, + ) + launch_stage: launch_stage_pb2.LaunchStage = proto.Field( + proto.ENUM, + number=11, + enum=launch_stage_pb2.LaunchStage, + ) + job: str = proto.Field( + proto.STRING, + number=12, + ) + parallelism: int = proto.Field( + proto.INT32, + number=13, + ) + task_count: int = proto.Field( + proto.INT32, + number=14, + ) + template: task_template.TaskTemplate = proto.Field( + proto.MESSAGE, + number=15, + message=task_template.TaskTemplate, + ) + reconciling: bool = proto.Field( + proto.BOOL, + number=16, + ) + conditions: MutableSequence[condition.Condition] = proto.RepeatedField( + proto.MESSAGE, + number=17, + message=condition.Condition, + ) + observed_generation: int = proto.Field( + proto.INT64, + number=18, + ) + running_count: int = proto.Field( + proto.INT32, + number=19, + ) + succeeded_count: int = proto.Field( + proto.INT32, + number=20, + ) + failed_count: int = proto.Field( + proto.INT32, + number=21, + ) + etag: str = proto.Field( + proto.STRING, + number=99, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/run_v2/types/execution_template.py b/google/cloud/run_v2/types/execution_template.py new file mode 100644 index 0000000..83fd896 --- /dev/null +++ b/google/cloud/run_v2/types/execution_template.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import MutableMapping, MutableSequence + +import proto # type: ignore + +from google.cloud.run_v2.types import task_template + +__protobuf__ = proto.module( + package="google.cloud.run.v2", + manifest={ + "ExecutionTemplate", + }, +) + + +class ExecutionTemplate(proto.Message): + r"""ExecutionTemplate describes the data an execution should have + when created from a template. + + Attributes: + labels (MutableMapping[str, str]): + KRM-style labels for the resource. + annotations (MutableMapping[str, str]): + KRM-style annotations for the resource. + parallelism (int): + Specifies the maximum desired number of tasks the execution + should run at given time. Must be <= task_count. When the + job is run, if this field is 0 or unset, the maximum + possible value will be used for that execution. The actual + number of tasks running in steady state will be less than + this number when there are fewer tasks waiting to be + completed remaining, i.e. when the work left to do is less + than max parallelism. + task_count (int): + Specifies the desired number of tasks the + execution should run. Setting to 1 means that + parallelism is limited to 1 and the success of + that task signals the success of the execution. + More info: + https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + template (google.cloud.run_v2.types.TaskTemplate): + Required. Describes the task(s) that will be + created when executing an execution. + """ + + labels: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=1, + ) + annotations: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=2, + ) + parallelism: int = proto.Field( + proto.INT32, + number=3, + ) + task_count: int = proto.Field( + proto.INT32, + number=4, + ) + template: task_template.TaskTemplate = proto.Field( + proto.MESSAGE, + number=5, + message=task_template.TaskTemplate, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/run_v2/types/job.py b/google/cloud/run_v2/types/job.py new file mode 100644 index 0000000..0ea268b --- /dev/null +++ b/google/cloud/run_v2/types/job.py @@ -0,0 +1,524 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import MutableMapping, MutableSequence + +from google.api import launch_stage_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore + +from google.cloud.run_v2.types import condition, execution_template, vendor_settings + +__protobuf__ = proto.module( + package="google.cloud.run.v2", + manifest={ + "CreateJobRequest", + "GetJobRequest", + "UpdateJobRequest", + "ListJobsRequest", + "ListJobsResponse", + "DeleteJobRequest", + "RunJobRequest", + "Job", + "ExecutionReference", + }, +) + + +class CreateJobRequest(proto.Message): + r"""Request message for creating a Job. + + Attributes: + parent (str): + Required. The location and project in which + this Job should be created. Format: + projects/{project}/locations/{location}, where + {project} can be project id or number. + job (google.cloud.run_v2.types.Job): + Required. The Job instance to create. + job_id (str): + Required. The unique identifier for the Job. The name of the + job becomes {parent}/jobs/{job_id}. + validate_only (bool): + Indicates that the request should be + validated and default values populated, without + persisting the request or creating any + resources. + """ + + parent: str = proto.Field( + proto.STRING, + number=1, + ) + job: "Job" = proto.Field( + proto.MESSAGE, + number=2, + message="Job", + ) + job_id: str = proto.Field( + proto.STRING, + number=3, + ) + validate_only: bool = proto.Field( + proto.BOOL, + number=4, + ) + + +class GetJobRequest(proto.Message): + r"""Request message for obtaining a Job by its full name. + + Attributes: + name (str): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or number. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + + +class UpdateJobRequest(proto.Message): + r"""Request message for updating a Job. + + Attributes: + job (google.cloud.run_v2.types.Job): + Required. The Job to be updated. + validate_only (bool): + Indicates that the request should be + validated and default values populated, without + persisting the request or updating any + resources. + allow_missing (bool): + If set to true, and if the Job does not + exist, it will create a new one. Caller must + have both create and update permissions for this + call if this is set to true. + """ + + job: "Job" = proto.Field( + proto.MESSAGE, + number=1, + message="Job", + ) + validate_only: bool = proto.Field( + proto.BOOL, + number=3, + ) + allow_missing: bool = proto.Field( + proto.BOOL, + number=4, + ) + + +class ListJobsRequest(proto.Message): + r"""Request message for retrieving a list of Jobs. + + Attributes: + parent (str): + Required. The location and project to list + resources on. Format: + projects/{project}/locations/{location}, where + {project} can be project id or number. + page_size (int): + Maximum number of Jobs to return in this + call. + page_token (str): + A page token received from a previous call to + ListJobs. All other parameters must match. + show_deleted (bool): + If true, returns deleted (but unexpired) + resources along with active ones. + """ + + parent: str = proto.Field( + proto.STRING, + number=1, + ) + page_size: int = proto.Field( + proto.INT32, + number=2, + ) + page_token: str = proto.Field( + proto.STRING, + number=3, + ) + show_deleted: bool = proto.Field( + proto.BOOL, + number=4, + ) + + +class ListJobsResponse(proto.Message): + r"""Response message containing a list of Jobs. + + Attributes: + jobs (MutableSequence[google.cloud.run_v2.types.Job]): + The resulting list of Jobs. + next_page_token (str): + A token indicating there are more items than page_size. Use + it in the next ListJobs request to continue. + """ + + @property + def raw_page(self): + return self + + jobs: MutableSequence["Job"] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Job", + ) + next_page_token: str = proto.Field( + proto.STRING, + number=2, + ) + + +class DeleteJobRequest(proto.Message): + r"""Request message to delete a Job by its full name. + + Attributes: + name (str): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or number. + validate_only (bool): + Indicates that the request should be + validated without actually deleting any + resources. + etag (str): + A system-generated fingerprint for this + version of the resource. May be used to detect + modification conflict during updates. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + validate_only: bool = proto.Field( + proto.BOOL, + number=3, + ) + etag: str = proto.Field( + proto.STRING, + number=4, + ) + + +class RunJobRequest(proto.Message): + r"""Request message to create a new Execution of a Job. + + Attributes: + name (str): + Required. The full name of the Job. + Format: + projects/{project}/locations/{location}/jobs/{job}, + where {project} can be project id or number. + validate_only (bool): + Indicates that the request should be + validated without actually deleting any + resources. + etag (str): + A system-generated fingerprint for this + version of the resource. May be used to detect + modification conflict during updates. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + validate_only: bool = proto.Field( + proto.BOOL, + number=2, + ) + etag: str = proto.Field( + proto.STRING, + number=3, + ) + + +class Job(proto.Message): + r"""Job represents the configuration of a single job. A job an + immutable resource that references a container image which is + run to completion. + + Attributes: + name (str): + The fully qualified name of this Job. + Format: + projects/{project}/locations/{location}/jobs/{job} + uid (str): + Output only. Server assigned unique + identifier for the Execution. The value is a + UUID4 string and guaranteed to remain unchanged + until the resource is deleted. + generation (int): + Output only. A number that monotonically + increases every time the user modifies the + desired state. + labels (MutableMapping[str, str]): + KRM-style labels for the resource. + User-provided labels are shared with Google's + billing system, so they can be used to filter, + or break down billing charges by team, + component, environment, state, etc. For more + information, visit + https://cloud.google.com/resource-manager/docs/creating-managing-labels + or + https://cloud.google.com/run/docs/configuring/labels + Cloud Run will populate some labels with + 'run.googleapis.com' or 'serving.knative.dev' + namespaces. Those labels are read-only, and user + changes will not be preserved. + annotations (MutableMapping[str, str]): + KRM-style annotations for the resource. + Unstructured key value map that may be set by + external tools to store and arbitrary metadata. + They are not queryable and should be preserved + when modifying objects. Cloud Run will populate + some annotations using 'run.googleapis.com' or + 'serving.knative.dev' namespaces. This field + follows Kubernetes annotations' namespacing, + limits, and rules. More info: + https://kubernetes.io/docs/user-guide/annotations + create_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The creation time. + update_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The last-modified time. + delete_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The deletion time. + expire_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. For a deleted resource, the time + after which it will be permamently deleted. + creator (str): + Output only. Email address of the + authenticated creator. + last_modifier (str): + Output only. Email address of the last + authenticated modifier. + client (str): + Arbitrary identifier for the API client. + client_version (str): + Arbitrary version identifier for the API + client. + launch_stage (google.api.launch_stage_pb2.LaunchStage): + The launch stage as defined by `Google Cloud Platform Launch + Stages `__. + Cloud Run supports ``ALPHA``, ``BETA``, and ``GA``. If no + value is specified, GA is assumed. + binary_authorization (google.cloud.run_v2.types.BinaryAuthorization): + Settings for the Binary Authorization + feature. + template (google.cloud.run_v2.types.ExecutionTemplate): + Required. The template used to create + executions for this Job. + observed_generation (int): + Output only. The generation of this Job. See comments in + ``reconciling`` for additional information on reconciliation + process in Cloud Run. + terminal_condition (google.cloud.run_v2.types.Condition): + Output only. The Condition of this Job, + containing its readiness status, and detailed + error information in case it did not reach the + desired state. + conditions (MutableSequence[google.cloud.run_v2.types.Condition]): + Output only. The Conditions of all other associated + sub-resources. They contain additional diagnostics + information in case the Job does not reach its desired + state. See comments in ``reconciling`` for additional + information on reconciliation process in Cloud Run. + execution_count (int): + Output only. Number of executions created for + this job. + latest_created_execution (google.cloud.run_v2.types.ExecutionReference): + Output only. Name of the last created + execution. + reconciling (bool): + Output only. Returns true if the Job is currently being + acted upon by the system to bring it into the desired state. + + When a new Job is created, or an existing one is updated, + Cloud Run will asynchronously perform all necessary steps to + bring the Job to the desired state. This process is called + reconciliation. While reconciliation is in process, + ``observed_generation`` and ``latest_succeeded_execution``, + will have transient values that might mismatch the intended + state: Once reconciliation is over (and this field is + false), there are two possible outcomes: reconciliation + succeeded and the state matches the Job, or there was an + error, and reconciliation failed. This state can be found in + ``terminal_condition.state``. + + If reconciliation succeeded, the following fields will + match: ``observed_generation`` and ``generation``, + ``latest_succeeded_execution`` and + ``latest_created_execution``. + + If reconciliation failed, ``observed_generation`` and + ``latest_succeeded_execution`` will have the state of the + last succeeded execution or empty for newly created Job. + Additional information on the failure can be found in + ``terminal_condition`` and ``conditions``. + etag (str): + Output only. A system-generated fingerprint + for this version of the resource. May be used to + detect modification conflict during updates. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + uid: str = proto.Field( + proto.STRING, + number=2, + ) + generation: int = proto.Field( + proto.INT64, + number=3, + ) + labels: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=4, + ) + annotations: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=5, + ) + create_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=6, + message=timestamp_pb2.Timestamp, + ) + update_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=7, + message=timestamp_pb2.Timestamp, + ) + delete_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=8, + message=timestamp_pb2.Timestamp, + ) + expire_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=9, + message=timestamp_pb2.Timestamp, + ) + creator: str = proto.Field( + proto.STRING, + number=10, + ) + last_modifier: str = proto.Field( + proto.STRING, + number=11, + ) + client: str = proto.Field( + proto.STRING, + number=12, + ) + client_version: str = proto.Field( + proto.STRING, + number=13, + ) + launch_stage: launch_stage_pb2.LaunchStage = proto.Field( + proto.ENUM, + number=14, + enum=launch_stage_pb2.LaunchStage, + ) + binary_authorization: vendor_settings.BinaryAuthorization = proto.Field( + proto.MESSAGE, + number=15, + message=vendor_settings.BinaryAuthorization, + ) + template: execution_template.ExecutionTemplate = proto.Field( + proto.MESSAGE, + number=16, + message=execution_template.ExecutionTemplate, + ) + observed_generation: int = proto.Field( + proto.INT64, + number=17, + ) + terminal_condition: condition.Condition = proto.Field( + proto.MESSAGE, + number=18, + message=condition.Condition, + ) + conditions: MutableSequence[condition.Condition] = proto.RepeatedField( + proto.MESSAGE, + number=19, + message=condition.Condition, + ) + execution_count: int = proto.Field( + proto.INT32, + number=20, + ) + latest_created_execution: "ExecutionReference" = proto.Field( + proto.MESSAGE, + number=22, + message="ExecutionReference", + ) + reconciling: bool = proto.Field( + proto.BOOL, + number=23, + ) + etag: str = proto.Field( + proto.STRING, + number=99, + ) + + +class ExecutionReference(proto.Message): + r"""Reference to an Execution. Use /Executions.GetExecution with + the given name to get full execution including the latest + status. + + Attributes: + name (str): + Name of the execution. + create_time (google.protobuf.timestamp_pb2.Timestamp): + Creation timestamp of the execution. + completion_time (google.protobuf.timestamp_pb2.Timestamp): + Creation timestamp of the execution. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + create_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=2, + message=timestamp_pb2.Timestamp, + ) + completion_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=3, + message=timestamp_pb2.Timestamp, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/run_v2/types/k8s_min.py b/google/cloud/run_v2/types/k8s_min.py index 966361f..43ed90c 100644 --- a/google/cloud/run_v2/types/k8s_min.py +++ b/google/cloud/run_v2/types/k8s_min.py @@ -13,8 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence +import proto # type: ignore __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -30,6 +31,11 @@ "SecretVolumeSource", "VersionToPath", "CloudSqlInstance", + "Probe", + "HTTPGetAction", + "HTTPHeader", + "TCPSocketAction", + "GRPCAction", }, ) @@ -49,7 +55,7 @@ class Container(proto.Message): Google Container Registry or Google Artifact Registry. More info: https://kubernetes.io/docs/concepts/containers/images - command (Sequence[str]): + command (MutableSequence[str]): Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's @@ -59,7 +65,7 @@ class Container(proto.Message): Escaped references will never be expanded, regardless of whether the variable exists or not. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - args (Sequence[str]): + args (MutableSequence[str]): Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable @@ -69,14 +75,14 @@ class Container(proto.Message): be expanded, regardless of whether the variable exists or not. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - env (Sequence[google.cloud.run_v2.types.EnvVar]): + env (MutableSequence[google.cloud.run_v2.types.EnvVar]): List of environment variables to set in the container. resources (google.cloud.run_v2.types.ResourceRequirements): Compute Resource requirements by this container. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - ports (Sequence[google.cloud.run_v2.types.ContainerPort]): + ports (MutableSequence[google.cloud.run_v2.types.ContainerPort]): List of ports to expose from the container. Only a single port can be specified. The specified ports must be listening on all @@ -86,47 +92,79 @@ class Container(proto.Message): passed to the container through the PORT environment variable for the container to listen on. - volume_mounts (Sequence[google.cloud.run_v2.types.VolumeMount]): + volume_mounts (MutableSequence[google.cloud.run_v2.types.VolumeMount]): Volume to mount into the container's filesystem. + working_dir (str): + Container's working directory. + If not specified, the container runtime's + default will be used, which might be configured + in the container image. + liveness_probe (google.cloud.run_v2.types.Probe): + Periodic probe of container liveness. + Container will be restarted if the probe fails. + More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + startup_probe (google.cloud.run_v2.types.Probe): + Startup probe of application within the + container. All other probes are disabled if a + startup probe is provided, until it succeeds. + Container will not be added to service endpoints + if the probe fails. + More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - image = proto.Field( + image: str = proto.Field( proto.STRING, number=2, ) - command = proto.RepeatedField( + command: MutableSequence[str] = proto.RepeatedField( proto.STRING, number=3, ) - args = proto.RepeatedField( + args: MutableSequence[str] = proto.RepeatedField( proto.STRING, number=4, ) - env = proto.RepeatedField( + env: MutableSequence["EnvVar"] = proto.RepeatedField( proto.MESSAGE, number=5, message="EnvVar", ) - resources = proto.Field( + resources: "ResourceRequirements" = proto.Field( proto.MESSAGE, number=6, message="ResourceRequirements", ) - ports = proto.RepeatedField( + ports: MutableSequence["ContainerPort"] = proto.RepeatedField( proto.MESSAGE, number=7, message="ContainerPort", ) - volume_mounts = proto.RepeatedField( + volume_mounts: MutableSequence["VolumeMount"] = proto.RepeatedField( proto.MESSAGE, number=8, message="VolumeMount", ) + working_dir: str = proto.Field( + proto.STRING, + number=9, + ) + liveness_probe: "Probe" = proto.Field( + proto.MESSAGE, + number=10, + message="Probe", + ) + startup_probe: "Probe" = proto.Field( + proto.MESSAGE, + number=11, + message="Probe", + ) class ResourceRequirements(proto.Message): @@ -134,25 +172,24 @@ class ResourceRequirements(proto.Message): requirements. Attributes: - limits (Mapping[str, str]): + limits (MutableMapping[str, str]): Only memory and CPU are supported. Note: The - only supported values for CPU are '1', '2', and - '4'. Setting 4 CPU requires at least 2Gi of - memory. - The values of the map is string form of the - 'quantity' k8s type: + only supported values for CPU are '1', '2', + '4', and '8'. Setting 4 CPU requires at least + 2Gi of memory. The values of the map is string + form of the 'quantity' k8s type: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go cpu_idle (bool): Determines whether CPU should be throttled or not outside of requests. """ - limits = proto.MapField( + limits: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=1, ) - cpu_idle = proto.Field( + cpu_idle: bool = proto.Field( proto.BOOL, number=2, ) @@ -190,16 +227,16 @@ class EnvVar(proto.Message): This field is a member of `oneof`_ ``values``. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - value = proto.Field( + value: str = proto.Field( proto.STRING, number=2, oneof="values", ) - value_source = proto.Field( + value_source: "EnvVarSource" = proto.Field( proto.MESSAGE, number=3, oneof="values", @@ -216,7 +253,7 @@ class EnvVarSource(proto.Message): Cloud Secret Manager. """ - secret_key_ref = proto.Field( + secret_key_ref: "SecretKeySelector" = proto.Field( proto.MESSAGE, number=1, message="SecretKeySelector", @@ -235,15 +272,16 @@ class SecretKeySelector(proto.Message): a different project. version (str): The Cloud Secret Manager secret version. - Can be 'latest' for the latest value or an - integer for a specific version. + Can be 'latest' for the latest version, an + integer for a specific version, or a version + alias. """ - secret = proto.Field( + secret: str = proto.Field( proto.STRING, number=1, ) - version = proto.Field( + version: str = proto.Field( proto.STRING, number=2, ) @@ -262,11 +300,11 @@ class ContainerPort(proto.Message): TCP port number, 0 < container_port < 65536. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - container_port = proto.Field( + container_port: int = proto.Field( proto.INT32, number=3, ) @@ -290,11 +328,11 @@ class VolumeMount(proto.Message): https://cloud.google.com/sql/docs/mysql/connect-run """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - mount_path = proto.Field( + mount_path: str = proto.Field( proto.STRING, number=3, ) @@ -329,17 +367,17 @@ class Volume(proto.Message): This field is a member of `oneof`_ ``volume_type``. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - secret = proto.Field( + secret: "SecretVolumeSource" = proto.Field( proto.MESSAGE, number=2, oneof="volume_type", message="SecretVolumeSource", ) - cloud_sql_instance = proto.Field( + cloud_sql_instance: "CloudSqlInstance" = proto.Field( proto.MESSAGE, number=3, oneof="volume_type", @@ -359,7 +397,7 @@ class SecretVolumeSource(proto.Message): is in the same project. projects/{project}/secrets/{secret} if the secret is in a different project. - items (Sequence[google.cloud.run_v2.types.VersionToPath]): + items (MutableSequence[google.cloud.run_v2.types.VersionToPath]): If unspecified, the volume will expose a file whose name is the secret, relative to VolumeMount.mount_path. If specified, the key will be used as the version to fetch from @@ -369,7 +407,7 @@ class SecretVolumeSource(proto.Message): default_mode (int): Integer representation of mode bits to use on created files by default. Must be a value between 0000 and 0777 (octal), - defaulting to 0644. Directories within the path are not + defaulting to 0444. Directories within the path are not affected by this setting. Notes @@ -392,16 +430,16 @@ class SecretVolumeSource(proto.Message): could be set. """ - secret = proto.Field( + secret: str = proto.Field( proto.STRING, number=1, ) - items = proto.RepeatedField( + items: MutableSequence["VersionToPath"] = proto.RepeatedField( proto.MESSAGE, number=2, message="VersionToPath", ) - default_mode = proto.Field( + default_mode: int = proto.Field( proto.INT32, number=3, ) @@ -417,8 +455,9 @@ class VersionToPath(proto.Message): the container. version (str): The Cloud Secret Manager secret version. - Can be 'latest' for the latest value or an - integer for a specific version. + Can be 'latest' for the latest value, or an + integer or a secret alias for a specific + version. mode (int): Integer octal mode bits to use on this file, must be a value between 01 and 0777 (octal). If 0 or not set, the Volume's @@ -440,15 +479,15 @@ class VersionToPath(proto.Message): mode bits set. """ - path = proto.Field( + path: str = proto.Field( proto.STRING, number=1, ) - version = proto.Field( + version: str = proto.Field( proto.STRING, number=2, ) - mode = proto.Field( + mode: int = proto.Field( proto.INT32, number=3, ) @@ -458,7 +497,7 @@ class CloudSqlInstance(proto.Message): r"""Represents a specific Cloud SQL instance. Attributes: - instances (Sequence[str]): + instances (MutableSequence[str]): The Cloud SQL instance connection names, as can be found in https://console.cloud.google.com/sql/instances. @@ -469,10 +508,187 @@ class CloudSqlInstance(proto.Message): {project}:{location}:{instance} """ - instances = proto.RepeatedField( + instances: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=1, + ) + + +class Probe(proto.Message): + r"""Probe describes a health check to be performed against a + container to determine whether it is alive or ready to receive + traffic. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + initial_delay_seconds (int): + Number of seconds after the container has + started before the probe is initiated. + Defaults to 0 seconds. Minimum value is 0. + Maximum value for liveness probe is 3600. + Maximum value for startup probe is 240. More + info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + timeout_seconds (int): + Number of seconds after which the probe times out. Defaults + to 1 second. Minimum value is 1. Maximum value is 3600. Must + be smaller than period_seconds. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + period_seconds (int): + How often (in seconds) to perform the probe. Default to 10 + seconds. Minimum value is 1. Maximum value for liveness + probe is 3600. Maximum value for startup probe is 240. Must + be greater or equal than timeout_seconds. + failure_threshold (int): + Minimum consecutive failures for the probe to + be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + http_get (google.cloud.run_v2.types.HTTPGetAction): + HTTPGet specifies the http request to + perform. Exactly one of httpGet, tcpSocket, or + grpc must be specified. + + This field is a member of `oneof`_ ``probe_type``. + tcp_socket (google.cloud.run_v2.types.TCPSocketAction): + TCPSocket specifies an action involving a TCP + port. Exactly one of httpGet, tcpSocket, or grpc + must be specified. + + This field is a member of `oneof`_ ``probe_type``. + grpc (google.cloud.run_v2.types.GRPCAction): + GRPC specifies an action involving a gRPC + port. Exactly one of httpGet, tcpSocket, or grpc + must be specified. + + This field is a member of `oneof`_ ``probe_type``. + """ + + initial_delay_seconds: int = proto.Field( + proto.INT32, + number=1, + ) + timeout_seconds: int = proto.Field( + proto.INT32, + number=2, + ) + period_seconds: int = proto.Field( + proto.INT32, + number=3, + ) + failure_threshold: int = proto.Field( + proto.INT32, + number=4, + ) + http_get: "HTTPGetAction" = proto.Field( + proto.MESSAGE, + number=5, + oneof="probe_type", + message="HTTPGetAction", + ) + tcp_socket: "TCPSocketAction" = proto.Field( + proto.MESSAGE, + number=6, + oneof="probe_type", + message="TCPSocketAction", + ) + grpc: "GRPCAction" = proto.Field( + proto.MESSAGE, + number=7, + oneof="probe_type", + message="GRPCAction", + ) + + +class HTTPGetAction(proto.Message): + r"""HTTPGetAction describes an action based on HTTP Get requests. + + Attributes: + path (str): + Path to access on the HTTP server. Defaults + to '/'. + http_headers (MutableSequence[google.cloud.run_v2.types.HTTPHeader]): + Custom headers to set in the request. HTTP + allows repeated headers. + """ + + path: str = proto.Field( proto.STRING, number=1, ) + http_headers: MutableSequence["HTTPHeader"] = proto.RepeatedField( + proto.MESSAGE, + number=4, + message="HTTPHeader", + ) + + +class HTTPHeader(proto.Message): + r"""HTTPHeader describes a custom header to be used in HTTP + probes + + Attributes: + name (str): + Required. The header field name + value (str): + The header field value + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + value: str = proto.Field( + proto.STRING, + number=2, + ) + + +class TCPSocketAction(proto.Message): + r"""TCPSocketAction describes an action based on opening a socket + + Attributes: + port (int): + Port number to access on the container. Must + be in the range 1 to 65535. If not specified, + defaults to 8080. + """ + + port: int = proto.Field( + proto.INT32, + number=1, + ) + + +class GRPCAction(proto.Message): + r"""GRPCAction describes an action involving a GRPC port. + + Attributes: + port (int): + Port number of the gRPC service. Number must + be in the range 1 to 65535. If not specified, + defaults to 8080. + service (str): + Service is the name of the service to place + in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + If this is not specified, the default behavior + is defined by gRPC. + """ + + port: int = proto.Field( + proto.INT32, + number=1, + ) + service: str = proto.Field( + proto.STRING, + number=2, + ) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/run_v2/types/revision.py b/google/cloud/run_v2/types/revision.py index e4ea93e..64ad2b7 100644 --- a/google/cloud/run_v2/types/revision.py +++ b/google/cloud/run_v2/types/revision.py @@ -13,15 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence from google.api import launch_stage_pb2 # type: ignore -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import k8s_min -from google.cloud.run_v2.types import vendor_settings from google.protobuf import duration_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore +from google.cloud.run_v2.types import condition, k8s_min, vendor_settings __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -45,7 +44,7 @@ class GetRevisionRequest(proto.Message): projects/{project}/locations/{location}/services/{service}/revisions/{revision} """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) @@ -72,19 +71,19 @@ class ListRevisionsRequest(proto.Message): resources along with active ones. """ - parent = proto.Field( + parent: str = proto.Field( proto.STRING, number=1, ) - page_size = proto.Field( + page_size: int = proto.Field( proto.INT32, number=2, ) - page_token = proto.Field( + page_token: str = proto.Field( proto.STRING, number=3, ) - show_deleted = proto.Field( + show_deleted: bool = proto.Field( proto.BOOL, number=4, ) @@ -94,7 +93,7 @@ class ListRevisionsResponse(proto.Message): r"""Response message containing a list of Revisions. Attributes: - revisions (Sequence[google.cloud.run_v2.types.Revision]): + revisions (MutableSequence[google.cloud.run_v2.types.Revision]): The resulting list of Revisions. next_page_token (str): A token indicating there are more items than page_size. Use @@ -105,12 +104,12 @@ class ListRevisionsResponse(proto.Message): def raw_page(self): return self - revisions = proto.RepeatedField( + revisions: MutableSequence["Revision"] = proto.RepeatedField( proto.MESSAGE, number=1, message="Revision", ) - next_page_token = proto.Field( + next_page_token: str = proto.Field( proto.STRING, number=2, ) @@ -137,15 +136,15 @@ class DeleteRevisionRequest(proto.Message): detect modification conflict during updates. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - validate_only = proto.Field( + validate_only: bool = proto.Field( proto.BOOL, number=2, ) - etag = proto.Field( + etag: str = proto.Field( proto.STRING, number=3, ) @@ -169,7 +168,7 @@ class Revision(proto.Message): Output only. A number that monotonically increases every time the user modifies the desired state. - labels (Mapping[str, str]): + labels (MutableMapping[str, str]): KRM-style labels for the resource. User-provided labels are shared with Google's billing system, so they can be used to filter, @@ -183,7 +182,7 @@ class Revision(proto.Message): 'run.googleapis.com' or 'serving.knative.dev' namespaces. Those labels are read-only, and user changes will not be preserved. - annotations (Mapping[str, str]): + annotations (MutableMapping[str, str]): KRM-style annotations for the resource. create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The creation time. @@ -224,10 +223,10 @@ class Revision(proto.Message): service account represents the identity of the running revision, and determines what permissions the revision has. - containers (Sequence[google.cloud.run_v2.types.Container]): + containers (MutableSequence[google.cloud.run_v2.types.Container]): Holds the single container that defines the unit of execution for this Revision. - volumes (Sequence[google.cloud.run_v2.types.Volume]): + volumes (MutableSequence[google.cloud.run_v2.types.Volume]): A list of Volumes to make available to containers. execution_environment (google.cloud.run_v2.types.ExecutionEnvironment): @@ -243,7 +242,7 @@ class Revision(proto.Message): is still in progress. See comments in ``Service.reconciling`` for additional information on reconciliation process in Cloud Run. - conditions (Sequence[google.cloud.run_v2.types.Condition]): + conditions (MutableSequence[google.cloud.run_v2.types.Condition]): Output only. The Condition of this Revision, containing its readiness status, and detailed error information in case it did not reach a @@ -262,117 +261,117 @@ class Revision(proto.Message): detect modification conflict during updates. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - uid = proto.Field( + uid: str = proto.Field( proto.STRING, number=2, ) - generation = proto.Field( + generation: int = proto.Field( proto.INT64, number=3, ) - labels = proto.MapField( + labels: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=4, ) - annotations = proto.MapField( + annotations: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=5, ) - create_time = proto.Field( + create_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=6, message=timestamp_pb2.Timestamp, ) - update_time = proto.Field( + update_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=7, message=timestamp_pb2.Timestamp, ) - delete_time = proto.Field( + delete_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=8, message=timestamp_pb2.Timestamp, ) - expire_time = proto.Field( + expire_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=9, message=timestamp_pb2.Timestamp, ) - launch_stage = proto.Field( + launch_stage: launch_stage_pb2.LaunchStage = proto.Field( proto.ENUM, number=10, enum=launch_stage_pb2.LaunchStage, ) - service = proto.Field( + service: str = proto.Field( proto.STRING, number=11, ) - scaling = proto.Field( + scaling: vendor_settings.RevisionScaling = proto.Field( proto.MESSAGE, number=12, message=vendor_settings.RevisionScaling, ) - vpc_access = proto.Field( + vpc_access: vendor_settings.VpcAccess = proto.Field( proto.MESSAGE, number=13, message=vendor_settings.VpcAccess, ) - max_instance_request_concurrency = proto.Field( + max_instance_request_concurrency: int = proto.Field( proto.INT32, number=34, ) - timeout = proto.Field( + timeout: duration_pb2.Duration = proto.Field( proto.MESSAGE, number=15, message=duration_pb2.Duration, ) - service_account = proto.Field( + service_account: str = proto.Field( proto.STRING, number=16, ) - containers = proto.RepeatedField( + containers: MutableSequence[k8s_min.Container] = proto.RepeatedField( proto.MESSAGE, number=17, message=k8s_min.Container, ) - volumes = proto.RepeatedField( + volumes: MutableSequence[k8s_min.Volume] = proto.RepeatedField( proto.MESSAGE, number=18, message=k8s_min.Volume, ) - execution_environment = proto.Field( + execution_environment: vendor_settings.ExecutionEnvironment = proto.Field( proto.ENUM, number=20, enum=vendor_settings.ExecutionEnvironment, ) - encryption_key = proto.Field( + encryption_key: str = proto.Field( proto.STRING, number=21, ) - reconciling = proto.Field( + reconciling: bool = proto.Field( proto.BOOL, number=30, ) - conditions = proto.RepeatedField( + conditions: MutableSequence[condition.Condition] = proto.RepeatedField( proto.MESSAGE, number=31, message=condition.Condition, ) - observed_generation = proto.Field( + observed_generation: int = proto.Field( proto.INT64, number=32, ) - log_uri = proto.Field( + log_uri: str = proto.Field( proto.STRING, number=33, ) - etag = proto.Field( + etag: str = proto.Field( proto.STRING, number=99, ) diff --git a/google/cloud/run_v2/types/revision_template.py b/google/cloud/run_v2/types/revision_template.py index 2245f8f..e939e52 100644 --- a/google/cloud/run_v2/types/revision_template.py +++ b/google/cloud/run_v2/types/revision_template.py @@ -13,12 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence -from google.cloud.run_v2.types import k8s_min -from google.cloud.run_v2.types import vendor_settings from google.protobuf import duration_pb2 # type: ignore +import proto # type: ignore +from google.cloud.run_v2.types import k8s_min, vendor_settings __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -37,9 +37,9 @@ class RevisionTemplate(proto.Message): The unique name for the revision. If this field is omitted, it will be automatically generated based on the Service name. - labels (Mapping[str, str]): + labels (MutableMapping[str, str]): KRM-style labels for the resource. - annotations (Mapping[str, str]): + annotations (MutableMapping[str, str]): KRM-style annotations for the resource. scaling (google.cloud.run_v2.types.RevisionScaling): Scaling settings for this Revision. @@ -58,10 +58,10 @@ class RevisionTemplate(proto.Message): permissions the revision has. If not provided, the revision will use the project's default service account. - containers (Sequence[google.cloud.run_v2.types.Container]): + containers (MutableSequence[google.cloud.run_v2.types.Container]): Holds the single container that defines the unit of execution for this Revision. - volumes (Sequence[google.cloud.run_v2.types.Volume]): + volumes (MutableSequence[google.cloud.run_v2.types.Volume]): A list of Volumes to make available to containers. execution_environment (google.cloud.run_v2.types.ExecutionEnvironment): @@ -77,59 +77,59 @@ class RevisionTemplate(proto.Message): serving instance can receive. """ - revision = proto.Field( + revision: str = proto.Field( proto.STRING, number=1, ) - labels = proto.MapField( + labels: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=2, ) - annotations = proto.MapField( + annotations: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=3, ) - scaling = proto.Field( + scaling: vendor_settings.RevisionScaling = proto.Field( proto.MESSAGE, number=4, message=vendor_settings.RevisionScaling, ) - vpc_access = proto.Field( + vpc_access: vendor_settings.VpcAccess = proto.Field( proto.MESSAGE, number=6, message=vendor_settings.VpcAccess, ) - timeout = proto.Field( + timeout: duration_pb2.Duration = proto.Field( proto.MESSAGE, number=8, message=duration_pb2.Duration, ) - service_account = proto.Field( + service_account: str = proto.Field( proto.STRING, number=9, ) - containers = proto.RepeatedField( + containers: MutableSequence[k8s_min.Container] = proto.RepeatedField( proto.MESSAGE, number=10, message=k8s_min.Container, ) - volumes = proto.RepeatedField( + volumes: MutableSequence[k8s_min.Volume] = proto.RepeatedField( proto.MESSAGE, number=11, message=k8s_min.Volume, ) - execution_environment = proto.Field( + execution_environment: vendor_settings.ExecutionEnvironment = proto.Field( proto.ENUM, number=13, enum=vendor_settings.ExecutionEnvironment, ) - encryption_key = proto.Field( + encryption_key: str = proto.Field( proto.STRING, number=14, ) - max_instance_request_concurrency = proto.Field( + max_instance_request_concurrency: int = proto.Field( proto.INT32, number=15, ) diff --git a/google/cloud/run_v2/types/service.py b/google/cloud/run_v2/types/service.py index 9c993fc..2f0d3e4 100644 --- a/google/cloud/run_v2/types/service.py +++ b/google/cloud/run_v2/types/service.py @@ -13,15 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence from google.api import launch_stage_pb2 # type: ignore -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import revision_template -from google.cloud.run_v2.types import traffic_target -from google.cloud.run_v2.types import vendor_settings from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore +from google.cloud.run_v2.types import ( + condition, + revision_template, + traffic_target, + vendor_settings, +) __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -44,12 +47,16 @@ class CreateServiceRequest(proto.Message): parent (str): Required. The location and project in which this service should be created. Format: - projects/{projectnumber}/locations/{location} + projects/{project}/locations/{location}, where + {project} can be project id or number. Only + lowercase characters, digits, and hyphens. service (google.cloud.run_v2.types.Service): Required. The Service instance to create. service_id (str): - Required. The unique identifier for the Service. The name of - the service becomes {parent}/services/{service_id}. + Required. The unique identifier for the Service. It must + begin with letter, and cannot end with hyphen; must contain + fewer than 50 characters. The name of the service becomes + {parent}/services/{service_id}. validate_only (bool): Indicates that the request should be validated and default values populated, without @@ -57,20 +64,20 @@ class CreateServiceRequest(proto.Message): resources. """ - parent = proto.Field( + parent: str = proto.Field( proto.STRING, number=1, ) - service = proto.Field( + service: "Service" = proto.Field( proto.MESSAGE, number=2, message="Service", ) - service_id = proto.Field( + service_id: str = proto.Field( proto.STRING, number=3, ) - validate_only = proto.Field( + validate_only: bool = proto.Field( proto.BOOL, number=4, ) @@ -94,16 +101,16 @@ class UpdateServiceRequest(proto.Message): call if this is set to true. """ - service = proto.Field( + service: "Service" = proto.Field( proto.MESSAGE, number=1, message="Service", ) - validate_only = proto.Field( + validate_only: bool = proto.Field( proto.BOOL, number=3, ) - allow_missing = proto.Field( + allow_missing: bool = proto.Field( proto.BOOL, number=4, ) @@ -116,8 +123,9 @@ class ListServicesRequest(proto.Message): parent (str): Required. The location and project to list resources on. Location must be a valid GCP - region, and may not be the "-" wildcard. Format: - projects/{projectnumber}/locations/{location} + region, and cannot be the "-" wildcard. Format: + projects/{project}/locations/{location}, where + {project} can be project id or number. page_size (int): Maximum number of Services to return in this call. @@ -129,19 +137,19 @@ class ListServicesRequest(proto.Message): resources along with active ones. """ - parent = proto.Field( + parent: str = proto.Field( proto.STRING, number=1, ) - page_size = proto.Field( + page_size: int = proto.Field( proto.INT32, number=2, ) - page_token = proto.Field( + page_token: str = proto.Field( proto.STRING, number=3, ) - show_deleted = proto.Field( + show_deleted: bool = proto.Field( proto.BOOL, number=4, ) @@ -151,7 +159,7 @@ class ListServicesResponse(proto.Message): r"""Response message containing a list of Services. Attributes: - services (Sequence[google.cloud.run_v2.types.Service]): + services (MutableSequence[google.cloud.run_v2.types.Service]): The resulting list of Services. next_page_token (str): A token indicating there are more items than page_size. Use @@ -162,12 +170,12 @@ class ListServicesResponse(proto.Message): def raw_page(self): return self - services = proto.RepeatedField( + services: MutableSequence["Service"] = proto.RepeatedField( proto.MESSAGE, number=1, message="Service", ) - next_page_token = proto.Field( + next_page_token: str = proto.Field( proto.STRING, number=2, ) @@ -180,10 +188,11 @@ class GetServiceRequest(proto.Message): name (str): Required. The full name of the Service. Format: - projects/{projectnumber}/locations/{location}/services/{service} + projects/{project}/locations/{location}/services/{service}, + where {project} can be project id or number. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) @@ -196,7 +205,8 @@ class DeleteServiceRequest(proto.Message): name (str): Required. The full name of the Service. Format: - projects/{projectnumber}/locations/{location}/services/{service} + projects/{project}/locations/{location}/services/{service}, + where {project} can be project id or number. validate_only (bool): Indicates that the request should be validated without actually deleting any @@ -207,15 +217,15 @@ class DeleteServiceRequest(proto.Message): modification conflict during updates. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - validate_only = proto.Field( + validate_only: bool = proto.Field( proto.BOOL, number=2, ) - etag = proto.Field( + etag: str = proto.Field( proto.STRING, number=3, ) @@ -252,7 +262,7 @@ class Service(proto.Message): unlike v1, this is an int64 value. As with most Google APIs, its JSON representation will be a ``string`` instead of an ``integer``. - labels (Mapping[str, str]): + labels (MutableMapping[str, str]): Map of string keys and values that can be used to organize and categorize objects. User-provided labels are shared with Google's @@ -267,7 +277,7 @@ class Service(proto.Message): 'run.googleapis.com' or 'serving.knative.dev' namespaces. Those labels are read-only, and user changes will not be preserved. - annotations (Mapping[str, str]): + annotations (MutableMapping[str, str]): Unstructured key value map that may be set by external tools to store and arbitrary metadata. They are not queryable and should be preserved @@ -312,7 +322,7 @@ class Service(proto.Message): template (google.cloud.run_v2.types.RevisionTemplate): Required. The template used to create revisions for this Service. - traffic (Sequence[google.cloud.run_v2.types.TrafficTarget]): + traffic (MutableSequence[google.cloud.run_v2.types.TrafficTarget]): Specifies how to distribute traffic over a collection of Revisions belonging to the Service. If traffic is empty or not provided, defaults to 100% traffic to the latest @@ -330,7 +340,7 @@ class Service(proto.Message): did not reach a serving state. See comments in ``reconciling`` for additional information on reconciliation process in Cloud Run. - conditions (Sequence[google.cloud.run_v2.types.Condition]): + conditions (MutableSequence[google.cloud.run_v2.types.Condition]): Output only. The Conditions of all other associated sub-resources. They contain additional diagnostics information in case the Service does not reach its Serving @@ -344,7 +354,7 @@ class Service(proto.Message): Output only. Name of the last created revision. See comments in ``reconciling`` for additional information on reconciliation process in Cloud Run. - traffic_statuses (Sequence[google.cloud.run_v2.types.TrafficTargetStatus]): + traffic_statuses (MutableSequence[google.cloud.run_v2.types.TrafficTargetStatus]): Output only. Detailed status information for corresponding traffic targets. See comments in ``reconciling`` for additional information on reconciliation process in Cloud @@ -386,129 +396,131 @@ class Service(proto.Message): detect modification conflict during updates. """ - name = proto.Field( + name: str = proto.Field( proto.STRING, number=1, ) - description = proto.Field( + description: str = proto.Field( proto.STRING, number=2, ) - uid = proto.Field( + uid: str = proto.Field( proto.STRING, number=3, ) - generation = proto.Field( + generation: int = proto.Field( proto.INT64, number=4, ) - labels = proto.MapField( + labels: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=5, ) - annotations = proto.MapField( + annotations: MutableMapping[str, str] = proto.MapField( proto.STRING, proto.STRING, number=6, ) - create_time = proto.Field( + create_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=7, message=timestamp_pb2.Timestamp, ) - update_time = proto.Field( + update_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=8, message=timestamp_pb2.Timestamp, ) - delete_time = proto.Field( + delete_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=9, message=timestamp_pb2.Timestamp, ) - expire_time = proto.Field( + expire_time: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=10, message=timestamp_pb2.Timestamp, ) - creator = proto.Field( + creator: str = proto.Field( proto.STRING, number=11, ) - last_modifier = proto.Field( + last_modifier: str = proto.Field( proto.STRING, number=12, ) - client = proto.Field( + client: str = proto.Field( proto.STRING, number=13, ) - client_version = proto.Field( + client_version: str = proto.Field( proto.STRING, number=14, ) - ingress = proto.Field( + ingress: vendor_settings.IngressTraffic = proto.Field( proto.ENUM, number=15, enum=vendor_settings.IngressTraffic, ) - launch_stage = proto.Field( + launch_stage: launch_stage_pb2.LaunchStage = proto.Field( proto.ENUM, number=16, enum=launch_stage_pb2.LaunchStage, ) - binary_authorization = proto.Field( + binary_authorization: vendor_settings.BinaryAuthorization = proto.Field( proto.MESSAGE, number=17, message=vendor_settings.BinaryAuthorization, ) - template = proto.Field( + template: revision_template.RevisionTemplate = proto.Field( proto.MESSAGE, number=18, message=revision_template.RevisionTemplate, ) - traffic = proto.RepeatedField( + traffic: MutableSequence[traffic_target.TrafficTarget] = proto.RepeatedField( proto.MESSAGE, number=19, message=traffic_target.TrafficTarget, ) - observed_generation = proto.Field( + observed_generation: int = proto.Field( proto.INT64, number=30, ) - terminal_condition = proto.Field( + terminal_condition: condition.Condition = proto.Field( proto.MESSAGE, number=31, message=condition.Condition, ) - conditions = proto.RepeatedField( + conditions: MutableSequence[condition.Condition] = proto.RepeatedField( proto.MESSAGE, number=32, message=condition.Condition, ) - latest_ready_revision = proto.Field( + latest_ready_revision: str = proto.Field( proto.STRING, number=33, ) - latest_created_revision = proto.Field( + latest_created_revision: str = proto.Field( proto.STRING, number=34, ) - traffic_statuses = proto.RepeatedField( + traffic_statuses: MutableSequence[ + traffic_target.TrafficTargetStatus + ] = proto.RepeatedField( proto.MESSAGE, number=35, message=traffic_target.TrafficTargetStatus, ) - uri = proto.Field( + uri: str = proto.Field( proto.STRING, number=36, ) - reconciling = proto.Field( + reconciling: bool = proto.Field( proto.BOOL, number=98, ) - etag = proto.Field( + etag: str = proto.Field( proto.STRING, number=99, ) diff --git a/google/cloud/run_v2/types/task.py b/google/cloud/run_v2/types/task.py new file mode 100644 index 0000000..fce97d5 --- /dev/null +++ b/google/cloud/run_v2/types/task.py @@ -0,0 +1,401 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import MutableMapping, MutableSequence + +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +from google.rpc import status_pb2 # type: ignore +import proto # type: ignore + +from google.cloud.run_v2.types import condition, k8s_min, vendor_settings + +__protobuf__ = proto.module( + package="google.cloud.run.v2", + manifest={ + "GetTaskRequest", + "ListTasksRequest", + "ListTasksResponse", + "Task", + "TaskAttemptResult", + }, +) + + +class GetTaskRequest(proto.Message): + r"""Request message for obtaining a Task by its full name. + + Attributes: + name (str): + Required. The full name of the Task. + Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution}/tasks/{task} + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + + +class ListTasksRequest(proto.Message): + r"""Request message for retrieving a list of Tasks. + + Attributes: + parent (str): + Required. The Execution from which the Tasks + should be listed. To list all Tasks across + Executions of a Job, use "-" instead of + Execution name. To list all Tasks across Jobs, + use "-" instead of Job name. Format: + projects/{project}/locations/{location}/jobs/{job}/executions/{execution} + page_size (int): + Maximum number of Tasks to return in this + call. + page_token (str): + A page token received from a previous call to + ListTasks. All other parameters must match. + show_deleted (bool): + If true, returns deleted (but unexpired) + resources along with active ones. + """ + + parent: str = proto.Field( + proto.STRING, + number=1, + ) + page_size: int = proto.Field( + proto.INT32, + number=2, + ) + page_token: str = proto.Field( + proto.STRING, + number=3, + ) + show_deleted: bool = proto.Field( + proto.BOOL, + number=4, + ) + + +class ListTasksResponse(proto.Message): + r"""Response message containing a list of Tasks. + + Attributes: + tasks (MutableSequence[google.cloud.run_v2.types.Task]): + The resulting list of Tasks. + next_page_token (str): + A token indicating there are more items than page_size. Use + it in the next ListTasks request to continue. + """ + + @property + def raw_page(self): + return self + + tasks: MutableSequence["Task"] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Task", + ) + next_page_token: str = proto.Field( + proto.STRING, + number=2, + ) + + +class Task(proto.Message): + r"""Task represents a single run of a container to completion. + + Attributes: + name (str): + Output only. The unique name of this Task. + uid (str): + Output only. Server assigned unique + identifier for the Task. The value is a UUID4 + string and guaranteed to remain unchanged until + the resource is deleted. + generation (int): + Output only. A number that monotonically + increases every time the user modifies the + desired state. + labels (MutableMapping[str, str]): + KRM-style labels for the resource. + User-provided labels are shared with Google's + billing system, so they can be used to filter, + or break down billing charges by team, + component, environment, state, etc. For more + information, visit + https://cloud.google.com/resource-manager/docs/creating-managing-labels + or + https://cloud.google.com/run/docs/configuring/labels + Cloud Run will populate some labels with + 'run.googleapis.com' or 'serving.knative.dev' + namespaces. Those labels are read-only, and user + changes will not be preserved. + annotations (MutableMapping[str, str]): + KRM-style annotations for the resource. + create_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. Represents time when the task + was created by the job controller. It is not + guaranteed to be set in happens-before order + across separate operations. + start_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. Represents time when the task + started to run. It is not guaranteed to be set + in happens-before order across separate + operations. + completion_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. Represents time when the Task + was completed. It is not guaranteed to be set in + happens-before order across separate operations. + update_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The last-modified time. + delete_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. For a deleted resource, the + deletion time. It is only populated as a + response to a Delete request. + expire_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. For a deleted resource, the time + after which it will be permamently deleted. It + is only populated as a response to a Delete + request. + job (str): + Output only. The name of the parent Job. + execution (str): + Output only. The name of the parent + Execution. + containers (MutableSequence[google.cloud.run_v2.types.Container]): + Holds the single container that defines the + unit of execution for this task. + volumes (MutableSequence[google.cloud.run_v2.types.Volume]): + A list of Volumes to make available to + containers. + max_retries (int): + Number of retries allowed per Task, before + marking this Task failed. + timeout (google.protobuf.duration_pb2.Duration): + Max allowed time duration the Task may be + active before the system will actively try to + mark it failed and kill associated containers. + This applies per attempt of a task, meaning each + retry can run for the full timeout. + service_account (str): + Email address of the IAM service account + associated with the Task of a Job. The service + account represents the identity of the running + task, and determines what permissions the task + has. If not provided, the task will use the + project's default service account. + execution_environment (google.cloud.run_v2.types.ExecutionEnvironment): + The execution environment being used to host + this Task. + reconciling (bool): + Output only. Indicates whether the resource's reconciliation + is still in progress. See comments in ``Job.reconciling`` + for additional information on reconciliation process in + Cloud Run. + conditions (MutableSequence[google.cloud.run_v2.types.Condition]): + Output only. The Condition of this Task, + containing its readiness status, and detailed + error information in case it did not reach the + desired state. + observed_generation (int): + Output only. The generation of this Task. See comments in + ``Job.reconciling`` for additional information on + reconciliation process in Cloud Run. + index (int): + Output only. Index of the Task, unique per + execution, and beginning at 0. + retried (int): + Output only. The number of times this Task + was retried. Tasks are retried when they fail up + to the maxRetries limit. + last_attempt_result (google.cloud.run_v2.types.TaskAttemptResult): + Output only. Result of the last attempt of + this Task. + encryption_key (str): + Output only. A reference to a customer + managed encryption key (CMEK) to use to encrypt + this container image. For more information, go + to + https://cloud.google.com/run/docs/securing/using-cmek + vpc_access (google.cloud.run_v2.types.VpcAccess): + Output only. VPC Access configuration to use + for this Task. For more information, visit + https://cloud.google.com/run/docs/configuring/connecting-vpc. + etag (str): + Output only. A system-generated fingerprint + for this version of the resource. May be used to + detect modification conflict during updates. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + uid: str = proto.Field( + proto.STRING, + number=2, + ) + generation: int = proto.Field( + proto.INT64, + number=3, + ) + labels: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=4, + ) + annotations: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=5, + ) + create_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=6, + message=timestamp_pb2.Timestamp, + ) + start_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=27, + message=timestamp_pb2.Timestamp, + ) + completion_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=7, + message=timestamp_pb2.Timestamp, + ) + update_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=8, + message=timestamp_pb2.Timestamp, + ) + delete_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=9, + message=timestamp_pb2.Timestamp, + ) + expire_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=10, + message=timestamp_pb2.Timestamp, + ) + job: str = proto.Field( + proto.STRING, + number=12, + ) + execution: str = proto.Field( + proto.STRING, + number=13, + ) + containers: MutableSequence[k8s_min.Container] = proto.RepeatedField( + proto.MESSAGE, + number=14, + message=k8s_min.Container, + ) + volumes: MutableSequence[k8s_min.Volume] = proto.RepeatedField( + proto.MESSAGE, + number=15, + message=k8s_min.Volume, + ) + max_retries: int = proto.Field( + proto.INT32, + number=16, + ) + timeout: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=17, + message=duration_pb2.Duration, + ) + service_account: str = proto.Field( + proto.STRING, + number=18, + ) + execution_environment: vendor_settings.ExecutionEnvironment = proto.Field( + proto.ENUM, + number=20, + enum=vendor_settings.ExecutionEnvironment, + ) + reconciling: bool = proto.Field( + proto.BOOL, + number=21, + ) + conditions: MutableSequence[condition.Condition] = proto.RepeatedField( + proto.MESSAGE, + number=22, + message=condition.Condition, + ) + observed_generation: int = proto.Field( + proto.INT64, + number=23, + ) + index: int = proto.Field( + proto.INT32, + number=24, + ) + retried: int = proto.Field( + proto.INT32, + number=25, + ) + last_attempt_result: "TaskAttemptResult" = proto.Field( + proto.MESSAGE, + number=26, + message="TaskAttemptResult", + ) + encryption_key: str = proto.Field( + proto.STRING, + number=28, + ) + vpc_access: vendor_settings.VpcAccess = proto.Field( + proto.MESSAGE, + number=29, + message=vendor_settings.VpcAccess, + ) + etag: str = proto.Field( + proto.STRING, + number=99, + ) + + +class TaskAttemptResult(proto.Message): + r"""Result of a task attempt. + + Attributes: + status (google.rpc.status_pb2.Status): + Output only. The status of this attempt. + If the status code is OK, then the attempt + succeeded. + exit_code (int): + Output only. The exit code of this attempt. + This may be unset if the container was unable to + exit cleanly with a code due to some other + failure. + See status field for possible failure details. + """ + + status: status_pb2.Status = proto.Field( + proto.MESSAGE, + number=1, + message=status_pb2.Status, + ) + exit_code: int = proto.Field( + proto.INT32, + number=2, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/run_v2/types/task_template.py b/google/cloud/run_v2/types/task_template.py new file mode 100644 index 0000000..a06c572 --- /dev/null +++ b/google/cloud/run_v2/types/task_template.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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 typing import MutableMapping, MutableSequence + +from google.protobuf import duration_pb2 # type: ignore +import proto # type: ignore + +from google.cloud.run_v2.types import k8s_min, vendor_settings + +__protobuf__ = proto.module( + package="google.cloud.run.v2", + manifest={ + "TaskTemplate", + }, +) + + +class TaskTemplate(proto.Message): + r"""TaskTemplate describes the data a task should have when + created from a template. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + containers (MutableSequence[google.cloud.run_v2.types.Container]): + Holds the single container that defines the + unit of execution for this task. + volumes (MutableSequence[google.cloud.run_v2.types.Volume]): + A list of Volumes to make available to + containers. + max_retries (int): + Number of retries allowed per Task, before + marking this Task failed. + + This field is a member of `oneof`_ ``retries``. + timeout (google.protobuf.duration_pb2.Duration): + Max allowed time duration the Task may be + active before the system will actively try to + mark it failed and kill associated containers. + This applies per attempt of a task, meaning each + retry can run for the full timeout. + service_account (str): + Email address of the IAM service account + associated with the Task of a Job. The service + account represents the identity of the running + task, and determines what permissions the task + has. If not provided, the task will use the + project's default service account. + execution_environment (google.cloud.run_v2.types.ExecutionEnvironment): + The execution environment being used to host + this Task. + encryption_key (str): + A reference to a customer managed encryption + key (CMEK) to use to encrypt this container + image. For more information, go to + https://cloud.google.com/run/docs/securing/using-cmek + vpc_access (google.cloud.run_v2.types.VpcAccess): + VPC Access configuration to use for this + Task. For more information, visit + https://cloud.google.com/run/docs/configuring/connecting-vpc. + """ + + containers: MutableSequence[k8s_min.Container] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=k8s_min.Container, + ) + volumes: MutableSequence[k8s_min.Volume] = proto.RepeatedField( + proto.MESSAGE, + number=2, + message=k8s_min.Volume, + ) + max_retries: int = proto.Field( + proto.INT32, + number=3, + oneof="retries", + ) + timeout: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=4, + message=duration_pb2.Duration, + ) + service_account: str = proto.Field( + proto.STRING, + number=5, + ) + execution_environment: vendor_settings.ExecutionEnvironment = proto.Field( + proto.ENUM, + number=6, + enum=vendor_settings.ExecutionEnvironment, + ) + encryption_key: str = proto.Field( + proto.STRING, + number=7, + ) + vpc_access: vendor_settings.VpcAccess = proto.Field( + proto.MESSAGE, + number=8, + message=vendor_settings.VpcAccess, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/run_v2/types/traffic_target.py b/google/cloud/run_v2/types/traffic_target.py index 137aad6..12234b4 100644 --- a/google/cloud/run_v2/types/traffic_target.py +++ b/google/cloud/run_v2/types/traffic_target.py @@ -13,8 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence +import proto # type: ignore __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -52,20 +53,20 @@ class TrafficTarget(proto.Message): exclusively reference this target. """ - type_ = proto.Field( + type_: "TrafficTargetAllocationType" = proto.Field( proto.ENUM, number=1, enum="TrafficTargetAllocationType", ) - revision = proto.Field( + revision: str = proto.Field( proto.STRING, number=2, ) - percent = proto.Field( + percent: int = proto.Field( proto.INT32, number=3, ) - tag = proto.Field( + tag: str = proto.Field( proto.STRING, number=4, ) @@ -89,24 +90,24 @@ class TrafficTargetStatus(proto.Message): Displays the target URI. """ - type_ = proto.Field( + type_: "TrafficTargetAllocationType" = proto.Field( proto.ENUM, number=1, enum="TrafficTargetAllocationType", ) - revision = proto.Field( + revision: str = proto.Field( proto.STRING, number=2, ) - percent = proto.Field( + percent: int = proto.Field( proto.INT32, number=3, ) - tag = proto.Field( + tag: str = proto.Field( proto.STRING, number=4, ) - uri = proto.Field( + uri: str = proto.Field( proto.STRING, number=5, ) diff --git a/google/cloud/run_v2/types/vendor_settings.py b/google/cloud/run_v2/types/vendor_settings.py index 51da1e9..a13f0d0 100644 --- a/google/cloud/run_v2/types/vendor_settings.py +++ b/google/cloud/run_v2/types/vendor_settings.py @@ -13,8 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import proto # type: ignore +from typing import MutableMapping, MutableSequence +import proto # type: ignore __protobuf__ = proto.module( package="google.cloud.run.v2", @@ -55,7 +56,8 @@ class VpcAccess(proto.Message): connector (str): VPC Access connector name. Format: - projects/{project}/locations/{location}/connectors/{connector} + projects/{project}/locations/{location}/connectors/{connector}, + where {project} can be project id or number. egress (google.cloud.run_v2.types.VpcAccess.VpcEgress): Traffic VPC egress settings. """ @@ -66,11 +68,11 @@ class VpcEgress(proto.Enum): ALL_TRAFFIC = 1 PRIVATE_RANGES_ONLY = 2 - connector = proto.Field( + connector: str = proto.Field( proto.STRING, number=1, ) - egress = proto.Field( + egress: VpcEgress = proto.Field( proto.ENUM, number=2, enum=VpcEgress, @@ -96,12 +98,12 @@ class BinaryAuthorization(proto.Message): https://cloud.google.com/binary-authorization/docs/using-breakglass """ - use_default = proto.Field( + use_default: bool = proto.Field( proto.BOOL, number=1, oneof="binauthz_method", ) - breakglass_justification = proto.Field( + breakglass_justification: str = proto.Field( proto.STRING, number=2, ) @@ -119,11 +121,11 @@ class RevisionScaling(proto.Message): resource should have. """ - min_instance_count = proto.Field( + min_instance_count: int = proto.Field( proto.INT32, number=1, ) - max_instance_count = proto.Field( + max_instance_count: int = proto.Field( proto.INT32, number=2, ) diff --git a/noxfile.py b/noxfile.py index 5f898a7..d8440c0 100644 --- a/noxfile.py +++ b/noxfile.py @@ -17,6 +17,7 @@ # Generated by synthtool. DO NOT EDIT! from __future__ import absolute_import + import os import pathlib import re @@ -272,12 +273,16 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python="3.9") def docs(session): """Build the docs for this library.""" session.install("-e", ".") - session.install("sphinx==4.0.1", "alabaster", "recommonmark") + session.install( + "sphinx==4.0.1", + "alabaster", + "recommonmark", + ) shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) session.run( @@ -294,13 +299,16 @@ def docs(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python="3.9") def docfx(session): """Build the docfx yaml files for this library.""" session.install("-e", ".") session.install( - "sphinx==4.0.1", "alabaster", "recommonmark", "gcp-sphinx-docfx-yaml" + "sphinx==4.0.1", + "alabaster", + "recommonmark", + "gcp-sphinx-docfx-yaml", ) shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) diff --git a/owlbot.py b/owlbot.py index 1ecdcb8..3e68342 100644 --- a/owlbot.py +++ b/owlbot.py @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json +from pathlib import Path +import shutil + import synthtool as s import synthtool.gcp as gcp from synthtool.languages import python @@ -20,15 +24,20 @@ # Copy the generated client from the owl-bot staging directory # ---------------------------------------------------------------------------- -default_version = "v2" +clean_up_generated_samples = True + +# Load the default version defined in .repo-metadata.json. +default_version = json.load(open(".repo-metadata.json", "rt")).get( + "default_version" +) for library in s.get_staging_dirs(default_version): + if clean_up_generated_samples: + shutil.rmtree("samples/generated_samples", ignore_errors=True) + clean_up_generated_samples = False - excludes=["google/cloud/run/", "setup.py", "README.rst"] # See https://github.com/googleapis/gapic-generator-python/issues/825 - excludes.extend(["docs/index.rst", "docs/run_v2/services.rst"]) - s.move(library, excludes=excludes) - + s.move([library], excludes=["**/gapic_version.py", "docs/index.rst", "docs/run_v2/services.rst"]) s.remove_staging_dirs() # ---------------------------------------------------------------------------- @@ -36,14 +45,14 @@ # ---------------------------------------------------------------------------- templated_files = gcp.CommonTemplates().py_library( + cov_level=100, microgenerator=True, + versions=gcp.common.detect_versions(path="./google", default_first=True), ) -s.move(templated_files, excludes=[".coveragerc"]) # the microgenerator has a good coveragerc file +s.move(templated_files, excludes=[".coveragerc", ".github/release-please.yml", "docs/index.rst"]) python.py_samples(skip_readmes=True) -# ---------------------------------------------------------------------------- -# Run blacken session -# ---------------------------------------------------------------------------- - -s.shell.run(["nox", "-s", "blacken"], hide_output=False) +# run format session for all directories which have a noxfile +for noxfile in Path(".").glob("**/noxfile.py"): + s.shell.run(["nox", "-s", "format"], cwd=noxfile.parent, hide_output=False) diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..53785f2 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "python", + "extra-files": [ + "google/cloud/run_v2/gapic_version.py", + "google/cloud/run/gapic_version.py", + { + "type": "json", + "path": "samples/generated_samples/snippet_metadata_google.cloud.run.v2.json", + "jsonpath": "$.clientLibrary.version" + } + ] + } + }, + "release-type": "python", + "plugins": [ + { + "type": "sentence-case" + } + ], + "initial-version": "0.1.0" +} diff --git a/samples/generated_samples/run_v2_generated_revisions_delete_revision_sync_2da46bc2.py b/samples/generated_samples/run_v2_generated_executions_delete_execution_async.py similarity index 80% rename from samples/generated_samples/run_v2_generated_revisions_delete_revision_sync_2da46bc2.py rename to samples/generated_samples/run_v2_generated_executions_delete_execution_async.py index 058af22..2df54da 100644 --- a/samples/generated_samples/run_v2_generated_revisions_delete_revision_sync_2da46bc2.py +++ b/samples/generated_samples/run_v2_generated_executions_delete_execution_async.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for DeleteRevision +# Snippet for DeleteExecution # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Revisions_DeleteRevision_sync_2da46bc2] +# [START run_v2_generated_Executions_DeleteExecution_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,23 +34,23 @@ from google.cloud import run_v2 -def sample_delete_revision(): +async def sample_delete_execution(): # Create a client - client = run_v2.RevisionsClient() + client = run_v2.ExecutionsAsyncClient() # Initialize request argument(s) - request = run_v2.DeleteRevisionRequest( + request = run_v2.DeleteExecutionRequest( name="name_value", ) # Make the request - operation = client.delete_revision(request=request) + operation = client.delete_execution(request=request) print("Waiting for operation to complete...") - response = operation.result() + response = (await operation).result() # Handle the response print(response) -# [END run_v2_generated_Revisions_DeleteRevision_sync_2da46bc2] +# [END run_v2_generated_Executions_DeleteExecution_async] diff --git a/samples/generated_samples/run_v2_generated_services_delete_service_sync_91d4ca21.py b/samples/generated_samples/run_v2_generated_executions_delete_execution_sync.py similarity index 83% rename from samples/generated_samples/run_v2_generated_services_delete_service_sync_91d4ca21.py rename to samples/generated_samples/run_v2_generated_executions_delete_execution_sync.py index 08b4776..b62b5dc 100644 --- a/samples/generated_samples/run_v2_generated_services_delete_service_sync_91d4ca21.py +++ b/samples/generated_samples/run_v2_generated_executions_delete_execution_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for DeleteService +# Snippet for DeleteExecution # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_DeleteService_sync_91d4ca21] +# [START run_v2_generated_Executions_DeleteExecution_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,17 +34,17 @@ from google.cloud import run_v2 -def sample_delete_service(): +def sample_delete_execution(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.ExecutionsClient() # Initialize request argument(s) - request = run_v2.DeleteServiceRequest( + request = run_v2.DeleteExecutionRequest( name="name_value", ) # Make the request - operation = client.delete_service(request=request) + operation = client.delete_execution(request=request) print("Waiting for operation to complete...") @@ -53,4 +53,4 @@ def sample_delete_service(): # Handle the response print(response) -# [END run_v2_generated_Services_DeleteService_sync_91d4ca21] +# [END run_v2_generated_Executions_DeleteExecution_sync] diff --git a/samples/generated_samples/run_v2_generated_executions_get_execution_async.py b/samples/generated_samples/run_v2_generated_executions_get_execution_async.py new file mode 100644 index 0000000..8dabd7e --- /dev/null +++ b/samples/generated_samples/run_v2_generated_executions_get_execution_async.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for GetExecution +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-run + + +# [START run_v2_generated_Executions_GetExecution_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import run_v2 + + +async def sample_get_execution(): + # Create a client + client = run_v2.ExecutionsAsyncClient() + + # Initialize request argument(s) + request = run_v2.GetExecutionRequest( + name="name_value", + ) + + # Make the request + response = await client.get_execution(request=request) + + # Handle the response + print(response) + +# [END run_v2_generated_Executions_GetExecution_async] diff --git a/samples/generated_samples/run_v2_generated_services_get_service_sync_18284d02.py b/samples/generated_samples/run_v2_generated_executions_get_execution_sync.py similarity index 83% rename from samples/generated_samples/run_v2_generated_services_get_service_sync_18284d02.py rename to samples/generated_samples/run_v2_generated_executions_get_execution_sync.py index 6280f7f..eadb512 100644 --- a/samples/generated_samples/run_v2_generated_services_get_service_sync_18284d02.py +++ b/samples/generated_samples/run_v2_generated_executions_get_execution_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for GetService +# Snippet for GetExecution # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_GetService_sync_18284d02] +# [START run_v2_generated_Executions_GetExecution_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,19 +34,19 @@ from google.cloud import run_v2 -def sample_get_service(): +def sample_get_execution(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.ExecutionsClient() # Initialize request argument(s) - request = run_v2.GetServiceRequest( + request = run_v2.GetExecutionRequest( name="name_value", ) # Make the request - response = client.get_service(request=request) + response = client.get_execution(request=request) # Handle the response print(response) -# [END run_v2_generated_Services_GetService_sync_18284d02] +# [END run_v2_generated_Executions_GetExecution_sync] diff --git a/samples/generated_samples/run_v2_generated_executions_list_executions_async.py b/samples/generated_samples/run_v2_generated_executions_list_executions_async.py new file mode 100644 index 0000000..68865c0 --- /dev/null +++ b/samples/generated_samples/run_v2_generated_executions_list_executions_async.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for ListExecutions +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-run + + +# [START run_v2_generated_Executions_ListExecutions_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import run_v2 + + +async def sample_list_executions(): + # Create a client + client = run_v2.ExecutionsAsyncClient() + + # Initialize request argument(s) + request = run_v2.ListExecutionsRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_executions(request=request) + + # Handle the response + async for response in page_result: + print(response) + +# [END run_v2_generated_Executions_ListExecutions_async] diff --git a/samples/generated_samples/run_v2_generated_services_list_services_sync_7dbaf490.py b/samples/generated_samples/run_v2_generated_executions_list_executions_sync.py similarity index 82% rename from samples/generated_samples/run_v2_generated_services_list_services_sync_7dbaf490.py rename to samples/generated_samples/run_v2_generated_executions_list_executions_sync.py index 7d44aa7..df98a89 100644 --- a/samples/generated_samples/run_v2_generated_services_list_services_sync_7dbaf490.py +++ b/samples/generated_samples/run_v2_generated_executions_list_executions_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for ListServices +# Snippet for ListExecutions # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_ListServices_sync_7dbaf490] +# [START run_v2_generated_Executions_ListExecutions_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,20 +34,20 @@ from google.cloud import run_v2 -def sample_list_services(): +def sample_list_executions(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.ExecutionsClient() # Initialize request argument(s) - request = run_v2.ListServicesRequest( + request = run_v2.ListExecutionsRequest( parent="parent_value", ) # Make the request - page_result = client.list_services(request=request) + page_result = client.list_executions(request=request) # Handle the response for response in page_result: print(response) -# [END run_v2_generated_Services_ListServices_sync_7dbaf490] +# [END run_v2_generated_Executions_ListExecutions_sync] diff --git a/samples/generated_samples/run_v2_generated_services_create_service_sync_8031b824.py b/samples/generated_samples/run_v2_generated_jobs_create_job_async.py similarity index 77% rename from samples/generated_samples/run_v2_generated_services_create_service_sync_8031b824.py rename to samples/generated_samples/run_v2_generated_jobs_create_job_async.py index 2ec8a39..b9f23de 100644 --- a/samples/generated_samples/run_v2_generated_services_create_service_sync_8031b824.py +++ b/samples/generated_samples/run_v2_generated_jobs_create_job_async.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for CreateService +# Snippet for CreateJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_CreateService_sync_8031b824] +# [START run_v2_generated_Jobs_CreateJob_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,24 +34,28 @@ from google.cloud import run_v2 -def sample_create_service(): +async def sample_create_job(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) - request = run_v2.CreateServiceRequest( + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.CreateJobRequest( parent="parent_value", - service_id="service_id_value", + job=job, + job_id="job_id_value", ) # Make the request - operation = client.create_service(request=request) + operation = client.create_job(request=request) print("Waiting for operation to complete...") - response = operation.result() + response = (await operation).result() # Handle the response print(response) -# [END run_v2_generated_Services_CreateService_sync_8031b824] +# [END run_v2_generated_Jobs_CreateJob_async] diff --git a/samples/generated_samples/run_v2_generated_services_create_service_sync_3c405c33.py b/samples/generated_samples/run_v2_generated_jobs_create_job_sync.py similarity index 80% rename from samples/generated_samples/run_v2_generated_services_create_service_sync_3c405c33.py rename to samples/generated_samples/run_v2_generated_jobs_create_job_sync.py index d998b0d..cc86bdf 100644 --- a/samples/generated_samples/run_v2_generated_services_create_service_sync_3c405c33.py +++ b/samples/generated_samples/run_v2_generated_jobs_create_job_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for CreateService +# Snippet for CreateJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_CreateService_sync_3c405c33] +# [START run_v2_generated_Jobs_CreateJob_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,18 +34,22 @@ from google.cloud import run_v2 -def sample_create_service(): +def sample_create_job(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) - request = run_v2.CreateServiceRequest( + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.CreateJobRequest( parent="parent_value", - service_id="service_id_value", + job=job, + job_id="job_id_value", ) # Make the request - operation = client.create_service(request=request) + operation = client.create_job(request=request) print("Waiting for operation to complete...") @@ -54,4 +58,4 @@ def sample_create_service(): # Handle the response print(response) -# [END run_v2_generated_Services_CreateService_sync_3c405c33] +# [END run_v2_generated_Jobs_CreateJob_sync] diff --git a/samples/generated_samples/run_v2_generated_jobs_delete_job_async.py b/samples/generated_samples/run_v2_generated_jobs_delete_job_async.py new file mode 100644 index 0000000..2f52858 --- /dev/null +++ b/samples/generated_samples/run_v2_generated_jobs_delete_job_async.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for DeleteJob +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-run + + +# [START run_v2_generated_Jobs_DeleteJob_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import run_v2 + + +async def sample_delete_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = run_v2.DeleteJobRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_job(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + +# [END run_v2_generated_Jobs_DeleteJob_async] diff --git a/samples/generated_samples/run_v2_generated_services_delete_service_sync_9c99d0a2.py b/samples/generated_samples/run_v2_generated_jobs_delete_job_sync.py similarity index 83% rename from samples/generated_samples/run_v2_generated_services_delete_service_sync_9c99d0a2.py rename to samples/generated_samples/run_v2_generated_jobs_delete_job_sync.py index 4ce2d70..afbff03 100644 --- a/samples/generated_samples/run_v2_generated_services_delete_service_sync_9c99d0a2.py +++ b/samples/generated_samples/run_v2_generated_jobs_delete_job_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for DeleteService +# Snippet for DeleteJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_DeleteService_sync_9c99d0a2] +# [START run_v2_generated_Jobs_DeleteJob_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,17 +34,17 @@ from google.cloud import run_v2 -def sample_delete_service(): +def sample_delete_job(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) - request = run_v2.DeleteServiceRequest( + request = run_v2.DeleteJobRequest( name="name_value", ) # Make the request - operation = client.delete_service(request=request) + operation = client.delete_job(request=request) print("Waiting for operation to complete...") @@ -53,4 +53,4 @@ def sample_delete_service(): # Handle the response print(response) -# [END run_v2_generated_Services_DeleteService_sync_9c99d0a2] +# [END run_v2_generated_Jobs_DeleteJob_sync] diff --git a/samples/generated_samples/run_v2_generated_services_get_iam_policy_sync_9f45c2a7.py b/samples/generated_samples/run_v2_generated_jobs_get_iam_policy_async.py similarity index 86% rename from samples/generated_samples/run_v2_generated_services_get_iam_policy_sync_9f45c2a7.py rename to samples/generated_samples/run_v2_generated_jobs_get_iam_policy_async.py index 62a767f..cb50a6c 100644 --- a/samples/generated_samples/run_v2_generated_services_get_iam_policy_sync_9f45c2a7.py +++ b/samples/generated_samples/run_v2_generated_jobs_get_iam_policy_async.py @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_GetIamPolicy_sync_9f45c2a7] +# [START run_v2_generated_Jobs_GetIamPolicy_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -35,9 +35,9 @@ from google.iam.v1 import iam_policy_pb2 # type: ignore -def sample_get_iam_policy(): +async def sample_get_iam_policy(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.GetIamPolicyRequest( @@ -45,9 +45,9 @@ def sample_get_iam_policy(): ) # Make the request - response = client.get_iam_policy(request=request) + response = await client.get_iam_policy(request=request) # Handle the response print(response) -# [END run_v2_generated_Services_GetIamPolicy_sync_9f45c2a7] +# [END run_v2_generated_Jobs_GetIamPolicy_async] diff --git a/samples/generated_samples/run_v2_generated_services_get_iam_policy_sync_449f2eb3.py b/samples/generated_samples/run_v2_generated_jobs_get_iam_policy_sync.py similarity index 91% rename from samples/generated_samples/run_v2_generated_services_get_iam_policy_sync_449f2eb3.py rename to samples/generated_samples/run_v2_generated_jobs_get_iam_policy_sync.py index ae6c0cd..a6d2de0 100644 --- a/samples/generated_samples/run_v2_generated_services_get_iam_policy_sync_449f2eb3.py +++ b/samples/generated_samples/run_v2_generated_jobs_get_iam_policy_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_GetIamPolicy_sync_449f2eb3] +# [START run_v2_generated_Jobs_GetIamPolicy_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -37,7 +37,7 @@ def sample_get_iam_policy(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) request = iam_policy_pb2.GetIamPolicyRequest( @@ -50,4 +50,4 @@ def sample_get_iam_policy(): # Handle the response print(response) -# [END run_v2_generated_Services_GetIamPolicy_sync_449f2eb3] +# [END run_v2_generated_Jobs_GetIamPolicy_sync] diff --git a/samples/generated_samples/run_v2_generated_services_get_service_sync_1c3ef02e.py b/samples/generated_samples/run_v2_generated_jobs_get_job_async.py similarity index 83% rename from samples/generated_samples/run_v2_generated_services_get_service_sync_1c3ef02e.py rename to samples/generated_samples/run_v2_generated_jobs_get_job_async.py index 5c32f50..2f782ef 100644 --- a/samples/generated_samples/run_v2_generated_services_get_service_sync_1c3ef02e.py +++ b/samples/generated_samples/run_v2_generated_jobs_get_job_async.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for GetService +# Snippet for GetJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_GetService_sync_1c3ef02e] +# [START run_v2_generated_Jobs_GetJob_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,19 +34,19 @@ from google.cloud import run_v2 -def sample_get_service(): +async def sample_get_job(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) - request = run_v2.GetServiceRequest( + request = run_v2.GetJobRequest( name="name_value", ) # Make the request - response = client.get_service(request=request) + response = await client.get_job(request=request) # Handle the response print(response) -# [END run_v2_generated_Services_GetService_sync_1c3ef02e] +# [END run_v2_generated_Jobs_GetJob_async] diff --git a/samples/generated_samples/run_v2_generated_revisions_get_revision_sync_115a25ad.py b/samples/generated_samples/run_v2_generated_jobs_get_job_sync.py similarity index 82% rename from samples/generated_samples/run_v2_generated_revisions_get_revision_sync_115a25ad.py rename to samples/generated_samples/run_v2_generated_jobs_get_job_sync.py index 31661cc..285fd9b 100644 --- a/samples/generated_samples/run_v2_generated_revisions_get_revision_sync_115a25ad.py +++ b/samples/generated_samples/run_v2_generated_jobs_get_job_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for GetRevision +# Snippet for GetJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Revisions_GetRevision_sync_115a25ad] +# [START run_v2_generated_Jobs_GetJob_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,19 +34,19 @@ from google.cloud import run_v2 -def sample_get_revision(): +def sample_get_job(): # Create a client - client = run_v2.RevisionsClient() + client = run_v2.JobsClient() # Initialize request argument(s) - request = run_v2.GetRevisionRequest( + request = run_v2.GetJobRequest( name="name_value", ) # Make the request - response = client.get_revision(request=request) + response = client.get_job(request=request) # Handle the response print(response) -# [END run_v2_generated_Revisions_GetRevision_sync_115a25ad] +# [END run_v2_generated_Jobs_GetJob_sync] diff --git a/samples/generated_samples/run_v2_generated_revisions_list_revisions_sync_2312de2e.py b/samples/generated_samples/run_v2_generated_jobs_list_jobs_async.py similarity index 80% rename from samples/generated_samples/run_v2_generated_revisions_list_revisions_sync_2312de2e.py rename to samples/generated_samples/run_v2_generated_jobs_list_jobs_async.py index 7695c69..de1196a 100644 --- a/samples/generated_samples/run_v2_generated_revisions_list_revisions_sync_2312de2e.py +++ b/samples/generated_samples/run_v2_generated_jobs_list_jobs_async.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for ListRevisions +# Snippet for ListJobs # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Revisions_ListRevisions_sync_2312de2e] +# [START run_v2_generated_Jobs_ListJobs_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,20 +34,20 @@ from google.cloud import run_v2 -def sample_list_revisions(): +async def sample_list_jobs(): # Create a client - client = run_v2.RevisionsClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) - request = run_v2.ListRevisionsRequest( + request = run_v2.ListJobsRequest( parent="parent_value", ) # Make the request - page_result = client.list_revisions(request=request) + page_result = client.list_jobs(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) -# [END run_v2_generated_Revisions_ListRevisions_sync_2312de2e] +# [END run_v2_generated_Jobs_ListJobs_async] diff --git a/samples/generated_samples/run_v2_generated_services_list_services_sync_c5743712.py b/samples/generated_samples/run_v2_generated_jobs_list_jobs_sync.py similarity index 82% rename from samples/generated_samples/run_v2_generated_services_list_services_sync_c5743712.py rename to samples/generated_samples/run_v2_generated_jobs_list_jobs_sync.py index b14c8b4..a62d3fd 100644 --- a/samples/generated_samples/run_v2_generated_services_list_services_sync_c5743712.py +++ b/samples/generated_samples/run_v2_generated_jobs_list_jobs_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for ListServices +# Snippet for ListJobs # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_ListServices_sync_c5743712] +# [START run_v2_generated_Jobs_ListJobs_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,20 +34,20 @@ from google.cloud import run_v2 -def sample_list_services(): +def sample_list_jobs(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) - request = run_v2.ListServicesRequest( + request = run_v2.ListJobsRequest( parent="parent_value", ) # Make the request - page_result = client.list_services(request=request) + page_result = client.list_jobs(request=request) # Handle the response for response in page_result: print(response) -# [END run_v2_generated_Services_ListServices_sync_c5743712] +# [END run_v2_generated_Jobs_ListJobs_sync] diff --git a/samples/generated_samples/run_v2_generated_jobs_run_job_async.py b/samples/generated_samples/run_v2_generated_jobs_run_job_async.py new file mode 100644 index 0000000..67f42bf --- /dev/null +++ b/samples/generated_samples/run_v2_generated_jobs_run_job_async.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for RunJob +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-run + + +# [START run_v2_generated_Jobs_RunJob_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import run_v2 + + +async def sample_run_job(): + # Create a client + client = run_v2.JobsAsyncClient() + + # Initialize request argument(s) + request = run_v2.RunJobRequest( + name="name_value", + ) + + # Make the request + operation = client.run_job(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + +# [END run_v2_generated_Jobs_RunJob_async] diff --git a/samples/generated_samples/run_v2_generated_services_update_service_sync_2652a462.py b/samples/generated_samples/run_v2_generated_jobs_run_job_sync.py similarity index 82% rename from samples/generated_samples/run_v2_generated_services_update_service_sync_2652a462.py rename to samples/generated_samples/run_v2_generated_jobs_run_job_sync.py index 549b76b..450b562 100644 --- a/samples/generated_samples/run_v2_generated_services_update_service_sync_2652a462.py +++ b/samples/generated_samples/run_v2_generated_jobs_run_job_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for UpdateService +# Snippet for RunJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_UpdateService_sync_2652a462] +# [START run_v2_generated_Jobs_RunJob_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,16 +34,17 @@ from google.cloud import run_v2 -def sample_update_service(): +def sample_run_job(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) - request = run_v2.UpdateServiceRequest( + request = run_v2.RunJobRequest( + name="name_value", ) # Make the request - operation = client.update_service(request=request) + operation = client.run_job(request=request) print("Waiting for operation to complete...") @@ -52,4 +53,4 @@ def sample_update_service(): # Handle the response print(response) -# [END run_v2_generated_Services_UpdateService_sync_2652a462] +# [END run_v2_generated_Jobs_RunJob_sync] diff --git a/samples/generated_samples/run_v2_generated_services_set_iam_policy_sync_c710ebbc.py b/samples/generated_samples/run_v2_generated_jobs_set_iam_policy_async.py similarity index 86% rename from samples/generated_samples/run_v2_generated_services_set_iam_policy_sync_c710ebbc.py rename to samples/generated_samples/run_v2_generated_jobs_set_iam_policy_async.py index 14641dc..18ed951 100644 --- a/samples/generated_samples/run_v2_generated_services_set_iam_policy_sync_c710ebbc.py +++ b/samples/generated_samples/run_v2_generated_jobs_set_iam_policy_async.py @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_SetIamPolicy_sync_c710ebbc] +# [START run_v2_generated_Jobs_SetIamPolicy_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -35,9 +35,9 @@ from google.iam.v1 import iam_policy_pb2 # type: ignore -def sample_set_iam_policy(): +async def sample_set_iam_policy(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.SetIamPolicyRequest( @@ -45,9 +45,9 @@ def sample_set_iam_policy(): ) # Make the request - response = client.set_iam_policy(request=request) + response = await client.set_iam_policy(request=request) # Handle the response print(response) -# [END run_v2_generated_Services_SetIamPolicy_sync_c710ebbc] +# [END run_v2_generated_Jobs_SetIamPolicy_async] diff --git a/samples/generated_samples/run_v2_generated_services_set_iam_policy_sync_b88666d6.py b/samples/generated_samples/run_v2_generated_jobs_set_iam_policy_sync.py similarity index 91% rename from samples/generated_samples/run_v2_generated_services_set_iam_policy_sync_b88666d6.py rename to samples/generated_samples/run_v2_generated_jobs_set_iam_policy_sync.py index d3f53e2..b1b17ca 100644 --- a/samples/generated_samples/run_v2_generated_services_set_iam_policy_sync_b88666d6.py +++ b/samples/generated_samples/run_v2_generated_jobs_set_iam_policy_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_SetIamPolicy_sync_b88666d6] +# [START run_v2_generated_Jobs_SetIamPolicy_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -37,7 +37,7 @@ def sample_set_iam_policy(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) request = iam_policy_pb2.SetIamPolicyRequest( @@ -50,4 +50,4 @@ def sample_set_iam_policy(): # Handle the response print(response) -# [END run_v2_generated_Services_SetIamPolicy_sync_b88666d6] +# [END run_v2_generated_Jobs_SetIamPolicy_sync] diff --git a/samples/generated_samples/run_v2_generated_services_test_iam_permissions_sync_7c7fb79b.py b/samples/generated_samples/run_v2_generated_jobs_test_iam_permissions_async.py similarity index 86% rename from samples/generated_samples/run_v2_generated_services_test_iam_permissions_sync_7c7fb79b.py rename to samples/generated_samples/run_v2_generated_jobs_test_iam_permissions_async.py index 333f714..eec9fcb 100644 --- a/samples/generated_samples/run_v2_generated_services_test_iam_permissions_sync_7c7fb79b.py +++ b/samples/generated_samples/run_v2_generated_jobs_test_iam_permissions_async.py @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_TestIamPermissions_sync_7c7fb79b] +# [START run_v2_generated_Jobs_TestIamPermissions_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -35,9 +35,9 @@ from google.iam.v1 import iam_policy_pb2 # type: ignore -def sample_test_iam_permissions(): +async def sample_test_iam_permissions(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.TestIamPermissionsRequest( @@ -46,9 +46,9 @@ def sample_test_iam_permissions(): ) # Make the request - response = client.test_iam_permissions(request=request) + response = await client.test_iam_permissions(request=request) # Handle the response print(response) -# [END run_v2_generated_Services_TestIamPermissions_sync_7c7fb79b] +# [END run_v2_generated_Jobs_TestIamPermissions_async] diff --git a/samples/generated_samples/run_v2_generated_services_test_iam_permissions_sync_048b00bc.py b/samples/generated_samples/run_v2_generated_jobs_test_iam_permissions_sync.py similarity index 91% rename from samples/generated_samples/run_v2_generated_services_test_iam_permissions_sync_048b00bc.py rename to samples/generated_samples/run_v2_generated_jobs_test_iam_permissions_sync.py index b53a243..30caa40 100644 --- a/samples/generated_samples/run_v2_generated_services_test_iam_permissions_sync_048b00bc.py +++ b/samples/generated_samples/run_v2_generated_jobs_test_iam_permissions_sync.py @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_TestIamPermissions_sync_048b00bc] +# [START run_v2_generated_Jobs_TestIamPermissions_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -37,7 +37,7 @@ def sample_test_iam_permissions(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) request = iam_policy_pb2.TestIamPermissionsRequest( @@ -51,4 +51,4 @@ def sample_test_iam_permissions(): # Handle the response print(response) -# [END run_v2_generated_Services_TestIamPermissions_sync_048b00bc] +# [END run_v2_generated_Jobs_TestIamPermissions_sync] diff --git a/samples/generated_samples/run_v2_generated_revisions_delete_revision_sync_d74b55e0.py b/samples/generated_samples/run_v2_generated_jobs_update_job_async.py similarity index 78% rename from samples/generated_samples/run_v2_generated_revisions_delete_revision_sync_d74b55e0.py rename to samples/generated_samples/run_v2_generated_jobs_update_job_async.py index 55cea76..e8659dc 100644 --- a/samples/generated_samples/run_v2_generated_revisions_delete_revision_sync_d74b55e0.py +++ b/samples/generated_samples/run_v2_generated_jobs_update_job_async.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for DeleteRevision +# Snippet for UpdateJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Revisions_DeleteRevision_sync_d74b55e0] +# [START run_v2_generated_Jobs_UpdateJob_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,23 +34,26 @@ from google.cloud import run_v2 -def sample_delete_revision(): +async def sample_update_job(): # Create a client - client = run_v2.RevisionsClient() + client = run_v2.JobsAsyncClient() # Initialize request argument(s) - request = run_v2.DeleteRevisionRequest( - name="name_value", + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.UpdateJobRequest( + job=job, ) # Make the request - operation = client.delete_revision(request=request) + operation = client.update_job(request=request) print("Waiting for operation to complete...") - response = operation.result() + response = (await operation).result() # Handle the response print(response) -# [END run_v2_generated_Revisions_DeleteRevision_sync_d74b55e0] +# [END run_v2_generated_Jobs_UpdateJob_async] diff --git a/samples/generated_samples/run_v2_generated_services_update_service_sync_9076a854.py b/samples/generated_samples/run_v2_generated_jobs_update_job_sync.py similarity index 81% rename from samples/generated_samples/run_v2_generated_services_update_service_sync_9076a854.py rename to samples/generated_samples/run_v2_generated_jobs_update_job_sync.py index 37a8fe6..f82e959 100644 --- a/samples/generated_samples/run_v2_generated_services_update_service_sync_9076a854.py +++ b/samples/generated_samples/run_v2_generated_jobs_update_job_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for UpdateService +# Snippet for UpdateJob # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Services_UpdateService_sync_9076a854] +# [START run_v2_generated_Jobs_UpdateJob_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,16 +34,20 @@ from google.cloud import run_v2 -def sample_update_service(): +def sample_update_job(): # Create a client - client = run_v2.ServicesClient() + client = run_v2.JobsClient() # Initialize request argument(s) - request = run_v2.UpdateServiceRequest( + job = run_v2.Job() + job.template.template.max_retries = 1187 + + request = run_v2.UpdateJobRequest( + job=job, ) # Make the request - operation = client.update_service(request=request) + operation = client.update_job(request=request) print("Waiting for operation to complete...") @@ -52,4 +56,4 @@ def sample_update_service(): # Handle the response print(response) -# [END run_v2_generated_Services_UpdateService_sync_9076a854] +# [END run_v2_generated_Jobs_UpdateJob_sync] diff --git a/samples/generated_samples/run_v2_generated_revisions_delete_revision_async.py b/samples/generated_samples/run_v2_generated_revisions_delete_revision_async.py index 3587493..da85a44 100644 --- a/samples/generated_samples/run_v2_generated_revisions_delete_revision_async.py +++ b/samples/generated_samples/run_v2_generated_revisions_delete_revision_async.py @@ -48,7 +48,7 @@ async def sample_delete_revision(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) diff --git a/samples/generated_samples/run_v2_generated_services_create_service_async.py b/samples/generated_samples/run_v2_generated_services_create_service_async.py index c69136a..727df54 100644 --- a/samples/generated_samples/run_v2_generated_services_create_service_async.py +++ b/samples/generated_samples/run_v2_generated_services_create_service_async.py @@ -49,7 +49,7 @@ async def sample_create_service(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) diff --git a/samples/generated_samples/run_v2_generated_services_delete_service_async.py b/samples/generated_samples/run_v2_generated_services_delete_service_async.py index 961cc31..8317c12 100644 --- a/samples/generated_samples/run_v2_generated_services_delete_service_async.py +++ b/samples/generated_samples/run_v2_generated_services_delete_service_async.py @@ -48,7 +48,7 @@ async def sample_delete_service(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) diff --git a/samples/generated_samples/run_v2_generated_services_update_service_async.py b/samples/generated_samples/run_v2_generated_services_update_service_async.py index 9e49ee6..02a1f3f 100644 --- a/samples/generated_samples/run_v2_generated_services_update_service_async.py +++ b/samples/generated_samples/run_v2_generated_services_update_service_async.py @@ -47,7 +47,7 @@ async def sample_update_service(): print("Waiting for operation to complete...") - response = await operation.result() + response = (await operation).result() # Handle the response print(response) diff --git a/samples/generated_samples/run_v2_generated_revisions_get_revision_sync_e5e5b0ac.py b/samples/generated_samples/run_v2_generated_tasks_get_task_async.py similarity index 82% rename from samples/generated_samples/run_v2_generated_revisions_get_revision_sync_e5e5b0ac.py rename to samples/generated_samples/run_v2_generated_tasks_get_task_async.py index 5eac5cd..5193de3 100644 --- a/samples/generated_samples/run_v2_generated_revisions_get_revision_sync_e5e5b0ac.py +++ b/samples/generated_samples/run_v2_generated_tasks_get_task_async.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for GetRevision +# Snippet for GetTask # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Revisions_GetRevision_sync_e5e5b0ac] +# [START run_v2_generated_Tasks_GetTask_async] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,19 +34,19 @@ from google.cloud import run_v2 -def sample_get_revision(): +async def sample_get_task(): # Create a client - client = run_v2.RevisionsClient() + client = run_v2.TasksAsyncClient() # Initialize request argument(s) - request = run_v2.GetRevisionRequest( + request = run_v2.GetTaskRequest( name="name_value", ) # Make the request - response = client.get_revision(request=request) + response = await client.get_task(request=request) # Handle the response print(response) -# [END run_v2_generated_Revisions_GetRevision_sync_e5e5b0ac] +# [END run_v2_generated_Tasks_GetTask_async] diff --git a/samples/generated_samples/run_v2_generated_tasks_get_task_sync.py b/samples/generated_samples/run_v2_generated_tasks_get_task_sync.py new file mode 100644 index 0000000..e58057f --- /dev/null +++ b/samples/generated_samples/run_v2_generated_tasks_get_task_sync.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for GetTask +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-run + + +# [START run_v2_generated_Tasks_GetTask_sync] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import run_v2 + + +def sample_get_task(): + # Create a client + client = run_v2.TasksClient() + + # Initialize request argument(s) + request = run_v2.GetTaskRequest( + name="name_value", + ) + + # Make the request + response = client.get_task(request=request) + + # Handle the response + print(response) + +# [END run_v2_generated_Tasks_GetTask_sync] diff --git a/samples/generated_samples/run_v2_generated_tasks_list_tasks_async.py b/samples/generated_samples/run_v2_generated_tasks_list_tasks_async.py new file mode 100644 index 0000000..39d2715 --- /dev/null +++ b/samples/generated_samples/run_v2_generated_tasks_list_tasks_async.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for ListTasks +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-run + + +# [START run_v2_generated_Tasks_ListTasks_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import run_v2 + + +async def sample_list_tasks(): + # Create a client + client = run_v2.TasksAsyncClient() + + # Initialize request argument(s) + request = run_v2.ListTasksRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_tasks(request=request) + + # Handle the response + async for response in page_result: + print(response) + +# [END run_v2_generated_Tasks_ListTasks_async] diff --git a/samples/generated_samples/run_v2_generated_revisions_list_revisions_sync_1d0f1802.py b/samples/generated_samples/run_v2_generated_tasks_list_tasks_sync.py similarity index 82% rename from samples/generated_samples/run_v2_generated_revisions_list_revisions_sync_1d0f1802.py rename to samples/generated_samples/run_v2_generated_tasks_list_tasks_sync.py index 85c3992..32eb357 100644 --- a/samples/generated_samples/run_v2_generated_revisions_list_revisions_sync_1d0f1802.py +++ b/samples/generated_samples/run_v2_generated_tasks_list_tasks_sync.py @@ -15,7 +15,7 @@ # # Generated code. DO NOT EDIT! # -# Snippet for ListRevisions +# Snippet for ListTasks # NOTE: This snippet has been automatically generated for illustrative purposes only. # It may require modifications to work in your environment. @@ -23,7 +23,7 @@ # python3 -m pip install google-cloud-run -# [START run_v2_generated_Revisions_ListRevisions_sync_1d0f1802] +# [START run_v2_generated_Tasks_ListTasks_sync] # This snippet has been automatically generated and should be regarded as a # code template only. # It will require modifications to work: @@ -34,20 +34,20 @@ from google.cloud import run_v2 -def sample_list_revisions(): +def sample_list_tasks(): # Create a client - client = run_v2.RevisionsClient() + client = run_v2.TasksClient() # Initialize request argument(s) - request = run_v2.ListRevisionsRequest( + request = run_v2.ListTasksRequest( parent="parent_value", ) # Make the request - page_result = client.list_revisions(request=request) + page_result = client.list_tasks(request=request) # Handle the response for response in page_result: print(response) -# [END run_v2_generated_Revisions_ListRevisions_sync_1d0f1802] +# [END run_v2_generated_Tasks_ListTasks_sync] diff --git a/samples/generated_samples/snippet_metadata_run_v2.json b/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json similarity index 57% rename from samples/generated_samples/snippet_metadata_run_v2.json rename to samples/generated_samples/snippet_metadata_google.cloud.run.v2.json index 635f790..b6d3982 100644 --- a/samples/generated_samples/snippet_metadata_run_v2.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json @@ -7,7 +7,8 @@ } ], "language": "PYTHON", - "name": "google-cloud-run" + "name": "google-cloud-run", + "version": "0.5.0" }, "snippets": [ { @@ -15,22 +16,22 @@ "clientMethod": { "async": true, "client": { - "fullName": "google.cloud.run_v2.RevisionsAsyncClient", - "shortName": "RevisionsAsyncClient" + "fullName": "google.cloud.run_v2.ExecutionsAsyncClient", + "shortName": "ExecutionsAsyncClient" }, - "fullName": "google.cloud.run_v2.RevisionsAsyncClient.delete_revision", + "fullName": "google.cloud.run_v2.ExecutionsAsyncClient.delete_execution", "method": { - "fullName": "google.cloud.run.v2.Revisions.DeleteRevision", + "fullName": "google.cloud.run.v2.Executions.DeleteExecution", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Executions", + "shortName": "Executions" }, - "shortName": "DeleteRevision" + "shortName": "DeleteExecution" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.DeleteRevisionRequest" + "type": "google.cloud.run_v2.types.DeleteExecutionRequest" }, { "name": "name", @@ -50,13 +51,13 @@ } ], "resultType": "google.api_core.operation_async.AsyncOperation", - "shortName": "delete_revision" + "shortName": "delete_execution" }, - "description": "Sample for DeleteRevision", - "file": "run_v2_generated_revisions_delete_revision_async.py", + "description": "Sample for DeleteExecution", + "file": "run_v2_generated_executions_delete_execution_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_DeleteRevision_async", + "regionTag": "run_v2_generated_Executions_DeleteExecution_async", "segments": [ { "end": 55, @@ -89,28 +90,28 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_delete_revision_async.py" + "title": "run_v2_generated_executions_delete_execution_async.py" }, { "canonical": true, "clientMethod": { "client": { - "fullName": "google.cloud.run_v2.RevisionsClient", - "shortName": "RevisionsClient" + "fullName": "google.cloud.run_v2.ExecutionsClient", + "shortName": "ExecutionsClient" }, - "fullName": "google.cloud.run_v2.RevisionsClient.delete_revision", + "fullName": "google.cloud.run_v2.ExecutionsClient.delete_execution", "method": { - "fullName": "google.cloud.run.v2.Revisions.DeleteRevision", + "fullName": "google.cloud.run.v2.Executions.DeleteExecution", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Executions", + "shortName": "Executions" }, - "shortName": "DeleteRevision" + "shortName": "DeleteExecution" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.DeleteRevisionRequest" + "type": "google.cloud.run_v2.types.DeleteExecutionRequest" }, { "name": "name", @@ -130,13 +131,13 @@ } ], "resultType": "google.api_core.operation.Operation", - "shortName": "delete_revision" + "shortName": "delete_execution" }, - "description": "Sample for DeleteRevision", - "file": "run_v2_generated_revisions_delete_revision_sync_2da46bc2.py", + "description": "Sample for DeleteExecution", + "file": "run_v2_generated_executions_delete_execution_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_DeleteRevision_sync", + "regionTag": "run_v2_generated_Executions_DeleteExecution_sync", "segments": [ { "end": 55, @@ -169,28 +170,29 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_delete_revision_sync_2da46bc2.py" + "title": "run_v2_generated_executions_delete_execution_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.RevisionsClient", - "shortName": "RevisionsClient" + "fullName": "google.cloud.run_v2.ExecutionsAsyncClient", + "shortName": "ExecutionsAsyncClient" }, - "fullName": "google.cloud.run_v2.RevisionsClient.delete_revision", + "fullName": "google.cloud.run_v2.ExecutionsAsyncClient.get_execution", "method": { - "fullName": "google.cloud.run.v2.Revisions.DeleteRevision", + "fullName": "google.cloud.run.v2.Executions.GetExecution", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Executions", + "shortName": "Executions" }, - "shortName": "DeleteRevision" + "shortName": "GetExecution" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.DeleteRevisionRequest" + "type": "google.cloud.run_v2.types.GetExecutionRequest" }, { "name": "name", @@ -209,22 +211,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation.Operation", - "shortName": "delete_revision" + "resultType": "google.cloud.run_v2.types.Execution", + "shortName": "get_execution" }, - "description": "Sample for DeleteRevision", - "file": "run_v2_generated_revisions_delete_revision_sync_d74b55e0.py", + "description": "Sample for GetExecution", + "file": "run_v2_generated_executions_get_execution_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_DeleteRevision_sync", + "regionTag": "run_v2_generated_Executions_GetExecution_async", "segments": [ { - "end": 55, + "end": 51, "start": 27, "type": "FULL" }, { - "end": 55, + "end": 51, "start": 27, "type": "SHORT" }, @@ -239,39 +241,38 @@ "type": "REQUEST_INITIALIZATION" }, { - "end": 52, + "end": 48, "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 56, - "start": 53, + "end": 52, + "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_delete_revision_sync_d74b55e0.py" + "title": "run_v2_generated_executions_get_execution_async.py" }, { "canonical": true, "clientMethod": { - "async": true, "client": { - "fullName": "google.cloud.run_v2.RevisionsAsyncClient", - "shortName": "RevisionsAsyncClient" + "fullName": "google.cloud.run_v2.ExecutionsClient", + "shortName": "ExecutionsClient" }, - "fullName": "google.cloud.run_v2.RevisionsAsyncClient.get_revision", + "fullName": "google.cloud.run_v2.ExecutionsClient.get_execution", "method": { - "fullName": "google.cloud.run.v2.Revisions.GetRevision", + "fullName": "google.cloud.run.v2.Executions.GetExecution", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Executions", + "shortName": "Executions" }, - "shortName": "GetRevision" + "shortName": "GetExecution" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.GetRevisionRequest" + "type": "google.cloud.run_v2.types.GetExecutionRequest" }, { "name": "name", @@ -290,14 +291,14 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.types.Revision", - "shortName": "get_revision" + "resultType": "google.cloud.run_v2.types.Execution", + "shortName": "get_execution" }, - "description": "Sample for GetRevision", - "file": "run_v2_generated_revisions_get_revision_async.py", + "description": "Sample for GetExecution", + "file": "run_v2_generated_executions_get_execution_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_GetRevision_async", + "regionTag": "run_v2_generated_Executions_GetExecution_sync", "segments": [ { "end": 51, @@ -330,31 +331,32 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_get_revision_async.py" + "title": "run_v2_generated_executions_get_execution_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.RevisionsClient", - "shortName": "RevisionsClient" + "fullName": "google.cloud.run_v2.ExecutionsAsyncClient", + "shortName": "ExecutionsAsyncClient" }, - "fullName": "google.cloud.run_v2.RevisionsClient.get_revision", + "fullName": "google.cloud.run_v2.ExecutionsAsyncClient.list_executions", "method": { - "fullName": "google.cloud.run.v2.Revisions.GetRevision", + "fullName": "google.cloud.run.v2.Executions.ListExecutions", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Executions", + "shortName": "Executions" }, - "shortName": "GetRevision" + "shortName": "ListExecutions" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.GetRevisionRequest" + "type": "google.cloud.run_v2.types.ListExecutionsRequest" }, { - "name": "name", + "name": "parent", "type": "str" }, { @@ -370,22 +372,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.types.Revision", - "shortName": "get_revision" + "resultType": "google.cloud.run_v2.services.executions.pagers.ListExecutionsAsyncPager", + "shortName": "list_executions" }, - "description": "Sample for GetRevision", - "file": "run_v2_generated_revisions_get_revision_sync_115a25ad.py", + "description": "Sample for ListExecutions", + "file": "run_v2_generated_executions_list_executions_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_GetRevision_sync", + "regionTag": "run_v2_generated_Executions_ListExecutions_async", "segments": [ { - "end": 51, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 51, + "end": 52, "start": 27, "type": "SHORT" }, @@ -405,36 +407,36 @@ "type": "REQUEST_EXECUTION" }, { - "end": 52, + "end": 53, "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_get_revision_sync_115a25ad.py" + "title": "run_v2_generated_executions_list_executions_async.py" }, { "canonical": true, "clientMethod": { "client": { - "fullName": "google.cloud.run_v2.RevisionsClient", - "shortName": "RevisionsClient" + "fullName": "google.cloud.run_v2.ExecutionsClient", + "shortName": "ExecutionsClient" }, - "fullName": "google.cloud.run_v2.RevisionsClient.get_revision", + "fullName": "google.cloud.run_v2.ExecutionsClient.list_executions", "method": { - "fullName": "google.cloud.run.v2.Revisions.GetRevision", + "fullName": "google.cloud.run.v2.Executions.ListExecutions", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Executions", + "shortName": "Executions" }, - "shortName": "GetRevision" + "shortName": "ListExecutions" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.GetRevisionRequest" + "type": "google.cloud.run_v2.types.ListExecutionsRequest" }, { - "name": "name", + "name": "parent", "type": "str" }, { @@ -450,22 +452,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.types.Revision", - "shortName": "get_revision" + "resultType": "google.cloud.run_v2.services.executions.pagers.ListExecutionsPager", + "shortName": "list_executions" }, - "description": "Sample for GetRevision", - "file": "run_v2_generated_revisions_get_revision_sync_e5e5b0ac.py", + "description": "Sample for ListExecutions", + "file": "run_v2_generated_executions_list_executions_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_GetRevision_sync", + "regionTag": "run_v2_generated_Executions_ListExecutions_sync", "segments": [ { - "end": 51, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 51, + "end": 52, "start": 27, "type": "SHORT" }, @@ -485,39 +487,47 @@ "type": "REQUEST_EXECUTION" }, { - "end": 52, + "end": 53, "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_get_revision_sync_e5e5b0ac.py" + "title": "run_v2_generated_executions_list_executions_sync.py" }, { "canonical": true, "clientMethod": { "async": true, "client": { - "fullName": "google.cloud.run_v2.RevisionsAsyncClient", - "shortName": "RevisionsAsyncClient" + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" }, - "fullName": "google.cloud.run_v2.RevisionsAsyncClient.list_revisions", + "fullName": "google.cloud.run_v2.JobsAsyncClient.create_job", "method": { - "fullName": "google.cloud.run.v2.Revisions.ListRevisions", + "fullName": "google.cloud.run.v2.Jobs.CreateJob", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" }, - "shortName": "ListRevisions" + "shortName": "CreateJob" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.ListRevisionsRequest" + "type": "google.cloud.run_v2.types.CreateJobRequest" }, { "name": "parent", "type": "str" }, + { + "name": "job", + "type": "google.cloud.run_v2.types.Job" + }, + { + "name": "job_id", + "type": "str" + }, { "name": "retry", "type": "google.api_core.retry.Retry" @@ -531,22 +541,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.services.revisions.pagers.ListRevisionsAsyncPager", - "shortName": "list_revisions" + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "create_job" }, - "description": "Sample for ListRevisions", - "file": "run_v2_generated_revisions_list_revisions_async.py", + "description": "Sample for CreateJob", + "file": "run_v2_generated_jobs_create_job_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_ListRevisions_async", + "regionTag": "run_v2_generated_Jobs_CreateJob_async", "segments": [ { - "end": 52, + "end": 60, "start": 27, "type": "FULL" }, { - "end": 52, + "end": 60, "start": 27, "type": "SHORT" }, @@ -556,48 +566,56 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 45, + "end": 50, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 48, - "start": 46, + "end": 57, + "start": 51, "type": "REQUEST_EXECUTION" }, { - "end": 53, - "start": 49, + "end": 61, + "start": 58, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_list_revisions_async.py" + "title": "run_v2_generated_jobs_create_job_async.py" }, { "canonical": true, "clientMethod": { "client": { - "fullName": "google.cloud.run_v2.RevisionsClient", - "shortName": "RevisionsClient" + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" }, - "fullName": "google.cloud.run_v2.RevisionsClient.list_revisions", + "fullName": "google.cloud.run_v2.JobsClient.create_job", "method": { - "fullName": "google.cloud.run.v2.Revisions.ListRevisions", + "fullName": "google.cloud.run.v2.Jobs.CreateJob", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" }, - "shortName": "ListRevisions" + "shortName": "CreateJob" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.ListRevisionsRequest" + "type": "google.cloud.run_v2.types.CreateJobRequest" }, { "name": "parent", "type": "str" }, + { + "name": "job", + "type": "google.cloud.run_v2.types.Job" + }, + { + "name": "job_id", + "type": "str" + }, { "name": "retry", "type": "google.api_core.retry.Retry" @@ -611,22 +629,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.services.revisions.pagers.ListRevisionsPager", - "shortName": "list_revisions" + "resultType": "google.api_core.operation.Operation", + "shortName": "create_job" }, - "description": "Sample for ListRevisions", - "file": "run_v2_generated_revisions_list_revisions_sync_1d0f1802.py", + "description": "Sample for CreateJob", + "file": "run_v2_generated_jobs_create_job_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_ListRevisions_sync", + "regionTag": "run_v2_generated_Jobs_CreateJob_sync", "segments": [ { - "end": 52, + "end": 60, "start": 27, "type": "FULL" }, { - "end": 52, + "end": 60, "start": 27, "type": "SHORT" }, @@ -636,46 +654,47 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 45, + "end": 50, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 48, - "start": 46, + "end": 57, + "start": 51, "type": "REQUEST_EXECUTION" }, { - "end": 53, - "start": 49, + "end": 61, + "start": 58, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_list_revisions_sync_1d0f1802.py" + "title": "run_v2_generated_jobs_create_job_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.RevisionsClient", - "shortName": "RevisionsClient" + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" }, - "fullName": "google.cloud.run_v2.RevisionsClient.list_revisions", + "fullName": "google.cloud.run_v2.JobsAsyncClient.delete_job", "method": { - "fullName": "google.cloud.run.v2.Revisions.ListRevisions", + "fullName": "google.cloud.run.v2.Jobs.DeleteJob", "service": { - "fullName": "google.cloud.run.v2.Revisions", - "shortName": "Revisions" + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" }, - "shortName": "ListRevisions" + "shortName": "DeleteJob" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.ListRevisionsRequest" + "type": "google.cloud.run_v2.types.DeleteJobRequest" }, { - "name": "parent", + "name": "name", "type": "str" }, { @@ -691,22 +710,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.services.revisions.pagers.ListRevisionsPager", - "shortName": "list_revisions" + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "delete_job" }, - "description": "Sample for ListRevisions", - "file": "run_v2_generated_revisions_list_revisions_sync_2312de2e.py", + "description": "Sample for DeleteJob", + "file": "run_v2_generated_jobs_delete_job_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Revisions_ListRevisions_sync", + "regionTag": "run_v2_generated_Jobs_DeleteJob_async", "segments": [ { - "end": 52, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 52, + "end": 55, "start": 27, "type": "SHORT" }, @@ -721,50 +740,41 @@ "type": "REQUEST_INITIALIZATION" }, { - "end": 48, + "end": 52, "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 53, - "start": 49, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_revisions_list_revisions_sync_2312de2e.py" + "title": "run_v2_generated_jobs_delete_job_async.py" }, { "canonical": true, "clientMethod": { - "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesAsyncClient", - "shortName": "ServicesAsyncClient" + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" }, - "fullName": "google.cloud.run_v2.ServicesAsyncClient.create_service", + "fullName": "google.cloud.run_v2.JobsClient.delete_job", "method": { - "fullName": "google.cloud.run.v2.Services.CreateService", + "fullName": "google.cloud.run.v2.Jobs.DeleteJob", "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" }, - "shortName": "CreateService" + "shortName": "DeleteJob" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.CreateServiceRequest" - }, - { - "name": "parent", - "type": "str" + "type": "google.cloud.run_v2.types.DeleteJobRequest" }, { - "name": "service", - "type": "google.cloud.run_v2.types.Service" - }, - { - "name": "service_id", + "name": "name", "type": "str" }, { @@ -780,22 +790,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation_async.AsyncOperation", - "shortName": "create_service" + "resultType": "google.api_core.operation.Operation", + "shortName": "delete_job" }, - "description": "Sample for CreateService", - "file": "run_v2_generated_services_create_service_async.py", + "description": "Sample for DeleteJob", + "file": "run_v2_generated_jobs_delete_job_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_CreateService_async", + "regionTag": "run_v2_generated_Jobs_DeleteJob_sync", "segments": [ { - "end": 56, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 56, + "end": 55, "start": 27, "type": "SHORT" }, @@ -805,55 +815,44 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 46, + "end": 45, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 53, - "start": 47, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 57, - "start": 54, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_create_service_async.py" + "title": "run_v2_generated_jobs_delete_job_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.create_service", + "fullName": "google.cloud.run_v2.JobsAsyncClient.get_iam_policy", "method": { - "fullName": "google.cloud.run.v2.Services.CreateService", + "fullName": "google.cloud.run.v2.Jobs.GetIamPolicy", "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" }, - "shortName": "CreateService" + "shortName": "GetIamPolicy" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.CreateServiceRequest" - }, - { - "name": "parent", - "type": "str" - }, - { - "name": "service", - "type": "google.cloud.run_v2.types.Service" - }, - { - "name": "service_id", - "type": "str" + "type": "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest" }, { "name": "retry", @@ -868,22 +867,1370 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation.Operation", - "shortName": "create_service" + "resultType": "google.iam.v1.policy_pb2.Policy", + "shortName": "get_iam_policy" }, - "description": "Sample for CreateService", - "file": "run_v2_generated_services_create_service_sync_8031b824.py", + "description": "Sample for GetIamPolicy", + "file": "run_v2_generated_jobs_get_iam_policy_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_CreateService_sync", + "regionTag": "run_v2_generated_Jobs_GetIamPolicy_async", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 41, + "start": 39, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 46, + "start": 42, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 49, + "start": 47, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 50, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_get_iam_policy_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.get_iam_policy", + "method": { + "fullName": "google.cloud.run.v2.Jobs.GetIamPolicy", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "GetIamPolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.iam.v1.policy_pb2.Policy", + "shortName": "get_iam_policy" + }, + "description": "Sample for GetIamPolicy", + "file": "run_v2_generated_jobs_get_iam_policy_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_GetIamPolicy_sync", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 41, + "start": 39, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 46, + "start": 42, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 49, + "start": 47, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 50, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_get_iam_policy_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" + }, + "fullName": "google.cloud.run_v2.JobsAsyncClient.get_job", + "method": { + "fullName": "google.cloud.run.v2.Jobs.GetJob", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "GetJob" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.GetJobRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.types.Job", + "shortName": "get_job" + }, + "description": "Sample for GetJob", + "file": "run_v2_generated_jobs_get_job_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_GetJob_async", + "segments": [ + { + "end": 51, + "start": 27, + "type": "FULL" + }, + { + "end": 51, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 52, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_get_job_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.get_job", + "method": { + "fullName": "google.cloud.run.v2.Jobs.GetJob", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "GetJob" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.GetJobRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.types.Job", + "shortName": "get_job" + }, + "description": "Sample for GetJob", + "file": "run_v2_generated_jobs_get_job_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_GetJob_sync", + "segments": [ + { + "end": 51, + "start": 27, + "type": "FULL" + }, + { + "end": 51, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 52, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_get_job_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" + }, + "fullName": "google.cloud.run_v2.JobsAsyncClient.list_jobs", + "method": { + "fullName": "google.cloud.run.v2.Jobs.ListJobs", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "ListJobs" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.ListJobsRequest" + }, + { + "name": "parent", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.services.jobs.pagers.ListJobsAsyncPager", + "shortName": "list_jobs" + }, + "description": "Sample for ListJobs", + "file": "run_v2_generated_jobs_list_jobs_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_ListJobs_async", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_list_jobs_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.list_jobs", + "method": { + "fullName": "google.cloud.run.v2.Jobs.ListJobs", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "ListJobs" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.ListJobsRequest" + }, + { + "name": "parent", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.services.jobs.pagers.ListJobsPager", + "shortName": "list_jobs" + }, + "description": "Sample for ListJobs", + "file": "run_v2_generated_jobs_list_jobs_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_ListJobs_sync", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_list_jobs_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" + }, + "fullName": "google.cloud.run_v2.JobsAsyncClient.run_job", + "method": { + "fullName": "google.cloud.run.v2.Jobs.RunJob", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "RunJob" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.RunJobRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "run_job" + }, + "description": "Sample for RunJob", + "file": "run_v2_generated_jobs_run_job_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_RunJob_async", + "segments": [ + { + "end": 55, + "start": 27, + "type": "FULL" + }, + { + "end": 55, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 52, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 56, + "start": 53, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_run_job_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.run_job", + "method": { + "fullName": "google.cloud.run.v2.Jobs.RunJob", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "RunJob" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.RunJobRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.api_core.operation.Operation", + "shortName": "run_job" + }, + "description": "Sample for RunJob", + "file": "run_v2_generated_jobs_run_job_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_RunJob_sync", + "segments": [ + { + "end": 55, + "start": 27, + "type": "FULL" + }, + { + "end": 55, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 52, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 56, + "start": 53, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_run_job_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" + }, + "fullName": "google.cloud.run_v2.JobsAsyncClient.set_iam_policy", + "method": { + "fullName": "google.cloud.run.v2.Jobs.SetIamPolicy", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "SetIamPolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.iam.v1.iam_policy_pb2.SetIamPolicyRequest" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.iam.v1.policy_pb2.Policy", + "shortName": "set_iam_policy" + }, + "description": "Sample for SetIamPolicy", + "file": "run_v2_generated_jobs_set_iam_policy_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_SetIamPolicy_async", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 41, + "start": 39, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 46, + "start": 42, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 49, + "start": 47, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 50, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_set_iam_policy_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.set_iam_policy", + "method": { + "fullName": "google.cloud.run.v2.Jobs.SetIamPolicy", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "SetIamPolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.iam.v1.iam_policy_pb2.SetIamPolicyRequest" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.iam.v1.policy_pb2.Policy", + "shortName": "set_iam_policy" + }, + "description": "Sample for SetIamPolicy", + "file": "run_v2_generated_jobs_set_iam_policy_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_SetIamPolicy_sync", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 41, + "start": 39, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 46, + "start": 42, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 49, + "start": 47, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 50, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_set_iam_policy_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" + }, + "fullName": "google.cloud.run_v2.JobsAsyncClient.test_iam_permissions", + "method": { + "fullName": "google.cloud.run.v2.Jobs.TestIamPermissions", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "TestIamPermissions" + }, + "parameters": [ + { + "name": "request", + "type": "google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.iam.v1.iam_policy_pb2.TestIamPermissionsResponse", + "shortName": "test_iam_permissions" + }, + "description": "Sample for TestIamPermissions", + "file": "run_v2_generated_jobs_test_iam_permissions_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_TestIamPermissions_async", + "segments": [ + { + "end": 53, + "start": 27, + "type": "FULL" + }, + { + "end": 53, + "start": 27, + "type": "SHORT" + }, + { + "end": 41, + "start": 39, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 47, + "start": 42, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 50, + "start": 48, + "type": "REQUEST_EXECUTION" + }, + { + "end": 54, + "start": 51, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_test_iam_permissions_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.test_iam_permissions", + "method": { + "fullName": "google.cloud.run.v2.Jobs.TestIamPermissions", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "TestIamPermissions" + }, + "parameters": [ + { + "name": "request", + "type": "google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.iam.v1.iam_policy_pb2.TestIamPermissionsResponse", + "shortName": "test_iam_permissions" + }, + "description": "Sample for TestIamPermissions", + "file": "run_v2_generated_jobs_test_iam_permissions_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_TestIamPermissions_sync", + "segments": [ + { + "end": 53, + "start": 27, + "type": "FULL" + }, + { + "end": 53, + "start": 27, + "type": "SHORT" + }, + { + "end": 41, + "start": 39, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 47, + "start": 42, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 50, + "start": 48, + "type": "REQUEST_EXECUTION" + }, + { + "end": 54, + "start": 51, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_test_iam_permissions_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.JobsAsyncClient", + "shortName": "JobsAsyncClient" + }, + "fullName": "google.cloud.run_v2.JobsAsyncClient.update_job", + "method": { + "fullName": "google.cloud.run.v2.Jobs.UpdateJob", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "UpdateJob" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.UpdateJobRequest" + }, + { + "name": "job", + "type": "google.cloud.run_v2.types.Job" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "update_job" + }, + "description": "Sample for UpdateJob", + "file": "run_v2_generated_jobs_update_job_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_UpdateJob_async", + "segments": [ + { + "end": 58, + "start": 27, + "type": "FULL" + }, + { + "end": 58, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 48, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 55, + "start": 49, + "type": "REQUEST_EXECUTION" + }, + { + "end": 59, + "start": 56, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_update_job_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.JobsClient", + "shortName": "JobsClient" + }, + "fullName": "google.cloud.run_v2.JobsClient.update_job", + "method": { + "fullName": "google.cloud.run.v2.Jobs.UpdateJob", + "service": { + "fullName": "google.cloud.run.v2.Jobs", + "shortName": "Jobs" + }, + "shortName": "UpdateJob" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.UpdateJobRequest" + }, + { + "name": "job", + "type": "google.cloud.run_v2.types.Job" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.api_core.operation.Operation", + "shortName": "update_job" + }, + "description": "Sample for UpdateJob", + "file": "run_v2_generated_jobs_update_job_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Jobs_UpdateJob_sync", + "segments": [ + { + "end": 58, + "start": 27, + "type": "FULL" + }, + { + "end": 58, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 48, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 55, + "start": 49, + "type": "REQUEST_EXECUTION" + }, + { + "end": 59, + "start": 56, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_jobs_update_job_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.RevisionsAsyncClient", + "shortName": "RevisionsAsyncClient" + }, + "fullName": "google.cloud.run_v2.RevisionsAsyncClient.delete_revision", + "method": { + "fullName": "google.cloud.run.v2.Revisions.DeleteRevision", + "service": { + "fullName": "google.cloud.run.v2.Revisions", + "shortName": "Revisions" + }, + "shortName": "DeleteRevision" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.DeleteRevisionRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "delete_revision" + }, + "description": "Sample for DeleteRevision", + "file": "run_v2_generated_revisions_delete_revision_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Revisions_DeleteRevision_async", + "segments": [ + { + "end": 55, + "start": 27, + "type": "FULL" + }, + { + "end": 55, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 52, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 56, + "start": 53, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_revisions_delete_revision_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.RevisionsClient", + "shortName": "RevisionsClient" + }, + "fullName": "google.cloud.run_v2.RevisionsClient.delete_revision", + "method": { + "fullName": "google.cloud.run.v2.Revisions.DeleteRevision", + "service": { + "fullName": "google.cloud.run.v2.Revisions", + "shortName": "Revisions" + }, + "shortName": "DeleteRevision" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.DeleteRevisionRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.api_core.operation.Operation", + "shortName": "delete_revision" + }, + "description": "Sample for DeleteRevision", + "file": "run_v2_generated_revisions_delete_revision_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Revisions_DeleteRevision_sync", + "segments": [ + { + "end": 55, + "start": 27, + "type": "FULL" + }, + { + "end": 55, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 52, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 56, + "start": 53, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_revisions_delete_revision_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.run_v2.RevisionsAsyncClient", + "shortName": "RevisionsAsyncClient" + }, + "fullName": "google.cloud.run_v2.RevisionsAsyncClient.get_revision", + "method": { + "fullName": "google.cloud.run.v2.Revisions.GetRevision", + "service": { + "fullName": "google.cloud.run.v2.Revisions", + "shortName": "Revisions" + }, + "shortName": "GetRevision" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.GetRevisionRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.types.Revision", + "shortName": "get_revision" + }, + "description": "Sample for GetRevision", + "file": "run_v2_generated_revisions_get_revision_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Revisions_GetRevision_async", + "segments": [ + { + "end": 51, + "start": 27, + "type": "FULL" + }, + { + "end": 51, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 52, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_revisions_get_revision_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.RevisionsClient", + "shortName": "RevisionsClient" + }, + "fullName": "google.cloud.run_v2.RevisionsClient.get_revision", + "method": { + "fullName": "google.cloud.run.v2.Revisions.GetRevision", + "service": { + "fullName": "google.cloud.run.v2.Revisions", + "shortName": "Revisions" + }, + "shortName": "GetRevision" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.GetRevisionRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.types.Revision", + "shortName": "get_revision" + }, + "description": "Sample for GetRevision", + "file": "run_v2_generated_revisions_get_revision_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Revisions_GetRevision_sync", "segments": [ { - "end": 56, + "end": 51, "start": 27, "type": "FULL" }, { - "end": 56, + "end": 51, "start": 27, "type": "SHORT" }, @@ -893,56 +2240,49 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 46, + "end": 45, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 53, - "start": 47, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 57, - "start": 54, + "end": 52, + "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_create_service_sync_8031b824.py" + "title": "run_v2_generated_revisions_get_revision_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.RevisionsAsyncClient", + "shortName": "RevisionsAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.create_service", + "fullName": "google.cloud.run_v2.RevisionsAsyncClient.list_revisions", "method": { - "fullName": "google.cloud.run.v2.Services.CreateService", + "fullName": "google.cloud.run.v2.Revisions.ListRevisions", "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" + "fullName": "google.cloud.run.v2.Revisions", + "shortName": "Revisions" }, - "shortName": "CreateService" + "shortName": "ListRevisions" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.CreateServiceRequest" + "type": "google.cloud.run_v2.types.ListRevisionsRequest" }, { "name": "parent", "type": "str" }, - { - "name": "service", - "type": "google.cloud.run_v2.types.Service" - }, - { - "name": "service_id", - "type": "str" - }, { "name": "retry", "type": "google.api_core.retry.Retry" @@ -956,22 +2296,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation.Operation", - "shortName": "create_service" + "resultType": "google.cloud.run_v2.services.revisions.pagers.ListRevisionsAsyncPager", + "shortName": "list_revisions" }, - "description": "Sample for CreateService", - "file": "run_v2_generated_services_create_service_sync_3c405c33.py", + "description": "Sample for ListRevisions", + "file": "run_v2_generated_revisions_list_revisions_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_CreateService_sync", + "regionTag": "run_v2_generated_Revisions_ListRevisions_async", "segments": [ { - "end": 56, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 56, + "end": 52, "start": 27, "type": "SHORT" }, @@ -981,47 +2321,46 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 46, + "end": 45, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 53, - "start": 47, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 57, - "start": 54, + "end": 53, + "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_create_service_sync_3c405c33.py" + "title": "run_v2_generated_revisions_list_revisions_async.py" }, { "canonical": true, "clientMethod": { - "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesAsyncClient", - "shortName": "ServicesAsyncClient" + "fullName": "google.cloud.run_v2.RevisionsClient", + "shortName": "RevisionsClient" }, - "fullName": "google.cloud.run_v2.ServicesAsyncClient.delete_service", + "fullName": "google.cloud.run_v2.RevisionsClient.list_revisions", "method": { - "fullName": "google.cloud.run.v2.Services.DeleteService", + "fullName": "google.cloud.run.v2.Revisions.ListRevisions", "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" + "fullName": "google.cloud.run.v2.Revisions", + "shortName": "Revisions" }, - "shortName": "DeleteService" + "shortName": "ListRevisions" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.DeleteServiceRequest" + "type": "google.cloud.run_v2.types.ListRevisionsRequest" }, { - "name": "name", + "name": "parent", "type": "str" }, { @@ -1037,22 +2376,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation_async.AsyncOperation", - "shortName": "delete_service" + "resultType": "google.cloud.run_v2.services.revisions.pagers.ListRevisionsPager", + "shortName": "list_revisions" }, - "description": "Sample for DeleteService", - "file": "run_v2_generated_services_delete_service_async.py", + "description": "Sample for ListRevisions", + "file": "run_v2_generated_revisions_list_revisions_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_DeleteService_async", + "regionTag": "run_v2_generated_Revisions_ListRevisions_sync", "segments": [ { - "end": 55, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 55, + "end": 52, "start": 27, "type": "SHORT" }, @@ -1067,41 +2406,50 @@ "type": "REQUEST_INITIALIZATION" }, { - "end": 52, + "end": 48, "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 56, - "start": 53, + "end": 53, + "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_delete_service_async.py" + "title": "run_v2_generated_revisions_list_revisions_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.ServicesAsyncClient", + "shortName": "ServicesAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.delete_service", + "fullName": "google.cloud.run_v2.ServicesAsyncClient.create_service", "method": { - "fullName": "google.cloud.run.v2.Services.DeleteService", + "fullName": "google.cloud.run.v2.Services.CreateService", "service": { "fullName": "google.cloud.run.v2.Services", "shortName": "Services" }, - "shortName": "DeleteService" + "shortName": "CreateService" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.DeleteServiceRequest" + "type": "google.cloud.run_v2.types.CreateServiceRequest" }, { - "name": "name", + "name": "parent", + "type": "str" + }, + { + "name": "service", + "type": "google.cloud.run_v2.types.Service" + }, + { + "name": "service_id", "type": "str" }, { @@ -1117,22 +2465,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation.Operation", - "shortName": "delete_service" + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "create_service" }, - "description": "Sample for DeleteService", - "file": "run_v2_generated_services_delete_service_sync_9c99d0a2.py", + "description": "Sample for CreateService", + "file": "run_v2_generated_services_create_service_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_DeleteService_sync", + "regionTag": "run_v2_generated_Services_CreateService_async", "segments": [ { - "end": 55, + "end": 56, "start": 27, "type": "FULL" }, { - "end": 55, + "end": 56, "start": 27, "type": "SHORT" }, @@ -1142,22 +2490,22 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 45, + "end": 46, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 52, - "start": 46, + "end": 53, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 56, - "start": 53, + "end": 57, + "start": 54, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_delete_service_sync_9c99d0a2.py" + "title": "run_v2_generated_services_create_service_async.py" }, { "canonical": true, @@ -1166,22 +2514,30 @@ "fullName": "google.cloud.run_v2.ServicesClient", "shortName": "ServicesClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.delete_service", + "fullName": "google.cloud.run_v2.ServicesClient.create_service", "method": { - "fullName": "google.cloud.run.v2.Services.DeleteService", + "fullName": "google.cloud.run.v2.Services.CreateService", "service": { "fullName": "google.cloud.run.v2.Services", "shortName": "Services" }, - "shortName": "DeleteService" + "shortName": "CreateService" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.DeleteServiceRequest" + "type": "google.cloud.run_v2.types.CreateServiceRequest" }, { - "name": "name", + "name": "parent", + "type": "str" + }, + { + "name": "service", + "type": "google.cloud.run_v2.types.Service" + }, + { + "name": "service_id", "type": "str" }, { @@ -1198,21 +2554,21 @@ } ], "resultType": "google.api_core.operation.Operation", - "shortName": "delete_service" + "shortName": "create_service" }, - "description": "Sample for DeleteService", - "file": "run_v2_generated_services_delete_service_sync_91d4ca21.py", + "description": "Sample for CreateService", + "file": "run_v2_generated_services_create_service_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_DeleteService_sync", + "regionTag": "run_v2_generated_Services_CreateService_sync", "segments": [ { - "end": 55, + "end": 56, "start": 27, "type": "FULL" }, { - "end": 55, + "end": 56, "start": 27, "type": "SHORT" }, @@ -1222,22 +2578,22 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 45, + "end": 46, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 52, - "start": 46, + "end": 53, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 56, - "start": 53, + "end": 57, + "start": 54, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_delete_service_sync_91d4ca21.py" + "title": "run_v2_generated_services_create_service_sync.py" }, { "canonical": true, @@ -1247,19 +2603,23 @@ "fullName": "google.cloud.run_v2.ServicesAsyncClient", "shortName": "ServicesAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesAsyncClient.get_iam_policy", + "fullName": "google.cloud.run_v2.ServicesAsyncClient.delete_service", "method": { - "fullName": "google.cloud.run.v2.Services.GetIamPolicy", + "fullName": "google.cloud.run.v2.Services.DeleteService", "service": { "fullName": "google.cloud.run.v2.Services", "shortName": "Services" }, - "shortName": "GetIamPolicy" + "shortName": "DeleteService" }, "parameters": [ { "name": "request", - "type": "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest" + "type": "google.cloud.run_v2.types.DeleteServiceRequest" + }, + { + "name": "name", + "type": "str" }, { "name": "retry", @@ -1274,47 +2634,47 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.iam.v1.policy_pb2.Policy", - "shortName": "get_iam_policy" + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "delete_service" }, - "description": "Sample for GetIamPolicy", - "file": "run_v2_generated_services_get_iam_policy_async.py", + "description": "Sample for DeleteService", + "file": "run_v2_generated_services_delete_service_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_GetIamPolicy_async", + "regionTag": "run_v2_generated_Services_DeleteService_async", "segments": [ { - "end": 52, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 52, + "end": 55, "start": 27, "type": "SHORT" }, { - "end": 41, - "start": 39, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 46, - "start": 42, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 49, - "start": 47, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 53, - "start": 50, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_get_iam_policy_async.py" + "title": "run_v2_generated_services_delete_service_async.py" }, { "canonical": true, @@ -1323,19 +2683,23 @@ "fullName": "google.cloud.run_v2.ServicesClient", "shortName": "ServicesClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.get_iam_policy", + "fullName": "google.cloud.run_v2.ServicesClient.delete_service", "method": { - "fullName": "google.cloud.run.v2.Services.GetIamPolicy", + "fullName": "google.cloud.run.v2.Services.DeleteService", "service": { "fullName": "google.cloud.run.v2.Services", "shortName": "Services" }, - "shortName": "GetIamPolicy" + "shortName": "DeleteService" }, "parameters": [ { - "name": "request", - "type": "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest" + "name": "request", + "type": "google.cloud.run_v2.types.DeleteServiceRequest" + }, + { + "name": "name", + "type": "str" }, { "name": "retry", @@ -1350,56 +2714,57 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.iam.v1.policy_pb2.Policy", - "shortName": "get_iam_policy" + "resultType": "google.api_core.operation.Operation", + "shortName": "delete_service" }, - "description": "Sample for GetIamPolicy", - "file": "run_v2_generated_services_get_iam_policy_sync_449f2eb3.py", + "description": "Sample for DeleteService", + "file": "run_v2_generated_services_delete_service_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_GetIamPolicy_sync", + "regionTag": "run_v2_generated_Services_DeleteService_sync", "segments": [ { - "end": 52, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 52, + "end": 55, "start": 27, "type": "SHORT" }, { - "end": 41, - "start": 39, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 46, - "start": 42, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 49, - "start": 47, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 53, - "start": 50, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_get_iam_policy_sync_449f2eb3.py" + "title": "run_v2_generated_services_delete_service_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.ServicesAsyncClient", + "shortName": "ServicesAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.get_iam_policy", + "fullName": "google.cloud.run_v2.ServicesAsyncClient.get_iam_policy", "method": { "fullName": "google.cloud.run.v2.Services.GetIamPolicy", "service": { @@ -1430,10 +2795,10 @@ "shortName": "get_iam_policy" }, "description": "Sample for GetIamPolicy", - "file": "run_v2_generated_services_get_iam_policy_sync_9f45c2a7.py", + "file": "run_v2_generated_services_get_iam_policy_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_GetIamPolicy_sync", + "regionTag": "run_v2_generated_Services_GetIamPolicy_async", "segments": [ { "end": 52, @@ -1466,33 +2831,28 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_get_iam_policy_sync_9f45c2a7.py" + "title": "run_v2_generated_services_get_iam_policy_async.py" }, { "canonical": true, "clientMethod": { - "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesAsyncClient", - "shortName": "ServicesAsyncClient" + "fullName": "google.cloud.run_v2.ServicesClient", + "shortName": "ServicesClient" }, - "fullName": "google.cloud.run_v2.ServicesAsyncClient.get_service", + "fullName": "google.cloud.run_v2.ServicesClient.get_iam_policy", "method": { - "fullName": "google.cloud.run.v2.Services.GetService", + "fullName": "google.cloud.run.v2.Services.GetIamPolicy", "service": { "fullName": "google.cloud.run.v2.Services", "shortName": "Services" }, - "shortName": "GetService" + "shortName": "GetIamPolicy" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.GetServiceRequest" - }, - { - "name": "name", - "type": "str" + "type": "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest" }, { "name": "retry", @@ -1507,56 +2867,57 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.cloud.run_v2.types.Service", - "shortName": "get_service" + "resultType": "google.iam.v1.policy_pb2.Policy", + "shortName": "get_iam_policy" }, - "description": "Sample for GetService", - "file": "run_v2_generated_services_get_service_async.py", + "description": "Sample for GetIamPolicy", + "file": "run_v2_generated_services_get_iam_policy_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_GetService_async", + "regionTag": "run_v2_generated_Services_GetIamPolicy_sync", "segments": [ { - "end": 51, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 51, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 40, - "start": 38, + "end": 41, + "start": 39, "type": "CLIENT_INITIALIZATION" }, { - "end": 45, - "start": 41, + "end": 46, + "start": 42, "type": "REQUEST_INITIALIZATION" }, { - "end": 48, - "start": 46, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 52, - "start": 49, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_get_service_async.py" + "title": "run_v2_generated_services_get_iam_policy_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.ServicesAsyncClient", + "shortName": "ServicesAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.get_service", + "fullName": "google.cloud.run_v2.ServicesAsyncClient.get_service", "method": { "fullName": "google.cloud.run.v2.Services.GetService", "service": { @@ -1591,10 +2952,10 @@ "shortName": "get_service" }, "description": "Sample for GetService", - "file": "run_v2_generated_services_get_service_sync_18284d02.py", + "file": "run_v2_generated_services_get_service_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_GetService_sync", + "regionTag": "run_v2_generated_Services_GetService_async", "segments": [ { "end": 51, @@ -1627,7 +2988,7 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_get_service_sync_18284d02.py" + "title": "run_v2_generated_services_get_service_async.py" }, { "canonical": true, @@ -1671,7 +3032,7 @@ "shortName": "get_service" }, "description": "Sample for GetService", - "file": "run_v2_generated_services_get_service_sync_1c3ef02e.py", + "file": "run_v2_generated_services_get_service_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", "regionTag": "run_v2_generated_Services_GetService_sync", @@ -1707,7 +3068,7 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_get_service_sync_1c3ef02e.py" + "title": "run_v2_generated_services_get_service_sync.py" }, { "canonical": true, @@ -1832,87 +3193,7 @@ "shortName": "list_services" }, "description": "Sample for ListServices", - "file": "run_v2_generated_services_list_services_sync_7dbaf490.py", - "language": "PYTHON", - "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_ListServices_sync", - "segments": [ - { - "end": 52, - "start": 27, - "type": "FULL" - }, - { - "end": 52, - "start": 27, - "type": "SHORT" - }, - { - "end": 40, - "start": 38, - "type": "CLIENT_INITIALIZATION" - }, - { - "end": 45, - "start": 41, - "type": "REQUEST_INITIALIZATION" - }, - { - "end": 48, - "start": 46, - "type": "REQUEST_EXECUTION" - }, - { - "end": 53, - "start": 49, - "type": "RESPONSE_HANDLING" - } - ], - "title": "run_v2_generated_services_list_services_sync_7dbaf490.py" - }, - { - "canonical": true, - "clientMethod": { - "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" - }, - "fullName": "google.cloud.run_v2.ServicesClient.list_services", - "method": { - "fullName": "google.cloud.run.v2.Services.ListServices", - "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" - }, - "shortName": "ListServices" - }, - "parameters": [ - { - "name": "request", - "type": "google.cloud.run_v2.types.ListServicesRequest" - }, - { - "name": "parent", - "type": "str" - }, - { - "name": "retry", - "type": "google.api_core.retry.Retry" - }, - { - "name": "timeout", - "type": "float" - }, - { - "name": "metadata", - "type": "Sequence[Tuple[str, str]" - } - ], - "resultType": "google.cloud.run_v2.services.services.pagers.ListServicesPager", - "shortName": "list_services" - }, - "description": "Sample for ListServices", - "file": "run_v2_generated_services_list_services_sync_c5743712.py", + "file": "run_v2_generated_services_list_services_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", "regionTag": "run_v2_generated_Services_ListServices_sync", @@ -1948,7 +3229,7 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_list_services_sync_c5743712.py" + "title": "run_v2_generated_services_list_services_sync.py" }, { "canonical": true, @@ -1989,86 +3270,10 @@ "shortName": "set_iam_policy" }, "description": "Sample for SetIamPolicy", - "file": "run_v2_generated_services_set_iam_policy_async.py", - "language": "PYTHON", - "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_SetIamPolicy_async", - "segments": [ - { - "end": 52, - "start": 27, - "type": "FULL" - }, - { - "end": 52, - "start": 27, - "type": "SHORT" - }, - { - "end": 41, - "start": 39, - "type": "CLIENT_INITIALIZATION" - }, - { - "end": 46, - "start": 42, - "type": "REQUEST_INITIALIZATION" - }, - { - "end": 49, - "start": 47, - "type": "REQUEST_EXECUTION" - }, - { - "end": 53, - "start": 50, - "type": "RESPONSE_HANDLING" - } - ], - "title": "run_v2_generated_services_set_iam_policy_async.py" - }, - { - "canonical": true, - "clientMethod": { - "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" - }, - "fullName": "google.cloud.run_v2.ServicesClient.set_iam_policy", - "method": { - "fullName": "google.cloud.run.v2.Services.SetIamPolicy", - "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" - }, - "shortName": "SetIamPolicy" - }, - "parameters": [ - { - "name": "request", - "type": "google.iam.v1.iam_policy_pb2.SetIamPolicyRequest" - }, - { - "name": "retry", - "type": "google.api_core.retry.Retry" - }, - { - "name": "timeout", - "type": "float" - }, - { - "name": "metadata", - "type": "Sequence[Tuple[str, str]" - } - ], - "resultType": "google.iam.v1.policy_pb2.Policy", - "shortName": "set_iam_policy" - }, - "description": "Sample for SetIamPolicy", - "file": "run_v2_generated_services_set_iam_policy_sync_b88666d6.py", + "file": "run_v2_generated_services_set_iam_policy_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_SetIamPolicy_sync", + "regionTag": "run_v2_generated_Services_SetIamPolicy_async", "segments": [ { "end": 52, @@ -2101,7 +3306,7 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_set_iam_policy_sync_b88666d6.py" + "title": "run_v2_generated_services_set_iam_policy_async.py" }, { "canonical": true, @@ -2141,7 +3346,7 @@ "shortName": "set_iam_policy" }, "description": "Sample for SetIamPolicy", - "file": "run_v2_generated_services_set_iam_policy_sync_c710ebbc.py", + "file": "run_v2_generated_services_set_iam_policy_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", "regionTag": "run_v2_generated_Services_SetIamPolicy_sync", @@ -2177,7 +3382,7 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_set_iam_policy_sync_c710ebbc.py" + "title": "run_v2_generated_services_set_iam_policy_sync.py" }, { "canonical": true, @@ -2294,7 +3499,7 @@ "shortName": "test_iam_permissions" }, "description": "Sample for TestIamPermissions", - "file": "run_v2_generated_services_test_iam_permissions_sync_7c7fb79b.py", + "file": "run_v2_generated_services_test_iam_permissions_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", "regionTag": "run_v2_generated_Services_TestIamPermissions_sync", @@ -2330,28 +3535,33 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_test_iam_permissions_sync_7c7fb79b.py" + "title": "run_v2_generated_services_test_iam_permissions_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.ServicesAsyncClient", + "shortName": "ServicesAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.test_iam_permissions", + "fullName": "google.cloud.run_v2.ServicesAsyncClient.update_service", "method": { - "fullName": "google.cloud.run.v2.Services.TestIamPermissions", + "fullName": "google.cloud.run.v2.Services.UpdateService", "service": { "fullName": "google.cloud.run.v2.Services", "shortName": "Services" }, - "shortName": "TestIamPermissions" + "shortName": "UpdateService" }, "parameters": [ { "name": "request", - "type": "google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest" + "type": "google.cloud.run_v2.types.UpdateServiceRequest" + }, + { + "name": "service", + "type": "google.cloud.run_v2.types.Service" }, { "name": "retry", @@ -2366,57 +3576,56 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.iam.v1.iam_policy_pb2.TestIamPermissionsResponse", - "shortName": "test_iam_permissions" + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "update_service" }, - "description": "Sample for TestIamPermissions", - "file": "run_v2_generated_services_test_iam_permissions_sync_048b00bc.py", + "description": "Sample for UpdateService", + "file": "run_v2_generated_services_update_service_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_TestIamPermissions_sync", + "regionTag": "run_v2_generated_Services_UpdateService_async", "segments": [ { - "end": 53, + "end": 54, "start": 27, "type": "FULL" }, { - "end": 53, + "end": 54, "start": 27, "type": "SHORT" }, { - "end": 41, - "start": 39, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 47, - "start": 42, + "end": 44, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 50, - "start": 48, + "end": 51, + "start": 45, "type": "REQUEST_EXECUTION" }, { - "end": 54, - "start": 51, + "end": 55, + "start": 52, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_test_iam_permissions_sync_048b00bc.py" + "title": "run_v2_generated_services_update_service_async.py" }, { "canonical": true, "clientMethod": { - "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesAsyncClient", - "shortName": "ServicesAsyncClient" + "fullName": "google.cloud.run_v2.ServicesClient", + "shortName": "ServicesClient" }, - "fullName": "google.cloud.run_v2.ServicesAsyncClient.update_service", + "fullName": "google.cloud.run_v2.ServicesClient.update_service", "method": { "fullName": "google.cloud.run.v2.Services.UpdateService", "service": { @@ -2447,14 +3656,14 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation_async.AsyncOperation", + "resultType": "google.api_core.operation.Operation", "shortName": "update_service" }, "description": "Sample for UpdateService", - "file": "run_v2_generated_services_update_service_async.py", + "file": "run_v2_generated_services_update_service_sync.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_UpdateService_async", + "regionTag": "run_v2_generated_Services_UpdateService_sync", "segments": [ { "end": 54, @@ -2487,32 +3696,33 @@ "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_update_service_async.py" + "title": "run_v2_generated_services_update_service_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.TasksAsyncClient", + "shortName": "TasksAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.update_service", + "fullName": "google.cloud.run_v2.TasksAsyncClient.get_task", "method": { - "fullName": "google.cloud.run.v2.Services.UpdateService", + "fullName": "google.cloud.run.v2.Tasks.GetTask", "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" + "fullName": "google.cloud.run.v2.Tasks", + "shortName": "Tasks" }, - "shortName": "UpdateService" + "shortName": "GetTask" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.UpdateServiceRequest" + "type": "google.cloud.run_v2.types.GetTaskRequest" }, { - "name": "service", - "type": "google.cloud.run_v2.types.Service" + "name": "name", + "type": "str" }, { "name": "retry", @@ -2527,22 +3737,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation.Operation", - "shortName": "update_service" + "resultType": "google.cloud.run_v2.types.Task", + "shortName": "get_task" }, - "description": "Sample for UpdateService", - "file": "run_v2_generated_services_update_service_sync_2652a462.py", + "description": "Sample for GetTask", + "file": "run_v2_generated_tasks_get_task_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_UpdateService_sync", + "regionTag": "run_v2_generated_Tasks_GetTask_async", "segments": [ { - "end": 54, + "end": 51, "start": 27, "type": "FULL" }, { - "end": 54, + "end": 51, "start": 27, "type": "SHORT" }, @@ -2552,47 +3762,128 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 44, + "end": 45, "start": 41, "type": "REQUEST_INITIALIZATION" }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 52, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_tasks_get_task_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.TasksClient", + "shortName": "TasksClient" + }, + "fullName": "google.cloud.run_v2.TasksClient.get_task", + "method": { + "fullName": "google.cloud.run.v2.Tasks.GetTask", + "service": { + "fullName": "google.cloud.run.v2.Tasks", + "shortName": "Tasks" + }, + "shortName": "GetTask" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.GetTaskRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.types.Task", + "shortName": "get_task" + }, + "description": "Sample for GetTask", + "file": "run_v2_generated_tasks_get_task_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Tasks_GetTask_sync", + "segments": [ + { + "end": 51, + "start": 27, + "type": "FULL" + }, { "end": 51, - "start": 45, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 55, - "start": 52, + "end": 52, + "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_update_service_sync_2652a462.py" + "title": "run_v2_generated_tasks_get_task_sync.py" }, { "canonical": true, "clientMethod": { + "async": true, "client": { - "fullName": "google.cloud.run_v2.ServicesClient", - "shortName": "ServicesClient" + "fullName": "google.cloud.run_v2.TasksAsyncClient", + "shortName": "TasksAsyncClient" }, - "fullName": "google.cloud.run_v2.ServicesClient.update_service", + "fullName": "google.cloud.run_v2.TasksAsyncClient.list_tasks", "method": { - "fullName": "google.cloud.run.v2.Services.UpdateService", + "fullName": "google.cloud.run.v2.Tasks.ListTasks", "service": { - "fullName": "google.cloud.run.v2.Services", - "shortName": "Services" + "fullName": "google.cloud.run.v2.Tasks", + "shortName": "Tasks" }, - "shortName": "UpdateService" + "shortName": "ListTasks" }, "parameters": [ { "name": "request", - "type": "google.cloud.run_v2.types.UpdateServiceRequest" + "type": "google.cloud.run_v2.types.ListTasksRequest" }, { - "name": "service", - "type": "google.cloud.run_v2.types.Service" + "name": "parent", + "type": "str" }, { "name": "retry", @@ -2607,22 +3898,22 @@ "type": "Sequence[Tuple[str, str]" } ], - "resultType": "google.api_core.operation.Operation", - "shortName": "update_service" + "resultType": "google.cloud.run_v2.services.tasks.pagers.ListTasksAsyncPager", + "shortName": "list_tasks" }, - "description": "Sample for UpdateService", - "file": "run_v2_generated_services_update_service_sync_9076a854.py", + "description": "Sample for ListTasks", + "file": "run_v2_generated_tasks_list_tasks_async.py", "language": "PYTHON", "origin": "API_DEFINITION", - "regionTag": "run_v2_generated_Services_UpdateService_sync", + "regionTag": "run_v2_generated_Tasks_ListTasks_async", "segments": [ { - "end": 54, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 54, + "end": 52, "start": 27, "type": "SHORT" }, @@ -2632,22 +3923,102 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 44, + "end": 45, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 51, - "start": 45, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 55, - "start": 52, + "end": 53, + "start": 49, + "type": "RESPONSE_HANDLING" + } + ], + "title": "run_v2_generated_tasks_list_tasks_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.run_v2.TasksClient", + "shortName": "TasksClient" + }, + "fullName": "google.cloud.run_v2.TasksClient.list_tasks", + "method": { + "fullName": "google.cloud.run.v2.Tasks.ListTasks", + "service": { + "fullName": "google.cloud.run.v2.Tasks", + "shortName": "Tasks" + }, + "shortName": "ListTasks" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.run_v2.types.ListTasksRequest" + }, + { + "name": "parent", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, str]" + } + ], + "resultType": "google.cloud.run_v2.services.tasks.pagers.ListTasksPager", + "shortName": "list_tasks" + }, + "description": "Sample for ListTasks", + "file": "run_v2_generated_tasks_list_tasks_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "run_v2_generated_Tasks_ListTasks_sync", + "segments": [ + { + "end": 52, + "start": 27, + "type": "FULL" + }, + { + "end": 52, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 48, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 53, + "start": 49, "type": "RESPONSE_HANDLING" } ], - "title": "run_v2_generated_services_update_service_sync_9076a854.py" + "title": "run_v2_generated_tasks_list_tasks_sync.py" } ] } diff --git a/scripts/fixup_run_v2_keywords.py b/scripts/fixup_run_v2_keywords.py index 771b0bc..c051080 100644 --- a/scripts/fixup_run_v2_keywords.py +++ b/scripts/fixup_run_v2_keywords.py @@ -39,16 +39,27 @@ def partition( class runCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'create_job': ('parent', 'job', 'job_id', 'validate_only', ), 'create_service': ('parent', 'service', 'service_id', 'validate_only', ), + 'delete_execution': ('name', 'validate_only', 'etag', ), + 'delete_job': ('name', 'validate_only', 'etag', ), 'delete_revision': ('name', 'validate_only', 'etag', ), 'delete_service': ('name', 'validate_only', 'etag', ), + 'get_execution': ('name', ), 'get_iam_policy': ('resource', 'options', ), + 'get_job': ('name', ), 'get_revision': ('name', ), 'get_service': ('name', ), + 'get_task': ('name', ), + 'list_executions': ('parent', 'page_size', 'page_token', 'show_deleted', ), + 'list_jobs': ('parent', 'page_size', 'page_token', 'show_deleted', ), 'list_revisions': ('parent', 'page_size', 'page_token', 'show_deleted', ), 'list_services': ('parent', 'page_size', 'page_token', 'show_deleted', ), + 'list_tasks': ('parent', 'page_size', 'page_token', 'show_deleted', ), + 'run_job': ('name', 'validate_only', 'etag', ), 'set_iam_policy': ('resource', 'policy', 'update_mask', ), 'test_iam_permissions': ('resource', 'permissions', ), + 'update_job': ('job', 'validate_only', 'allow_missing', ), 'update_service': ('service', 'validate_only', 'allow_missing', ), } diff --git a/setup.py b/setup.py index 0ef73e7..199d300 100644 --- a/setup.py +++ b/setup.py @@ -1,36 +1,47 @@ # -*- coding: utf-8 -*- -# -# Copyright 2020 Google LLC +# Copyright 2022 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 +# 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 io import os -import setuptools +import setuptools # type: ignore +package_root = os.path.abspath(os.path.dirname(__file__)) name = "google-cloud-run" -description = "Cloud Run API client library" -version = "0.4.2" -release_status = "Development Status :: 4 - Beta" -url = "https://github.com/googleapis/python-run" + + +description = "Google Cloud Run API client library" + +version = {} +with open(os.path.join(package_root, "google/cloud/run/gapic_version.py")) as fp: + exec(fp.read(), version) +version = version["__version__"] + +if version[0] == "0": + release_status = "Development Status :: 4 - Beta" +else: + release_status = "Development Status :: 5 - Production/Stable" + dependencies = [ - "google-api-core[grpc] >= 1.33.2, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*", + "google-api-core[grpc] >= 1.34.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,!=2.10.*", "proto-plus >= 1.22.0, <2.0.0dev", "protobuf>=3.19.5,<5.0.0dev,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.12.4, < 1.0.0dev", ] +url = "https://github.com/googleapis/python-run" package_root = os.path.abspath(os.path.dirname(__file__)) @@ -48,7 +59,6 @@ if "google.cloud" in packages: namespaces.append("google.cloud") - setuptools.setup( name=name, version=version, diff --git a/testing/constraints-3.10.txt b/testing/constraints-3.10.txt index e69de29..ad3f0fa 100644 --- a/testing/constraints-3.10.txt +++ b/testing/constraints-3.10.txt @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# This constraints file is required for unit tests. +# List all library dependencies and extras in this file. +google-api-core +proto-plus +protobuf +grpc-google-iam-v1 diff --git a/testing/constraints-3.11.txt b/testing/constraints-3.11.txt new file mode 100644 index 0000000..ad3f0fa --- /dev/null +++ b/testing/constraints-3.11.txt @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# This constraints file is required for unit tests. +# List all library dependencies and extras in this file. +google-api-core +proto-plus +protobuf +grpc-google-iam-v1 diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index 87c3b8c..2beecf9 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -4,7 +4,7 @@ # Pin the version to the lower bound. # e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0dev", # Then this file should have google-cloud-foo==1.14.0 -google-api-core==1.33.2 +google-api-core==1.34.0 proto-plus==1.22.0 -grpc-google-iam-v1==0.12.4 protobuf==3.19.5 +grpc-google-iam-v1==0.12.4 diff --git a/testing/constraints-3.8.txt b/testing/constraints-3.8.txt index e69de29..ad3f0fa 100644 --- a/testing/constraints-3.8.txt +++ b/testing/constraints-3.8.txt @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# This constraints file is required for unit tests. +# List all library dependencies and extras in this file. +google-api-core +proto-plus +protobuf +grpc-google-iam-v1 diff --git a/testing/constraints-3.9.txt b/testing/constraints-3.9.txt index e69de29..ad3f0fa 100644 --- a/testing/constraints-3.9.txt +++ b/testing/constraints-3.9.txt @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# This constraints file is required for unit tests. +# List all library dependencies and extras in this file. +google-api-core +proto-plus +protobuf +grpc-google-iam-v1 diff --git a/tests/unit/gapic/run_v2/test_executions.py b/tests/unit/gapic/run_v2/test_executions.py new file mode 100644 index 0000000..5292eaa --- /dev/null +++ b/tests/unit/gapic/run_v2/test_executions.py @@ -0,0 +1,4081 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER + import mock + +from collections.abc import Iterable +import json +import math + +from google.api import launch_stage_pb2 # type: ignore +from google.api_core import ( + future, + gapic_v1, + grpc_helpers, + grpc_helpers_async, + operation, + operations_v1, + path_template, +) +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import operation_async # type: ignore +import google.auth +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.location import locations_pb2 +from google.longrunning import operations_pb2 +from google.oauth2 import service_account +from google.protobuf import json_format +from google.protobuf import timestamp_pb2 # type: ignore +import grpc +from grpc.experimental import aio +from proto.marshal.rules import wrappers +from proto.marshal.rules.dates import DurationRule, TimestampRule +import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session + +from google.cloud.run_v2.services.executions import ( + ExecutionsAsyncClient, + ExecutionsClient, + pagers, + transports, +) +from google.cloud.run_v2.types import condition, execution, task_template + + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert ExecutionsClient._get_default_mtls_endpoint(None) is None + assert ( + ExecutionsClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + ) + assert ( + ExecutionsClient._get_default_mtls_endpoint(api_mtls_endpoint) + == api_mtls_endpoint + ) + assert ( + ExecutionsClient._get_default_mtls_endpoint(sandbox_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + ExecutionsClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert ExecutionsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (ExecutionsClient, "grpc"), + (ExecutionsAsyncClient, "grpc_asyncio"), + (ExecutionsClient, "rest"), + ], +) +def test_executions_client_from_service_account_info(client_class, transport_name): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_info" + ) as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info, transport=transport_name) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +@pytest.mark.parametrize( + "transport_class,transport_name", + [ + (transports.ExecutionsGrpcTransport, "grpc"), + (transports.ExecutionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ExecutionsRestTransport, "rest"), + ], +) +def test_executions_client_service_account_always_use_jwt( + transport_class, transport_name +): + with mock.patch.object( + service_account.Credentials, "with_always_use_jwt_access", create=True + ) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object( + service_account.Credentials, "with_always_use_jwt_access", create=True + ) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (ExecutionsClient, "grpc"), + (ExecutionsAsyncClient, "grpc_asyncio"), + (ExecutionsClient, "rest"), + ], +) +def test_executions_client_from_service_account_file(client_class, transport_name): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_file" + ) as factory: + factory.return_value = creds + client = client_class.from_service_account_file( + "dummy/file/path.json", transport=transport_name + ) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json( + "dummy/file/path.json", transport=transport_name + ) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +def test_executions_client_get_transport_class(): + transport = ExecutionsClient.get_transport_class() + available_transports = [ + transports.ExecutionsGrpcTransport, + transports.ExecutionsRestTransport, + ] + assert transport in available_transports + + transport = ExecutionsClient.get_transport_class("grpc") + assert transport == transports.ExecutionsGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (ExecutionsClient, transports.ExecutionsGrpcTransport, "grpc"), + ( + ExecutionsAsyncClient, + transports.ExecutionsGrpcAsyncIOTransport, + "grpc_asyncio", + ), + (ExecutionsClient, transports.ExecutionsRestTransport, "rest"), + ], +) +@mock.patch.object( + ExecutionsClient, "DEFAULT_ENDPOINT", modify_default_endpoint(ExecutionsClient) +) +@mock.patch.object( + ExecutionsAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(ExecutionsAsyncClient), +) +def test_executions_client_client_options( + client_class, transport_class, transport_name +): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(ExecutionsClient, "get_transport_class") as gtc: + transport = transport_class(credentials=ga_credentials.AnonymousCredentials()) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(ExecutionsClient, "get_transport_class") as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name, client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class(transport=transport_name) + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class(transport=transport_name) + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + # Check the case api_endpoint is provided + options = client_options.ClientOptions( + api_audience="https://language.googleapis.com" + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience="https://language.googleapis.com", + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (ExecutionsClient, transports.ExecutionsGrpcTransport, "grpc", "true"), + ( + ExecutionsAsyncClient, + transports.ExecutionsGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (ExecutionsClient, transports.ExecutionsGrpcTransport, "grpc", "false"), + ( + ExecutionsAsyncClient, + transports.ExecutionsGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + (ExecutionsClient, transports.ExecutionsRestTransport, "rest", "true"), + (ExecutionsClient, transports.ExecutionsRestTransport, "rest", "false"), + ], +) +@mock.patch.object( + ExecutionsClient, "DEFAULT_ENDPOINT", modify_default_endpoint(ExecutionsClient) +) +@mock.patch.object( + ExecutionsAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(ExecutionsAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_executions_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + options = client_options.ClientOptions( + client_cert_source=client_cert_source_callback + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize("client_class", [ExecutionsClient, ExecutionsAsyncClient]) +@mock.patch.object( + ExecutionsClient, "DEFAULT_ENDPOINT", modify_default_endpoint(ExecutionsClient) +) +@mock.patch.object( + ExecutionsAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(ExecutionsAsyncClient), +) +def test_executions_client_get_mtls_endpoint_and_cert_source(client_class): + mock_client_cert_source = mock.Mock() + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source == mock_client_cert_source + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): + mock_client_cert_source = mock.Mock() + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=mock_client_cert_source, + ): + ( + api_endpoint, + cert_source, + ) = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source == mock_client_cert_source + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (ExecutionsClient, transports.ExecutionsGrpcTransport, "grpc"), + ( + ExecutionsAsyncClient, + transports.ExecutionsGrpcAsyncIOTransport, + "grpc_asyncio", + ), + (ExecutionsClient, transports.ExecutionsRestTransport, "rest"), + ], +) +def test_executions_client_client_options_scopes( + client_class, transport_class, transport_name +): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,grpc_helpers", + [ + (ExecutionsClient, transports.ExecutionsGrpcTransport, "grpc", grpc_helpers), + ( + ExecutionsAsyncClient, + transports.ExecutionsGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + (ExecutionsClient, transports.ExecutionsRestTransport, "rest", None), + ], +) +def test_executions_client_client_options_credentials_file( + client_class, transport_class, transport_name, grpc_helpers +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +def test_executions_client_client_options_from_dict(): + with mock.patch( + "google.cloud.run_v2.services.executions.transports.ExecutionsGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = ExecutionsClient(client_options={"api_endpoint": "squid.clam.whelk"}) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,grpc_helpers", + [ + (ExecutionsClient, transports.ExecutionsGrpcTransport, "grpc", grpc_helpers), + ( + ExecutionsAsyncClient, + transports.ExecutionsGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + ], +) +def test_executions_client_create_channel_credentials_file( + client_class, transport_class, transport_name, grpc_helpers +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # test that the credentials from file are saved and used as the credentials. + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel" + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + file_creds = ga_credentials.AnonymousCredentials() + load_creds.return_value = (file_creds, None) + adc.return_value = (creds, None) + client = client_class(client_options=options, transport=transport_name) + create_channel.assert_called_with( + "run.googleapis.com:443", + credentials=file_creds, + credentials_file=None, + quota_project_id=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=None, + default_host="run.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "request_type", + [ + execution.GetExecutionRequest, + dict, + ], +) +def test_get_execution(request_type, transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = execution.Execution( + name="name_value", + uid="uid_value", + generation=1068, + launch_stage=launch_stage_pb2.LaunchStage.UNIMPLEMENTED, + job="job_value", + parallelism=1174, + task_count=1083, + reconciling=True, + observed_generation=2021, + running_count=1417, + succeeded_count=1581, + failed_count=1261, + etag="etag_value", + ) + response = client.get_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == execution.GetExecutionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, execution.Execution) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.launch_stage == launch_stage_pb2.LaunchStage.UNIMPLEMENTED + assert response.job == "job_value" + assert response.parallelism == 1174 + assert response.task_count == 1083 + assert response.reconciling is True + assert response.observed_generation == 2021 + assert response.running_count == 1417 + assert response.succeeded_count == 1581 + assert response.failed_count == 1261 + assert response.etag == "etag_value" + + +def test_get_execution_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + client.get_execution() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == execution.GetExecutionRequest() + + +@pytest.mark.asyncio +async def test_get_execution_async( + transport: str = "grpc_asyncio", request_type=execution.GetExecutionRequest +): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + execution.Execution( + name="name_value", + uid="uid_value", + generation=1068, + launch_stage=launch_stage_pb2.LaunchStage.UNIMPLEMENTED, + job="job_value", + parallelism=1174, + task_count=1083, + reconciling=True, + observed_generation=2021, + running_count=1417, + succeeded_count=1581, + failed_count=1261, + etag="etag_value", + ) + ) + response = await client.get_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == execution.GetExecutionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, execution.Execution) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.launch_stage == launch_stage_pb2.LaunchStage.UNIMPLEMENTED + assert response.job == "job_value" + assert response.parallelism == 1174 + assert response.task_count == 1083 + assert response.reconciling is True + assert response.observed_generation == 2021 + assert response.running_count == 1417 + assert response.succeeded_count == 1581 + assert response.failed_count == 1261 + assert response.etag == "etag_value" + + +@pytest.mark.asyncio +async def test_get_execution_async_from_dict(): + await test_get_execution_async(request_type=dict) + + +def test_get_execution_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = execution.GetExecutionRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + call.return_value = execution.Execution() + client.get_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_execution_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = execution.GetExecutionRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(execution.Execution()) + await client.get_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_get_execution_flattened(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = execution.Execution() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_execution( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_get_execution_flattened_error(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_execution( + execution.GetExecutionRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_execution_flattened_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = execution.Execution() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(execution.Execution()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_execution( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_get_execution_flattened_error_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_execution( + execution.GetExecutionRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + execution.ListExecutionsRequest, + dict, + ], +) +def test_list_executions(request_type, transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = execution.ListExecutionsResponse( + next_page_token="next_page_token_value", + ) + response = client.list_executions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == execution.ListExecutionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListExecutionsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_executions_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + client.list_executions() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == execution.ListExecutionsRequest() + + +@pytest.mark.asyncio +async def test_list_executions_async( + transport: str = "grpc_asyncio", request_type=execution.ListExecutionsRequest +): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + execution.ListExecutionsResponse( + next_page_token="next_page_token_value", + ) + ) + response = await client.list_executions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == execution.ListExecutionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListExecutionsAsyncPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_executions_async_from_dict(): + await test_list_executions_async(request_type=dict) + + +def test_list_executions_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = execution.ListExecutionsRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + call.return_value = execution.ListExecutionsResponse() + client.list_executions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_executions_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = execution.ListExecutionsRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + execution.ListExecutionsResponse() + ) + await client.list_executions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +def test_list_executions_flattened(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = execution.ListExecutionsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_executions( + parent="parent_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + + +def test_list_executions_flattened_error(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_executions( + execution.ListExecutionsRequest(), + parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_executions_flattened_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = execution.ListExecutionsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + execution.ListExecutionsResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_executions( + parent="parent_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_list_executions_flattened_error_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_executions( + execution.ListExecutionsRequest(), + parent="parent_value", + ) + + +def test_list_executions_pager(transport_name: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials, + transport=transport_name, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + execution.Execution(), + ], + next_page_token="abc", + ), + execution.ListExecutionsResponse( + executions=[], + next_page_token="def", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + ], + next_page_token="ghi", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_executions(request={}) + + assert pager._metadata == metadata + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, execution.Execution) for i in results) + + +def test_list_executions_pages(transport_name: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials, + transport=transport_name, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_executions), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + execution.Execution(), + ], + next_page_token="abc", + ), + execution.ListExecutionsResponse( + executions=[], + next_page_token="def", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + ], + next_page_token="ghi", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + ], + ), + RuntimeError, + ) + pages = list(client.list_executions(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_executions_async_pager(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_executions), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + execution.Execution(), + ], + next_page_token="abc", + ), + execution.ListExecutionsResponse( + executions=[], + next_page_token="def", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + ], + next_page_token="ghi", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_executions( + request={}, + ) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: # pragma: no branch + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, execution.Execution) for i in responses) + + +@pytest.mark.asyncio +async def test_list_executions_async_pages(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_executions), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + execution.Execution(), + ], + next_page_token="abc", + ), + execution.ListExecutionsResponse( + executions=[], + next_page_token="def", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + ], + next_page_token="ghi", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in ( + await client.list_executions(request={}) + ).pages: # pragma: no branch + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + execution.DeleteExecutionRequest, + dict, + ], +) +def test_delete_execution(request_type, transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.delete_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == execution.DeleteExecutionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_delete_execution_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + client.delete_execution() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == execution.DeleteExecutionRequest() + + +@pytest.mark.asyncio +async def test_delete_execution_async( + transport: str = "grpc_asyncio", request_type=execution.DeleteExecutionRequest +): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.delete_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == execution.DeleteExecutionRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_delete_execution_async_from_dict(): + await test_delete_execution_async(request_type=dict) + + +def test_delete_execution_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = execution.DeleteExecutionRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.delete_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_execution_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = execution.DeleteExecutionRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.delete_execution(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_delete_execution_flattened(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_execution( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_delete_execution_flattened_error(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_execution( + execution.DeleteExecutionRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_delete_execution_flattened_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_execution), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_execution( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_delete_execution_flattened_error_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_execution( + execution.DeleteExecutionRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + execution.GetExecutionRequest, + dict, + ], +) +def test_get_execution_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = execution.Execution( + name="name_value", + uid="uid_value", + generation=1068, + launch_stage=launch_stage_pb2.LaunchStage.UNIMPLEMENTED, + job="job_value", + parallelism=1174, + task_count=1083, + reconciling=True, + observed_generation=2021, + running_count=1417, + succeeded_count=1581, + failed_count=1261, + etag="etag_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = execution.Execution.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_execution(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, execution.Execution) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.launch_stage == launch_stage_pb2.LaunchStage.UNIMPLEMENTED + assert response.job == "job_value" + assert response.parallelism == 1174 + assert response.task_count == 1083 + assert response.reconciling is True + assert response.observed_generation == 2021 + assert response.running_count == 1417 + assert response.succeeded_count == 1581 + assert response.failed_count == 1261 + assert response.etag == "etag_value" + + +def test_get_execution_rest_required_fields(request_type=execution.GetExecutionRequest): + transport_class = transports.ExecutionsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_execution._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_execution._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = execution.Execution() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = execution.Execution.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_execution(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_execution_rest_unset_required_fields(): + transport = transports.ExecutionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_execution._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_execution_rest_interceptors(null_interceptor): + transport = transports.ExecutionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExecutionsRestInterceptor(), + ) + client = ExecutionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ExecutionsRestInterceptor, "post_get_execution" + ) as post, mock.patch.object( + transports.ExecutionsRestInterceptor, "pre_get_execution" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = execution.GetExecutionRequest.pb(execution.GetExecutionRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = execution.Execution.to_json(execution.Execution()) + + request = execution.GetExecutionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = execution.Execution() + + client.get_execution( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_execution_rest_bad_request( + transport: str = "rest", request_type=execution.GetExecutionRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_execution(request) + + +def test_get_execution_rest_flattened(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = execution.Execution() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = execution.Execution.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_execution(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/jobs/*/executions/*}" + % client.transport._host, + args[1], + ) + + +def test_get_execution_rest_flattened_error(transport: str = "rest"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_execution( + execution.GetExecutionRequest(), + name="name_value", + ) + + +def test_get_execution_rest_error(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + execution.ListExecutionsRequest, + dict, + ], +) +def test_list_executions_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = execution.ListExecutionsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = execution.ListExecutionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_executions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListExecutionsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_executions_rest_required_fields( + request_type=execution.ListExecutionsRequest, +): + transport_class = transports.ExecutionsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_executions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_executions._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + "show_deleted", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = execution.ListExecutionsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = execution.ListExecutionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_executions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_executions_rest_unset_required_fields(): + transport = transports.ExecutionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_executions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + "showDeleted", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_executions_rest_interceptors(null_interceptor): + transport = transports.ExecutionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExecutionsRestInterceptor(), + ) + client = ExecutionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ExecutionsRestInterceptor, "post_list_executions" + ) as post, mock.patch.object( + transports.ExecutionsRestInterceptor, "pre_list_executions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = execution.ListExecutionsRequest.pb( + execution.ListExecutionsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = execution.ListExecutionsResponse.to_json( + execution.ListExecutionsResponse() + ) + + request = execution.ListExecutionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = execution.ListExecutionsResponse() + + client.list_executions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_executions_rest_bad_request( + transport: str = "rest", request_type=execution.ListExecutionsRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_executions(request) + + +def test_list_executions_rest_flattened(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = execution.ListExecutionsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/jobs/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = execution.ListExecutionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_executions(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/locations/*/jobs/*}/executions" + % client.transport._host, + args[1], + ) + + +def test_list_executions_rest_flattened_error(transport: str = "rest"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_executions( + execution.ListExecutionsRequest(), + parent="parent_value", + ) + + +def test_list_executions_rest_pager(transport: str = "rest"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + execution.Execution(), + ], + next_page_token="abc", + ), + execution.ListExecutionsResponse( + executions=[], + next_page_token="def", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + ], + next_page_token="ghi", + ), + execution.ListExecutionsResponse( + executions=[ + execution.Execution(), + execution.Execution(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(execution.ListExecutionsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/locations/sample2/jobs/sample3"} + + pager = client.list_executions(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, execution.Execution) for i in results) + + pages = list(client.list_executions(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + execution.DeleteExecutionRequest, + dict, + ], +) +def test_delete_execution_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_execution(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_delete_execution_rest_required_fields( + request_type=execution.DeleteExecutionRequest, +): + transport_class = transports.ExecutionsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_execution._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_execution._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "etag", + "validate_only", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_execution(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_execution_rest_unset_required_fields(): + transport = transports.ExecutionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_execution._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "etag", + "validateOnly", + ) + ) + & set(("name",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_execution_rest_interceptors(null_interceptor): + transport = transports.ExecutionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExecutionsRestInterceptor(), + ) + client = ExecutionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ExecutionsRestInterceptor, "post_delete_execution" + ) as post, mock.patch.object( + transports.ExecutionsRestInterceptor, "pre_delete_execution" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = execution.DeleteExecutionRequest.pb( + execution.DeleteExecutionRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = execution.DeleteExecutionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.delete_execution( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_delete_execution_rest_bad_request( + transport: str = "rest", request_type=execution.DeleteExecutionRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_execution(request) + + +def test_delete_execution_rest_flattened(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_execution(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/jobs/*/executions/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_execution_rest_flattened_error(transport: str = "rest"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_execution( + execution.DeleteExecutionRequest(), + name="name_value", + ) + + +def test_delete_execution_rest_error(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ExecutionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ExecutionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExecutionsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ExecutionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ExecutionsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ExecutionsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ExecutionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExecutionsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ExecutionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ExecutionsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ExecutionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ExecutionsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ExecutionsGrpcTransport, + transports.ExecutionsGrpcAsyncIOTransport, + transports.ExecutionsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ExecutionsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ExecutionsGrpcTransport, + ) + + +def test_executions_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ExecutionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_executions_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.run_v2.services.executions.transports.ExecutionsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ExecutionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "get_execution", + "list_executions", + "delete_execution", + "get_operation", + "delete_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_executions_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.run_v2.services.executions.transports.ExecutionsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ExecutionsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +def test_executions_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.run_v2.services.executions.transports.ExecutionsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ExecutionsTransport() + adc.assert_called_once() + + +def test_executions_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + ExecutionsClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ExecutionsGrpcTransport, + transports.ExecutionsGrpcAsyncIOTransport, + ], +) +def test_executions_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ExecutionsGrpcTransport, + transports.ExecutionsGrpcAsyncIOTransport, + transports.ExecutionsRestTransport, + ], +) +def test_executions_transport_auth_gdch_credentials(transport_class): + host = "https://language.com" + api_audience_tests = [None, "https://language2.com"] + api_audience_expect = [host, "https://language2.com"] + for t, e in zip(api_audience_tests, api_audience_expect): + with mock.patch.object(google.auth, "default", autospec=True) as adc: + gdch_mock = mock.MagicMock() + type(gdch_mock).with_gdch_audience = mock.PropertyMock( + return_value=gdch_mock + ) + adc.return_value = (gdch_mock, None) + transport_class(host=host, api_audience=t) + gdch_mock.with_gdch_audience.assert_called_once_with(e) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.ExecutionsGrpcTransport, grpc_helpers), + (transports.ExecutionsGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +def test_executions_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "run.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=["1", "2"], + default_host="run.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class", + [transports.ExecutionsGrpcTransport, transports.ExecutionsGrpcAsyncIOTransport], +) +def test_executions_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = ga_credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + +def test_executions_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ExecutionsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_executions_rest_lro_client(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + "rest", + ], +) +def test_executions_host_no_port(transport_name): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint="run.googleapis.com"), + transport=transport_name, + ) + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + "rest", + ], +) +def test_executions_host_with_port(transport_name): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="run.googleapis.com:8000" + ), + transport=transport_name, + ) + assert client.transport._host == ( + "run.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_executions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ExecutionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ExecutionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_execution._session + session2 = client2.transport.get_execution._session + assert session1 != session2 + session1 = client1.transport.list_executions._session + session2 = client2.transport.list_executions._session + assert session1 != session2 + session1 = client1.transport.delete_execution._session + session2 = client2.transport.delete_execution._session + assert session1 != session2 + + +def test_executions_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.ExecutionsGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_executions_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.ExecutionsGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.ExecutionsGrpcTransport, transports.ExecutionsGrpcAsyncIOTransport], +) +def test_executions_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.ExecutionsGrpcTransport, transports.ExecutionsGrpcAsyncIOTransport], +) +def test_executions_transport_channel_mtls_with_adc(transport_class): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_executions_grpc_lro_client(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.OperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_executions_grpc_lro_async_client(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.OperationsAsyncClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_connector_path(): + project = "squid" + location = "clam" + connector = "whelk" + expected = "projects/{project}/locations/{location}/connectors/{connector}".format( + project=project, + location=location, + connector=connector, + ) + actual = ExecutionsClient.connector_path(project, location, connector) + assert expected == actual + + +def test_parse_connector_path(): + expected = { + "project": "octopus", + "location": "oyster", + "connector": "nudibranch", + } + path = ExecutionsClient.connector_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_connector_path(path) + assert expected == actual + + +def test_crypto_key_path(): + project = "cuttlefish" + location = "mussel" + key_ring = "winkle" + crypto_key = "nautilus" + expected = "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + actual = ExecutionsClient.crypto_key_path(project, location, key_ring, crypto_key) + assert expected == actual + + +def test_parse_crypto_key_path(): + expected = { + "project": "scallop", + "location": "abalone", + "key_ring": "squid", + "crypto_key": "clam", + } + path = ExecutionsClient.crypto_key_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_crypto_key_path(path) + assert expected == actual + + +def test_execution_path(): + project = "whelk" + location = "octopus" + job = "oyster" + execution = "nudibranch" + expected = "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}".format( + project=project, + location=location, + job=job, + execution=execution, + ) + actual = ExecutionsClient.execution_path(project, location, job, execution) + assert expected == actual + + +def test_parse_execution_path(): + expected = { + "project": "cuttlefish", + "location": "mussel", + "job": "winkle", + "execution": "nautilus", + } + path = ExecutionsClient.execution_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_execution_path(path) + assert expected == actual + + +def test_job_path(): + project = "scallop" + location = "abalone" + job = "squid" + expected = "projects/{project}/locations/{location}/jobs/{job}".format( + project=project, + location=location, + job=job, + ) + actual = ExecutionsClient.job_path(project, location, job) + assert expected == actual + + +def test_parse_job_path(): + expected = { + "project": "clam", + "location": "whelk", + "job": "octopus", + } + path = ExecutionsClient.job_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_job_path(path) + assert expected == actual + + +def test_secret_path(): + project = "oyster" + secret = "nudibranch" + expected = "projects/{project}/secrets/{secret}".format( + project=project, + secret=secret, + ) + actual = ExecutionsClient.secret_path(project, secret) + assert expected == actual + + +def test_parse_secret_path(): + expected = { + "project": "cuttlefish", + "secret": "mussel", + } + path = ExecutionsClient.secret_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_secret_path(path) + assert expected == actual + + +def test_secret_version_path(): + project = "winkle" + secret = "nautilus" + version = "scallop" + expected = "projects/{project}/secrets/{secret}/versions/{version}".format( + project=project, + secret=secret, + version=version, + ) + actual = ExecutionsClient.secret_version_path(project, secret, version) + assert expected == actual + + +def test_parse_secret_version_path(): + expected = { + "project": "abalone", + "secret": "squid", + "version": "clam", + } + path = ExecutionsClient.secret_version_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_secret_version_path(path) + assert expected == actual + + +def test_common_billing_account_path(): + billing_account = "whelk" + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = ExecutionsClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "octopus", + } + path = ExecutionsClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "oyster" + expected = "folders/{folder}".format( + folder=folder, + ) + actual = ExecutionsClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nudibranch", + } + path = ExecutionsClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "cuttlefish" + expected = "organizations/{organization}".format( + organization=organization, + ) + actual = ExecutionsClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "mussel", + } + path = ExecutionsClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "winkle" + expected = "projects/{project}".format( + project=project, + ) + actual = ExecutionsClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "nautilus", + } + path = ExecutionsClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "scallop" + location = "abalone" + expected = "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + actual = ExecutionsClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "squid", + "location": "clam", + } + path = ExecutionsClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = ExecutionsClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_with_default_client_info(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object( + transports.ExecutionsTransport, "_prep_wrapped_messages" + ) as prep: + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object( + transports.ExecutionsTransport, "_prep_wrapped_messages" + ) as prep: + transport_class = ExecutionsClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object( + type(getattr(client.transport, "grpc_channel")), "close" + ) as close: + async with client: + close.assert_not_called() + close.assert_called_once() + + +def test_delete_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.DeleteOperationRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.DeleteOperationRequest, + dict, + ], +) +def test_delete_operation_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_delete_operation(transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_operation_async(transport: str = "grpc"): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_operation_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = None + + client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_operation_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_delete_operation_from_dict(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_delete_operation_from_dict_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_get_operation(transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_list_operations(transport: str = "grpc"): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + response = client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +@pytest.mark.asyncio +async def test_list_operations_async(transport: str = "grpc"): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_list_operations_field_headers(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = operations_pb2.ListOperationsResponse() + + client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_operations_field_headers_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_list_operations_from_dict(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + + response = client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_list_operations_from_dict_async(): + client = ExecutionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_transport_close(): + transports = { + "rest": "_session", + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + with mock.patch.object( + type(getattr(client.transport, close_name)), "close" + ) as close: + with client: + close.assert_not_called() + close.assert_called_once() + + +def test_client_ctx(): + transports = [ + "rest", + "grpc", + ] + for transport in transports: + client = ExecutionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() + + +@pytest.mark.parametrize( + "client_class,transport_class", + [ + (ExecutionsClient, transports.ExecutionsGrpcTransport), + (ExecutionsAsyncClient, transports.ExecutionsGrpcAsyncIOTransport), + ], +) +def test_api_key_credentials(client_class, transport_class): + with mock.patch.object( + google.auth._default, "get_api_key_credentials", create=True + ) as get_api_key_credentials: + mock_cred = mock.Mock() + get_api_key_credentials.return_value = mock_cred + options = client_options.ClientOptions() + options.api_key = "api_key" + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=mock_cred, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) diff --git a/tests/unit/gapic/run_v2/test_jobs.py b/tests/unit/gapic/run_v2/test_jobs.py new file mode 100644 index 0000000..190bf54 --- /dev/null +++ b/tests/unit/gapic/run_v2/test_jobs.py @@ -0,0 +1,7175 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER + import mock + +from collections.abc import Iterable +import json +import math + +from google.api import launch_stage_pb2 # type: ignore +from google.api_core import ( + future, + gapic_v1, + grpc_helpers, + grpc_helpers_async, + operation, + operations_v1, + path_template, +) +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +from google.api_core import operation_async # type: ignore +import google.auth +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.location import locations_pb2 +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import options_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.oauth2 import service_account +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format +from google.protobuf import timestamp_pb2 # type: ignore +from google.type import expr_pb2 # type: ignore +import grpc +from grpc.experimental import aio +from proto.marshal.rules import wrappers +from proto.marshal.rules.dates import DurationRule, TimestampRule +import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session + +from google.cloud.run_v2.services.jobs import ( + JobsAsyncClient, + JobsClient, + pagers, + transports, +) +from google.cloud.run_v2.types import condition, execution, execution_template +from google.cloud.run_v2.types import job +from google.cloud.run_v2.types import job as gcr_job +from google.cloud.run_v2.types import k8s_min, task_template, vendor_settings + + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert JobsClient._get_default_mtls_endpoint(None) is None + assert JobsClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert JobsClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + assert ( + JobsClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint + ) + assert ( + JobsClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert JobsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (JobsClient, "grpc"), + (JobsAsyncClient, "grpc_asyncio"), + (JobsClient, "rest"), + ], +) +def test_jobs_client_from_service_account_info(client_class, transport_name): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_info" + ) as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info, transport=transport_name) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +@pytest.mark.parametrize( + "transport_class,transport_name", + [ + (transports.JobsGrpcTransport, "grpc"), + (transports.JobsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.JobsRestTransport, "rest"), + ], +) +def test_jobs_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object( + service_account.Credentials, "with_always_use_jwt_access", create=True + ) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object( + service_account.Credentials, "with_always_use_jwt_access", create=True + ) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (JobsClient, "grpc"), + (JobsAsyncClient, "grpc_asyncio"), + (JobsClient, "rest"), + ], +) +def test_jobs_client_from_service_account_file(client_class, transport_name): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_file" + ) as factory: + factory.return_value = creds + client = client_class.from_service_account_file( + "dummy/file/path.json", transport=transport_name + ) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json( + "dummy/file/path.json", transport=transport_name + ) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +def test_jobs_client_get_transport_class(): + transport = JobsClient.get_transport_class() + available_transports = [ + transports.JobsGrpcTransport, + transports.JobsRestTransport, + ] + assert transport in available_transports + + transport = JobsClient.get_transport_class("grpc") + assert transport == transports.JobsGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (JobsClient, transports.JobsGrpcTransport, "grpc"), + (JobsAsyncClient, transports.JobsGrpcAsyncIOTransport, "grpc_asyncio"), + (JobsClient, transports.JobsRestTransport, "rest"), + ], +) +@mock.patch.object(JobsClient, "DEFAULT_ENDPOINT", modify_default_endpoint(JobsClient)) +@mock.patch.object( + JobsAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(JobsAsyncClient) +) +def test_jobs_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(JobsClient, "get_transport_class") as gtc: + transport = transport_class(credentials=ga_credentials.AnonymousCredentials()) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(JobsClient, "get_transport_class") as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name, client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class(transport=transport_name) + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class(transport=transport_name) + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + # Check the case api_endpoint is provided + options = client_options.ClientOptions( + api_audience="https://language.googleapis.com" + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience="https://language.googleapis.com", + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (JobsClient, transports.JobsGrpcTransport, "grpc", "true"), + (JobsAsyncClient, transports.JobsGrpcAsyncIOTransport, "grpc_asyncio", "true"), + (JobsClient, transports.JobsGrpcTransport, "grpc", "false"), + (JobsAsyncClient, transports.JobsGrpcAsyncIOTransport, "grpc_asyncio", "false"), + (JobsClient, transports.JobsRestTransport, "rest", "true"), + (JobsClient, transports.JobsRestTransport, "rest", "false"), + ], +) +@mock.patch.object(JobsClient, "DEFAULT_ENDPOINT", modify_default_endpoint(JobsClient)) +@mock.patch.object( + JobsAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(JobsAsyncClient) +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_jobs_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + options = client_options.ClientOptions( + client_cert_source=client_cert_source_callback + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize("client_class", [JobsClient, JobsAsyncClient]) +@mock.patch.object(JobsClient, "DEFAULT_ENDPOINT", modify_default_endpoint(JobsClient)) +@mock.patch.object( + JobsAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(JobsAsyncClient) +) +def test_jobs_client_get_mtls_endpoint_and_cert_source(client_class): + mock_client_cert_source = mock.Mock() + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source == mock_client_cert_source + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): + mock_client_cert_source = mock.Mock() + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=mock_client_cert_source, + ): + ( + api_endpoint, + cert_source, + ) = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source == mock_client_cert_source + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (JobsClient, transports.JobsGrpcTransport, "grpc"), + (JobsAsyncClient, transports.JobsGrpcAsyncIOTransport, "grpc_asyncio"), + (JobsClient, transports.JobsRestTransport, "rest"), + ], +) +def test_jobs_client_client_options_scopes( + client_class, transport_class, transport_name +): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,grpc_helpers", + [ + (JobsClient, transports.JobsGrpcTransport, "grpc", grpc_helpers), + ( + JobsAsyncClient, + transports.JobsGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + (JobsClient, transports.JobsRestTransport, "rest", None), + ], +) +def test_jobs_client_client_options_credentials_file( + client_class, transport_class, transport_name, grpc_helpers +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +def test_jobs_client_client_options_from_dict(): + with mock.patch( + "google.cloud.run_v2.services.jobs.transports.JobsGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = JobsClient(client_options={"api_endpoint": "squid.clam.whelk"}) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,grpc_helpers", + [ + (JobsClient, transports.JobsGrpcTransport, "grpc", grpc_helpers), + ( + JobsAsyncClient, + transports.JobsGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + ], +) +def test_jobs_client_create_channel_credentials_file( + client_class, transport_class, transport_name, grpc_helpers +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # test that the credentials from file are saved and used as the credentials. + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel" + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + file_creds = ga_credentials.AnonymousCredentials() + load_creds.return_value = (file_creds, None) + adc.return_value = (creds, None) + client = client_class(client_options=options, transport=transport_name) + create_channel.assert_called_with( + "run.googleapis.com:443", + credentials=file_creds, + credentials_file=None, + quota_project_id=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=None, + default_host="run.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcr_job.CreateJobRequest, + dict, + ], +) +def test_create_job(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.create_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == gcr_job.CreateJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_create_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + client.create_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == gcr_job.CreateJobRequest() + + +@pytest.mark.asyncio +async def test_create_job_async( + transport: str = "grpc_asyncio", request_type=gcr_job.CreateJobRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.create_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == gcr_job.CreateJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_create_job_async_from_dict(): + await test_create_job_async(request_type=dict) + + +def test_create_job_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcr_job.CreateJobRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.create_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_create_job_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcr_job.CreateJobRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.create_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +def test_create_job_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.create_job( + parent="parent_value", + job=gcr_job.Job(name="name_value"), + job_id="job_id_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].job + mock_val = gcr_job.Job(name="name_value") + assert arg == mock_val + arg = args[0].job_id + mock_val = "job_id_value" + assert arg == mock_val + + +def test_create_job_flattened_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_job( + gcr_job.CreateJobRequest(), + parent="parent_value", + job=gcr_job.Job(name="name_value"), + job_id="job_id_value", + ) + + +@pytest.mark.asyncio +async def test_create_job_flattened_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.create_job( + parent="parent_value", + job=gcr_job.Job(name="name_value"), + job_id="job_id_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].job + mock_val = gcr_job.Job(name="name_value") + assert arg == mock_val + arg = args[0].job_id + mock_val = "job_id_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_create_job_flattened_error_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.create_job( + gcr_job.CreateJobRequest(), + parent="parent_value", + job=gcr_job.Job(name="name_value"), + job_id="job_id_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.GetJobRequest, + dict, + ], +) +def test_get_job(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = job.Job( + name="name_value", + uid="uid_value", + generation=1068, + creator="creator_value", + last_modifier="last_modifier_value", + client="client_value", + client_version="client_version_value", + launch_stage=launch_stage_pb2.LaunchStage.UNIMPLEMENTED, + observed_generation=2021, + execution_count=1628, + reconciling=True, + etag="etag_value", + ) + response = client.get_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == job.GetJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, job.Job) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.creator == "creator_value" + assert response.last_modifier == "last_modifier_value" + assert response.client == "client_value" + assert response.client_version == "client_version_value" + assert response.launch_stage == launch_stage_pb2.LaunchStage.UNIMPLEMENTED + assert response.observed_generation == 2021 + assert response.execution_count == 1628 + assert response.reconciling is True + assert response.etag == "etag_value" + + +def test_get_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + client.get_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == job.GetJobRequest() + + +@pytest.mark.asyncio +async def test_get_job_async( + transport: str = "grpc_asyncio", request_type=job.GetJobRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + job.Job( + name="name_value", + uid="uid_value", + generation=1068, + creator="creator_value", + last_modifier="last_modifier_value", + client="client_value", + client_version="client_version_value", + launch_stage=launch_stage_pb2.LaunchStage.UNIMPLEMENTED, + observed_generation=2021, + execution_count=1628, + reconciling=True, + etag="etag_value", + ) + ) + response = await client.get_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == job.GetJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, job.Job) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.creator == "creator_value" + assert response.last_modifier == "last_modifier_value" + assert response.client == "client_value" + assert response.client_version == "client_version_value" + assert response.launch_stage == launch_stage_pb2.LaunchStage.UNIMPLEMENTED + assert response.observed_generation == 2021 + assert response.execution_count == 1628 + assert response.reconciling is True + assert response.etag == "etag_value" + + +@pytest.mark.asyncio +async def test_get_job_async_from_dict(): + await test_get_job_async(request_type=dict) + + +def test_get_job_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.GetJobRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + call.return_value = job.Job() + client.get_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_job_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.GetJobRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(job.Job()) + await client.get_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_get_job_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = job.Job() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_job( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_get_job_flattened_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_job( + job.GetJobRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_job_flattened_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = job.Job() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(job.Job()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_job( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_get_job_flattened_error_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_job( + job.GetJobRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.ListJobsRequest, + dict, + ], +) +def test_list_jobs(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = job.ListJobsResponse( + next_page_token="next_page_token_value", + ) + response = client.list_jobs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == job.ListJobsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListJobsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + client.list_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == job.ListJobsRequest() + + +@pytest.mark.asyncio +async def test_list_jobs_async( + transport: str = "grpc_asyncio", request_type=job.ListJobsRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + job.ListJobsResponse( + next_page_token="next_page_token_value", + ) + ) + response = await client.list_jobs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == job.ListJobsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListJobsAsyncPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_jobs_async_from_dict(): + await test_list_jobs_async(request_type=dict) + + +def test_list_jobs_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.ListJobsRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + call.return_value = job.ListJobsResponse() + client.list_jobs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_jobs_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.ListJobsRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + job.ListJobsResponse() + ) + await client.list_jobs(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +def test_list_jobs_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = job.ListJobsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_jobs( + parent="parent_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + + +def test_list_jobs_flattened_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_jobs( + job.ListJobsRequest(), + parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_jobs_flattened_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = job.ListJobsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + job.ListJobsResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_jobs( + parent="parent_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_list_jobs_flattened_error_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_jobs( + job.ListJobsRequest(), + parent="parent_value", + ) + + +def test_list_jobs_pager(transport_name: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials, + transport=transport_name, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + job.Job(), + ], + next_page_token="abc", + ), + job.ListJobsResponse( + jobs=[], + next_page_token="def", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + ], + next_page_token="ghi", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_jobs(request={}) + + assert pager._metadata == metadata + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, job.Job) for i in results) + + +def test_list_jobs_pages(transport_name: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials, + transport=transport_name, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + job.Job(), + ], + next_page_token="abc", + ), + job.ListJobsResponse( + jobs=[], + next_page_token="def", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + ], + next_page_token="ghi", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + ], + ), + RuntimeError, + ) + pages = list(client.list_jobs(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_jobs_async_pager(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_jobs), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + job.Job(), + ], + next_page_token="abc", + ), + job.ListJobsResponse( + jobs=[], + next_page_token="def", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + ], + next_page_token="ghi", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_jobs( + request={}, + ) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: # pragma: no branch + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, job.Job) for i in responses) + + +@pytest.mark.asyncio +async def test_list_jobs_async_pages(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_jobs), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + job.Job(), + ], + next_page_token="abc", + ), + job.ListJobsResponse( + jobs=[], + next_page_token="def", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + ], + next_page_token="ghi", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in ( + await client.list_jobs(request={}) + ).pages: # pragma: no branch + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcr_job.UpdateJobRequest, + dict, + ], +) +def test_update_job(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.update_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == gcr_job.UpdateJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_update_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + client.update_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == gcr_job.UpdateJobRequest() + + +@pytest.mark.asyncio +async def test_update_job_async( + transport: str = "grpc_asyncio", request_type=gcr_job.UpdateJobRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.update_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == gcr_job.UpdateJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_update_job_async_from_dict(): + await test_update_job_async(request_type=dict) + + +def test_update_job_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcr_job.UpdateJobRequest() + + request.job.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.update_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "job.name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_update_job_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcr_job.UpdateJobRequest() + + request.job.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.update_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "job.name=name_value", + ) in kw["metadata"] + + +def test_update_job_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_job( + job=gcr_job.Job(name="name_value"), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].job + mock_val = gcr_job.Job(name="name_value") + assert arg == mock_val + + +def test_update_job_flattened_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_job( + gcr_job.UpdateJobRequest(), + job=gcr_job.Job(name="name_value"), + ) + + +@pytest.mark.asyncio +async def test_update_job_flattened_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_job( + job=gcr_job.Job(name="name_value"), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].job + mock_val = gcr_job.Job(name="name_value") + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_update_job_flattened_error_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_job( + gcr_job.UpdateJobRequest(), + job=gcr_job.Job(name="name_value"), + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.DeleteJobRequest, + dict, + ], +) +def test_delete_job(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.delete_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == job.DeleteJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_delete_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + client.delete_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == job.DeleteJobRequest() + + +@pytest.mark.asyncio +async def test_delete_job_async( + transport: str = "grpc_asyncio", request_type=job.DeleteJobRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.delete_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == job.DeleteJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_delete_job_async_from_dict(): + await test_delete_job_async(request_type=dict) + + +def test_delete_job_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.DeleteJobRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.delete_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_job_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.DeleteJobRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.delete_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_delete_job_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_job( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_delete_job_flattened_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_job( + job.DeleteJobRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_delete_job_flattened_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_job( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_delete_job_flattened_error_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_job( + job.DeleteJobRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.RunJobRequest, + dict, + ], +) +def test_run_job(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.run_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == job.RunJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_run_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + client.run_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == job.RunJobRequest() + + +@pytest.mark.asyncio +async def test_run_job_async( + transport: str = "grpc_asyncio", request_type=job.RunJobRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.run_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == job.RunJobRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_run_job_async_from_dict(): + await test_run_job_async(request_type=dict) + + +def test_run_job_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.RunJobRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.run_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_run_job_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = job.RunJobRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.run_job(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_run_job_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.run_job( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_run_job_flattened_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.run_job( + job.RunJobRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_run_job_flattened_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_job), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.run_job( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_run_job_flattened_error_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.run_job( + job.RunJobRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + iam_policy_pb2.GetIamPolicyRequest, + dict, + ], +) +def test_get_iam_policy(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy_pb2.Policy( + version=774, + etag=b"etag_blob", + ) + response = client.get_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.GetIamPolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, policy_pb2.Policy) + assert response.version == 774 + assert response.etag == b"etag_blob" + + +def test_get_iam_policy_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: + client.get_iam_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.GetIamPolicyRequest() + + +@pytest.mark.asyncio +async def test_get_iam_policy_async( + transport: str = "grpc_asyncio", request_type=iam_policy_pb2.GetIamPolicyRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + policy_pb2.Policy( + version=774, + etag=b"etag_blob", + ) + ) + response = await client.get_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.GetIamPolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, policy_pb2.Policy) + assert response.version == 774 + assert response.etag == b"etag_blob" + + +@pytest.mark.asyncio +async def test_get_iam_policy_async_from_dict(): + await test_get_iam_policy_async(request_type=dict) + + +def test_get_iam_policy_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = iam_policy_pb2.GetIamPolicyRequest() + + request.resource = "resource_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: + call.return_value = policy_pb2.Policy() + client.get_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "resource=resource_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_iam_policy_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = iam_policy_pb2.GetIamPolicyRequest() + + request.resource = "resource_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(policy_pb2.Policy()) + await client.get_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "resource=resource_value", + ) in kw["metadata"] + + +def test_get_iam_policy_from_dict_foreign(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy_pb2.Policy() + response = client.get_iam_policy( + request={ + "resource": "resource_value", + "options": options_pb2.GetPolicyOptions(requested_policy_version=2598), + } + ) + call.assert_called() + + +@pytest.mark.parametrize( + "request_type", + [ + iam_policy_pb2.SetIamPolicyRequest, + dict, + ], +) +def test_set_iam_policy(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy_pb2.Policy( + version=774, + etag=b"etag_blob", + ) + response = client.set_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.SetIamPolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, policy_pb2.Policy) + assert response.version == 774 + assert response.etag == b"etag_blob" + + +def test_set_iam_policy_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: + client.set_iam_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.SetIamPolicyRequest() + + +@pytest.mark.asyncio +async def test_set_iam_policy_async( + transport: str = "grpc_asyncio", request_type=iam_policy_pb2.SetIamPolicyRequest +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + policy_pb2.Policy( + version=774, + etag=b"etag_blob", + ) + ) + response = await client.set_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.SetIamPolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, policy_pb2.Policy) + assert response.version == 774 + assert response.etag == b"etag_blob" + + +@pytest.mark.asyncio +async def test_set_iam_policy_async_from_dict(): + await test_set_iam_policy_async(request_type=dict) + + +def test_set_iam_policy_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = iam_policy_pb2.SetIamPolicyRequest() + + request.resource = "resource_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: + call.return_value = policy_pb2.Policy() + client.set_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "resource=resource_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_set_iam_policy_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = iam_policy_pb2.SetIamPolicyRequest() + + request.resource = "resource_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(policy_pb2.Policy()) + await client.set_iam_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "resource=resource_value", + ) in kw["metadata"] + + +def test_set_iam_policy_from_dict_foreign(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy_pb2.Policy() + response = client.set_iam_policy( + request={ + "resource": "resource_value", + "policy": policy_pb2.Policy(version=774), + "update_mask": field_mask_pb2.FieldMask(paths=["paths_value"]), + } + ) + call.assert_called() + + +@pytest.mark.parametrize( + "request_type", + [ + iam_policy_pb2.TestIamPermissionsRequest, + dict, + ], +) +def test_test_iam_permissions(request_type, transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.test_iam_permissions), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = iam_policy_pb2.TestIamPermissionsResponse( + permissions=["permissions_value"], + ) + response = client.test_iam_permissions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.TestIamPermissionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, iam_policy_pb2.TestIamPermissionsResponse) + assert response.permissions == ["permissions_value"] + + +def test_test_iam_permissions_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.test_iam_permissions), "__call__" + ) as call: + client.test_iam_permissions() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.TestIamPermissionsRequest() + + +@pytest.mark.asyncio +async def test_test_iam_permissions_async( + transport: str = "grpc_asyncio", + request_type=iam_policy_pb2.TestIamPermissionsRequest, +): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.test_iam_permissions), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + iam_policy_pb2.TestIamPermissionsResponse( + permissions=["permissions_value"], + ) + ) + response = await client.test_iam_permissions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == iam_policy_pb2.TestIamPermissionsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, iam_policy_pb2.TestIamPermissionsResponse) + assert response.permissions == ["permissions_value"] + + +@pytest.mark.asyncio +async def test_test_iam_permissions_async_from_dict(): + await test_test_iam_permissions_async(request_type=dict) + + +def test_test_iam_permissions_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = iam_policy_pb2.TestIamPermissionsRequest() + + request.resource = "resource_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.test_iam_permissions), "__call__" + ) as call: + call.return_value = iam_policy_pb2.TestIamPermissionsResponse() + client.test_iam_permissions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "resource=resource_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_test_iam_permissions_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = iam_policy_pb2.TestIamPermissionsRequest() + + request.resource = "resource_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.test_iam_permissions), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + iam_policy_pb2.TestIamPermissionsResponse() + ) + await client.test_iam_permissions(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "resource=resource_value", + ) in kw["metadata"] + + +def test_test_iam_permissions_from_dict_foreign(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.test_iam_permissions), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = iam_policy_pb2.TestIamPermissionsResponse() + response = client.test_iam_permissions( + request={ + "resource": "resource_value", + "permissions": ["permissions_value"], + } + ) + call.assert_called() + + +@pytest.mark.parametrize( + "request_type", + [ + gcr_job.CreateJobRequest, + dict, + ], +) +def test_create_job_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["job"] = { + "name": "name_value", + "uid": "uid_value", + "generation": 1068, + "labels": {}, + "annotations": {}, + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "delete_time": {}, + "expire_time": {}, + "creator": "creator_value", + "last_modifier": "last_modifier_value", + "client": "client_value", + "client_version": "client_version_value", + "launch_stage": 6, + "binary_authorization": { + "use_default": True, + "breakglass_justification": "breakglass_justification_value", + }, + "template": { + "labels": {}, + "annotations": {}, + "parallelism": 1174, + "task_count": 1083, + "template": { + "containers": [ + { + "name": "name_value", + "image": "image_value", + "command": ["command_value1", "command_value2"], + "args": ["args_value1", "args_value2"], + "env": [ + { + "name": "name_value", + "value": "value_value", + "value_source": { + "secret_key_ref": { + "secret": "secret_value", + "version": "version_value", + } + }, + } + ], + "resources": {"limits": {}, "cpu_idle": True}, + "ports": [{"name": "name_value", "container_port": 1511}], + "volume_mounts": [ + {"name": "name_value", "mount_path": "mount_path_value"} + ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, + } + ], + "volumes": [ + { + "name": "name_value", + "secret": { + "secret": "secret_value", + "items": [ + { + "path": "path_value", + "version": "version_value", + "mode": 421, + } + ], + "default_mode": 1257, + }, + "cloud_sql_instance": { + "instances": ["instances_value1", "instances_value2"] + }, + } + ], + "max_retries": 1187, + "timeout": {"seconds": 751, "nanos": 543}, + "service_account": "service_account_value", + "execution_environment": 1, + "encryption_key": "encryption_key_value", + "vpc_access": {"connector": "connector_value", "egress": 1}, + }, + }, + "observed_generation": 2021, + "terminal_condition": { + "type_": "type__value", + "state": 1, + "message": "message_value", + "last_transition_time": {}, + "severity": 1, + "reason": 1, + "revision_reason": 1, + "execution_reason": 1, + }, + "conditions": {}, + "execution_count": 1628, + "latest_created_execution": { + "name": "name_value", + "create_time": {}, + "completion_time": {}, + }, + "reconciling": True, + "etag": "etag_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_job(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_job_rest_required_fields(request_type=gcr_job.CreateJobRequest): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["job_id"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "jobId" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "jobId" in jsonified_request + assert jsonified_request["jobId"] == request_init["job_id"] + + jsonified_request["parent"] = "parent_value" + jsonified_request["jobId"] = "job_id_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_job._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "job_id", + "validate_only", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "jobId" in jsonified_request + assert jsonified_request["jobId"] == "job_id_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_job(request) + + expected_params = [ + ( + "jobId", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_job_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_job._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "jobId", + "validateOnly", + ) + ) + & set( + ( + "parent", + "job", + "jobId", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_job_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.JobsRestInterceptor, "post_create_job" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_create_job" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcr_job.CreateJobRequest.pb(gcr_job.CreateJobRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcr_job.CreateJobRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_job( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_job_rest_bad_request( + transport: str = "rest", request_type=gcr_job.CreateJobRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["job"] = { + "name": "name_value", + "uid": "uid_value", + "generation": 1068, + "labels": {}, + "annotations": {}, + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "delete_time": {}, + "expire_time": {}, + "creator": "creator_value", + "last_modifier": "last_modifier_value", + "client": "client_value", + "client_version": "client_version_value", + "launch_stage": 6, + "binary_authorization": { + "use_default": True, + "breakglass_justification": "breakglass_justification_value", + }, + "template": { + "labels": {}, + "annotations": {}, + "parallelism": 1174, + "task_count": 1083, + "template": { + "containers": [ + { + "name": "name_value", + "image": "image_value", + "command": ["command_value1", "command_value2"], + "args": ["args_value1", "args_value2"], + "env": [ + { + "name": "name_value", + "value": "value_value", + "value_source": { + "secret_key_ref": { + "secret": "secret_value", + "version": "version_value", + } + }, + } + ], + "resources": {"limits": {}, "cpu_idle": True}, + "ports": [{"name": "name_value", "container_port": 1511}], + "volume_mounts": [ + {"name": "name_value", "mount_path": "mount_path_value"} + ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, + } + ], + "volumes": [ + { + "name": "name_value", + "secret": { + "secret": "secret_value", + "items": [ + { + "path": "path_value", + "version": "version_value", + "mode": 421, + } + ], + "default_mode": 1257, + }, + "cloud_sql_instance": { + "instances": ["instances_value1", "instances_value2"] + }, + } + ], + "max_retries": 1187, + "timeout": {"seconds": 751, "nanos": 543}, + "service_account": "service_account_value", + "execution_environment": 1, + "encryption_key": "encryption_key_value", + "vpc_access": {"connector": "connector_value", "egress": 1}, + }, + }, + "observed_generation": 2021, + "terminal_condition": { + "type_": "type__value", + "state": 1, + "message": "message_value", + "last_transition_time": {}, + "severity": 1, + "reason": 1, + "revision_reason": 1, + "execution_reason": 1, + }, + "conditions": {}, + "execution_count": 1628, + "latest_created_execution": { + "name": "name_value", + "create_time": {}, + "completion_time": {}, + }, + "reconciling": True, + "etag": "etag_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_job(request) + + +def test_create_job_rest_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + job=gcr_job.Job(name="name_value"), + job_id="job_id_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_job(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/locations/*}/jobs" % client.transport._host, + args[1], + ) + + +def test_create_job_rest_flattened_error(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_job( + gcr_job.CreateJobRequest(), + parent="parent_value", + job=gcr_job.Job(name="name_value"), + job_id="job_id_value", + ) + + +def test_create_job_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.GetJobRequest, + dict, + ], +) +def test_get_job_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = job.Job( + name="name_value", + uid="uid_value", + generation=1068, + creator="creator_value", + last_modifier="last_modifier_value", + client="client_value", + client_version="client_version_value", + launch_stage=launch_stage_pb2.LaunchStage.UNIMPLEMENTED, + observed_generation=2021, + execution_count=1628, + reconciling=True, + etag="etag_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = job.Job.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_job(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, job.Job) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.creator == "creator_value" + assert response.last_modifier == "last_modifier_value" + assert response.client == "client_value" + assert response.client_version == "client_version_value" + assert response.launch_stage == launch_stage_pb2.LaunchStage.UNIMPLEMENTED + assert response.observed_generation == 2021 + assert response.execution_count == 1628 + assert response.reconciling is True + assert response.etag == "etag_value" + + +def test_get_job_rest_required_fields(request_type=job.GetJobRequest): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = job.Job() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = job.Job.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_job(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_job_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_job._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_job_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.JobsRestInterceptor, "post_get_job" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_get_job" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = job.GetJobRequest.pb(job.GetJobRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = job.Job.to_json(job.Job()) + + request = job.GetJobRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = job.Job() + + client.get_job( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_job_rest_bad_request( + transport: str = "rest", request_type=job.GetJobRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_job(request) + + +def test_get_job_rest_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = job.Job() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = job.Job.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_job(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/jobs/*}" % client.transport._host, + args[1], + ) + + +def test_get_job_rest_flattened_error(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_job( + job.GetJobRequest(), + name="name_value", + ) + + +def test_get_job_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.ListJobsRequest, + dict, + ], +) +def test_list_jobs_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = job.ListJobsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = job.ListJobsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_jobs(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListJobsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_jobs_rest_required_fields(request_type=job.ListJobsRequest): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_jobs._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_jobs._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + "show_deleted", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = job.ListJobsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = job.ListJobsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_jobs(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_jobs_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_jobs._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + "showDeleted", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_jobs_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.JobsRestInterceptor, "post_list_jobs" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_list_jobs" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = job.ListJobsRequest.pb(job.ListJobsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = job.ListJobsResponse.to_json(job.ListJobsResponse()) + + request = job.ListJobsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = job.ListJobsResponse() + + client.list_jobs( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_jobs_rest_bad_request( + transport: str = "rest", request_type=job.ListJobsRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_jobs(request) + + +def test_list_jobs_rest_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = job.ListJobsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = job.ListJobsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_jobs(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/locations/*}/jobs" % client.transport._host, + args[1], + ) + + +def test_list_jobs_rest_flattened_error(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_jobs( + job.ListJobsRequest(), + parent="parent_value", + ) + + +def test_list_jobs_rest_pager(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + job.Job(), + ], + next_page_token="abc", + ), + job.ListJobsResponse( + jobs=[], + next_page_token="def", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + ], + next_page_token="ghi", + ), + job.ListJobsResponse( + jobs=[ + job.Job(), + job.Job(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(job.ListJobsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/locations/sample2"} + + pager = client.list_jobs(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, job.Job) for i in results) + + pages = list(client.list_jobs(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcr_job.UpdateJobRequest, + dict, + ], +) +def test_update_job_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"job": {"name": "projects/sample1/locations/sample2/jobs/sample3"}} + request_init["job"] = { + "name": "projects/sample1/locations/sample2/jobs/sample3", + "uid": "uid_value", + "generation": 1068, + "labels": {}, + "annotations": {}, + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "delete_time": {}, + "expire_time": {}, + "creator": "creator_value", + "last_modifier": "last_modifier_value", + "client": "client_value", + "client_version": "client_version_value", + "launch_stage": 6, + "binary_authorization": { + "use_default": True, + "breakglass_justification": "breakglass_justification_value", + }, + "template": { + "labels": {}, + "annotations": {}, + "parallelism": 1174, + "task_count": 1083, + "template": { + "containers": [ + { + "name": "name_value", + "image": "image_value", + "command": ["command_value1", "command_value2"], + "args": ["args_value1", "args_value2"], + "env": [ + { + "name": "name_value", + "value": "value_value", + "value_source": { + "secret_key_ref": { + "secret": "secret_value", + "version": "version_value", + } + }, + } + ], + "resources": {"limits": {}, "cpu_idle": True}, + "ports": [{"name": "name_value", "container_port": 1511}], + "volume_mounts": [ + {"name": "name_value", "mount_path": "mount_path_value"} + ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, + } + ], + "volumes": [ + { + "name": "name_value", + "secret": { + "secret": "secret_value", + "items": [ + { + "path": "path_value", + "version": "version_value", + "mode": 421, + } + ], + "default_mode": 1257, + }, + "cloud_sql_instance": { + "instances": ["instances_value1", "instances_value2"] + }, + } + ], + "max_retries": 1187, + "timeout": {"seconds": 751, "nanos": 543}, + "service_account": "service_account_value", + "execution_environment": 1, + "encryption_key": "encryption_key_value", + "vpc_access": {"connector": "connector_value", "egress": 1}, + }, + }, + "observed_generation": 2021, + "terminal_condition": { + "type_": "type__value", + "state": 1, + "message": "message_value", + "last_transition_time": {}, + "severity": 1, + "reason": 1, + "revision_reason": 1, + "execution_reason": 1, + }, + "conditions": {}, + "execution_count": 1628, + "latest_created_execution": { + "name": "name_value", + "create_time": {}, + "completion_time": {}, + }, + "reconciling": True, + "etag": "etag_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_job(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_update_job_rest_required_fields(request_type=gcr_job.UpdateJobRequest): + transport_class = transports.JobsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_job._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "allow_missing", + "validate_only", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_job(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_job_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_job._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "allowMissing", + "validateOnly", + ) + ) + & set(("job",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_job_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.JobsRestInterceptor, "post_update_job" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_update_job" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcr_job.UpdateJobRequest.pb(gcr_job.UpdateJobRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcr_job.UpdateJobRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.update_job( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_job_rest_bad_request( + transport: str = "rest", request_type=gcr_job.UpdateJobRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"job": {"name": "projects/sample1/locations/sample2/jobs/sample3"}} + request_init["job"] = { + "name": "projects/sample1/locations/sample2/jobs/sample3", + "uid": "uid_value", + "generation": 1068, + "labels": {}, + "annotations": {}, + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "delete_time": {}, + "expire_time": {}, + "creator": "creator_value", + "last_modifier": "last_modifier_value", + "client": "client_value", + "client_version": "client_version_value", + "launch_stage": 6, + "binary_authorization": { + "use_default": True, + "breakglass_justification": "breakglass_justification_value", + }, + "template": { + "labels": {}, + "annotations": {}, + "parallelism": 1174, + "task_count": 1083, + "template": { + "containers": [ + { + "name": "name_value", + "image": "image_value", + "command": ["command_value1", "command_value2"], + "args": ["args_value1", "args_value2"], + "env": [ + { + "name": "name_value", + "value": "value_value", + "value_source": { + "secret_key_ref": { + "secret": "secret_value", + "version": "version_value", + } + }, + } + ], + "resources": {"limits": {}, "cpu_idle": True}, + "ports": [{"name": "name_value", "container_port": 1511}], + "volume_mounts": [ + {"name": "name_value", "mount_path": "mount_path_value"} + ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, + } + ], + "volumes": [ + { + "name": "name_value", + "secret": { + "secret": "secret_value", + "items": [ + { + "path": "path_value", + "version": "version_value", + "mode": 421, + } + ], + "default_mode": 1257, + }, + "cloud_sql_instance": { + "instances": ["instances_value1", "instances_value2"] + }, + } + ], + "max_retries": 1187, + "timeout": {"seconds": 751, "nanos": 543}, + "service_account": "service_account_value", + "execution_environment": 1, + "encryption_key": "encryption_key_value", + "vpc_access": {"connector": "connector_value", "egress": 1}, + }, + }, + "observed_generation": 2021, + "terminal_condition": { + "type_": "type__value", + "state": 1, + "message": "message_value", + "last_transition_time": {}, + "severity": 1, + "reason": 1, + "revision_reason": 1, + "execution_reason": 1, + }, + "conditions": {}, + "execution_count": 1628, + "latest_created_execution": { + "name": "name_value", + "create_time": {}, + "completion_time": {}, + }, + "reconciling": True, + "etag": "etag_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_job(request) + + +def test_update_job_rest_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "job": {"name": "projects/sample1/locations/sample2/jobs/sample3"} + } + + # get truthy value for each flattened field + mock_args = dict( + job=gcr_job.Job(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_job(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{job.name=projects/*/locations/*/jobs/*}" % client.transport._host, + args[1], + ) + + +def test_update_job_rest_flattened_error(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_job( + gcr_job.UpdateJobRequest(), + job=gcr_job.Job(name="name_value"), + ) + + +def test_update_job_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.DeleteJobRequest, + dict, + ], +) +def test_delete_job_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_job(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_delete_job_rest_required_fields(request_type=job.DeleteJobRequest): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_job._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "etag", + "validate_only", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_job(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_job_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_job._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "etag", + "validateOnly", + ) + ) + & set(("name",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_job_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.JobsRestInterceptor, "post_delete_job" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_delete_job" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = job.DeleteJobRequest.pb(job.DeleteJobRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = job.DeleteJobRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.delete_job( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_delete_job_rest_bad_request( + transport: str = "rest", request_type=job.DeleteJobRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_job(request) + + +def test_delete_job_rest_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_job(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/jobs/*}" % client.transport._host, + args[1], + ) + + +def test_delete_job_rest_flattened_error(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_job( + job.DeleteJobRequest(), + name="name_value", + ) + + +def test_delete_job_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + job.RunJobRequest, + dict, + ], +) +def test_run_job_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.run_job(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_run_job_rest_required_fields(request_type=job.RunJobRequest): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).run_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).run_job._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.run_job(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_run_job_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.run_job._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_run_job_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.JobsRestInterceptor, "post_run_job" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_run_job" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = job.RunJobRequest.pb(job.RunJobRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = job.RunJobRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.run_job( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_run_job_rest_bad_request( + transport: str = "rest", request_type=job.RunJobRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.run_job(request) + + +def test_run_job_rest_flattened(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/locations/sample2/jobs/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.run_job(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/jobs/*}:run" % client.transport._host, + args[1], + ) + + +def test_run_job_rest_flattened_error(transport: str = "rest"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.run_job( + job.RunJobRequest(), + name="name_value", + ) + + +def test_run_job_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + iam_policy_pb2.GetIamPolicyRequest, + dict, + ], +) +def test_get_iam_policy_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = policy_pb2.Policy( + version=774, + etag=b"etag_blob", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = return_value + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_iam_policy(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, policy_pb2.Policy) + assert response.version == 774 + assert response.etag == b"etag_blob" + + +def test_get_iam_policy_rest_required_fields( + request_type=iam_policy_pb2.GetIamPolicyRequest, +): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["resource"] = "" + request = request_type(**request_init) + pb_request = request + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_iam_policy._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["resource"] = "resource_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_iam_policy._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("options",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "resource" in jsonified_request + assert jsonified_request["resource"] == "resource_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = policy_pb2.Policy() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = return_value + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_iam_policy(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_iam_policy_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_iam_policy._get_unset_required_fields({}) + assert set(unset_fields) == (set(("options",)) & set(("resource",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_iam_policy_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.JobsRestInterceptor, "post_get_iam_policy" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_get_iam_policy" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = iam_policy_pb2.GetIamPolicyRequest() + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson(policy_pb2.Policy()) + + request = iam_policy_pb2.GetIamPolicyRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = policy_pb2.Policy() + + client.get_iam_policy( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_iam_policy_rest_bad_request( + transport: str = "rest", request_type=iam_policy_pb2.GetIamPolicyRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_iam_policy(request) + + +def test_get_iam_policy_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + iam_policy_pb2.SetIamPolicyRequest, + dict, + ], +) +def test_set_iam_policy_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = policy_pb2.Policy( + version=774, + etag=b"etag_blob", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = return_value + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.set_iam_policy(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, policy_pb2.Policy) + assert response.version == 774 + assert response.etag == b"etag_blob" + + +def test_set_iam_policy_rest_required_fields( + request_type=iam_policy_pb2.SetIamPolicyRequest, +): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["resource"] = "" + request = request_type(**request_init) + pb_request = request + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_iam_policy._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["resource"] = "resource_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_iam_policy._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "resource" in jsonified_request + assert jsonified_request["resource"] == "resource_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = policy_pb2.Policy() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = return_value + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.set_iam_policy(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_set_iam_policy_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.set_iam_policy._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "resource", + "policy", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_set_iam_policy_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.JobsRestInterceptor, "post_set_iam_policy" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_set_iam_policy" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = iam_policy_pb2.SetIamPolicyRequest() + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson(policy_pb2.Policy()) + + request = iam_policy_pb2.SetIamPolicyRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = policy_pb2.Policy() + + client.set_iam_policy( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_set_iam_policy_rest_bad_request( + transport: str = "rest", request_type=iam_policy_pb2.SetIamPolicyRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.set_iam_policy(request) + + +def test_set_iam_policy_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + iam_policy_pb2.TestIamPermissionsRequest, + dict, + ], +) +def test_test_iam_permissions_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = iam_policy_pb2.TestIamPermissionsResponse( + permissions=["permissions_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = return_value + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.test_iam_permissions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, iam_policy_pb2.TestIamPermissionsResponse) + assert response.permissions == ["permissions_value"] + + +def test_test_iam_permissions_rest_required_fields( + request_type=iam_policy_pb2.TestIamPermissionsRequest, +): + transport_class = transports.JobsRestTransport + + request_init = {} + request_init["resource"] = "" + request_init["permissions"] = "" + request = request_type(**request_init) + pb_request = request + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).test_iam_permissions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["resource"] = "resource_value" + jsonified_request["permissions"] = "permissions_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).test_iam_permissions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "resource" in jsonified_request + assert jsonified_request["resource"] == "resource_value" + assert "permissions" in jsonified_request + assert jsonified_request["permissions"] == "permissions_value" + + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = iam_policy_pb2.TestIamPermissionsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = return_value + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.test_iam_permissions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_test_iam_permissions_rest_unset_required_fields(): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.test_iam_permissions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "resource", + "permissions", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_test_iam_permissions_rest_interceptors(null_interceptor): + transport = transports.JobsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.JobsRestInterceptor(), + ) + client = JobsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.JobsRestInterceptor, "post_test_iam_permissions" + ) as post, mock.patch.object( + transports.JobsRestInterceptor, "pre_test_iam_permissions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = iam_policy_pb2.TestIamPermissionsRequest() + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + iam_policy_pb2.TestIamPermissionsResponse() + ) + + request = iam_policy_pb2.TestIamPermissionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = iam_policy_pb2.TestIamPermissionsResponse() + + client.test_iam_permissions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_test_iam_permissions_rest_bad_request( + transport: str = "rest", request_type=iam_policy_pb2.TestIamPermissionsRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "projects/sample1/locations/sample2/jobs/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.test_iam_permissions(request) + + +def test_test_iam_permissions_rest_error(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.JobsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.JobsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = JobsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.JobsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = JobsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = JobsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.JobsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = JobsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.JobsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = JobsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.JobsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.JobsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.JobsGrpcTransport, + transports.JobsGrpcAsyncIOTransport, + transports.JobsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = JobsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.JobsGrpcTransport, + ) + + +def test_jobs_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.JobsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_jobs_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.run_v2.services.jobs.transports.JobsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.JobsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_job", + "get_job", + "list_jobs", + "update_job", + "delete_job", + "run_job", + "get_iam_policy", + "set_iam_policy", + "test_iam_permissions", + "get_operation", + "delete_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_jobs_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.run_v2.services.jobs.transports.JobsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.JobsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +def test_jobs_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.run_v2.services.jobs.transports.JobsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.JobsTransport() + adc.assert_called_once() + + +def test_jobs_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + JobsClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.JobsGrpcTransport, + transports.JobsGrpcAsyncIOTransport, + ], +) +def test_jobs_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.JobsGrpcTransport, + transports.JobsGrpcAsyncIOTransport, + transports.JobsRestTransport, + ], +) +def test_jobs_transport_auth_gdch_credentials(transport_class): + host = "https://language.com" + api_audience_tests = [None, "https://language2.com"] + api_audience_expect = [host, "https://language2.com"] + for t, e in zip(api_audience_tests, api_audience_expect): + with mock.patch.object(google.auth, "default", autospec=True) as adc: + gdch_mock = mock.MagicMock() + type(gdch_mock).with_gdch_audience = mock.PropertyMock( + return_value=gdch_mock + ) + adc.return_value = (gdch_mock, None) + transport_class(host=host, api_audience=t) + gdch_mock.with_gdch_audience.assert_called_once_with(e) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.JobsGrpcTransport, grpc_helpers), + (transports.JobsGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +def test_jobs_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "run.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=["1", "2"], + default_host="run.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class", + [transports.JobsGrpcTransport, transports.JobsGrpcAsyncIOTransport], +) +def test_jobs_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = ga_credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + +def test_jobs_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.JobsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_jobs_rest_lro_client(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + "rest", + ], +) +def test_jobs_host_no_port(transport_name): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint="run.googleapis.com"), + transport=transport_name, + ) + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + "rest", + ], +) +def test_jobs_host_with_port(transport_name): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="run.googleapis.com:8000" + ), + transport=transport_name, + ) + assert client.transport._host == ( + "run.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_jobs_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = JobsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = JobsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_job._session + session2 = client2.transport.create_job._session + assert session1 != session2 + session1 = client1.transport.get_job._session + session2 = client2.transport.get_job._session + assert session1 != session2 + session1 = client1.transport.list_jobs._session + session2 = client2.transport.list_jobs._session + assert session1 != session2 + session1 = client1.transport.update_job._session + session2 = client2.transport.update_job._session + assert session1 != session2 + session1 = client1.transport.delete_job._session + session2 = client2.transport.delete_job._session + assert session1 != session2 + session1 = client1.transport.run_job._session + session2 = client2.transport.run_job._session + assert session1 != session2 + session1 = client1.transport.get_iam_policy._session + session2 = client2.transport.get_iam_policy._session + assert session1 != session2 + session1 = client1.transport.set_iam_policy._session + session2 = client2.transport.set_iam_policy._session + assert session1 != session2 + session1 = client1.transport.test_iam_permissions._session + session2 = client2.transport.test_iam_permissions._session + assert session1 != session2 + + +def test_jobs_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.JobsGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_jobs_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.JobsGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.JobsGrpcTransport, transports.JobsGrpcAsyncIOTransport], +) +def test_jobs_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.JobsGrpcTransport, transports.JobsGrpcAsyncIOTransport], +) +def test_jobs_transport_channel_mtls_with_adc(transport_class): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_jobs_grpc_lro_client(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.OperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_jobs_grpc_lro_async_client(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.OperationsAsyncClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_connector_path(): + project = "squid" + location = "clam" + connector = "whelk" + expected = "projects/{project}/locations/{location}/connectors/{connector}".format( + project=project, + location=location, + connector=connector, + ) + actual = JobsClient.connector_path(project, location, connector) + assert expected == actual + + +def test_parse_connector_path(): + expected = { + "project": "octopus", + "location": "oyster", + "connector": "nudibranch", + } + path = JobsClient.connector_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_connector_path(path) + assert expected == actual + + +def test_crypto_key_path(): + project = "cuttlefish" + location = "mussel" + key_ring = "winkle" + crypto_key = "nautilus" + expected = "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + actual = JobsClient.crypto_key_path(project, location, key_ring, crypto_key) + assert expected == actual + + +def test_parse_crypto_key_path(): + expected = { + "project": "scallop", + "location": "abalone", + "key_ring": "squid", + "crypto_key": "clam", + } + path = JobsClient.crypto_key_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_crypto_key_path(path) + assert expected == actual + + +def test_execution_path(): + project = "whelk" + location = "octopus" + job = "oyster" + execution = "nudibranch" + expected = "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}".format( + project=project, + location=location, + job=job, + execution=execution, + ) + actual = JobsClient.execution_path(project, location, job, execution) + assert expected == actual + + +def test_parse_execution_path(): + expected = { + "project": "cuttlefish", + "location": "mussel", + "job": "winkle", + "execution": "nautilus", + } + path = JobsClient.execution_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_execution_path(path) + assert expected == actual + + +def test_job_path(): + project = "scallop" + location = "abalone" + job = "squid" + expected = "projects/{project}/locations/{location}/jobs/{job}".format( + project=project, + location=location, + job=job, + ) + actual = JobsClient.job_path(project, location, job) + assert expected == actual + + +def test_parse_job_path(): + expected = { + "project": "clam", + "location": "whelk", + "job": "octopus", + } + path = JobsClient.job_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_job_path(path) + assert expected == actual + + +def test_secret_path(): + project = "oyster" + secret = "nudibranch" + expected = "projects/{project}/secrets/{secret}".format( + project=project, + secret=secret, + ) + actual = JobsClient.secret_path(project, secret) + assert expected == actual + + +def test_parse_secret_path(): + expected = { + "project": "cuttlefish", + "secret": "mussel", + } + path = JobsClient.secret_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_secret_path(path) + assert expected == actual + + +def test_secret_version_path(): + project = "winkle" + secret = "nautilus" + version = "scallop" + expected = "projects/{project}/secrets/{secret}/versions/{version}".format( + project=project, + secret=secret, + version=version, + ) + actual = JobsClient.secret_version_path(project, secret, version) + assert expected == actual + + +def test_parse_secret_version_path(): + expected = { + "project": "abalone", + "secret": "squid", + "version": "clam", + } + path = JobsClient.secret_version_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_secret_version_path(path) + assert expected == actual + + +def test_common_billing_account_path(): + billing_account = "whelk" + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = JobsClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "octopus", + } + path = JobsClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "oyster" + expected = "folders/{folder}".format( + folder=folder, + ) + actual = JobsClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "nudibranch", + } + path = JobsClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "cuttlefish" + expected = "organizations/{organization}".format( + organization=organization, + ) + actual = JobsClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "mussel", + } + path = JobsClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "winkle" + expected = "projects/{project}".format( + project=project, + ) + actual = JobsClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "nautilus", + } + path = JobsClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "scallop" + location = "abalone" + expected = "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + actual = JobsClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "squid", + "location": "clam", + } + path = JobsClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = JobsClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_with_default_client_info(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.JobsTransport, "_prep_wrapped_messages") as prep: + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.JobsTransport, "_prep_wrapped_messages") as prep: + transport_class = JobsClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object( + type(getattr(client.transport, "grpc_channel")), "close" + ) as close: + async with client: + close.assert_not_called() + close.assert_called_once() + + +def test_delete_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.DeleteOperationRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.DeleteOperationRequest, + dict, + ], +) +def test_delete_operation_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_delete_operation(transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_operation_async(transport: str = "grpc"): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_operation_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = None + + client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_operation_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_delete_operation_from_dict(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_delete_operation_from_dict_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_get_operation(transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_list_operations(transport: str = "grpc"): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + response = client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +@pytest.mark.asyncio +async def test_list_operations_async(transport: str = "grpc"): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_list_operations_field_headers(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = operations_pb2.ListOperationsResponse() + + client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_operations_field_headers_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_list_operations_from_dict(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + + response = client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_list_operations_from_dict_async(): + client = JobsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_transport_close(): + transports = { + "rest": "_session", + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + with mock.patch.object( + type(getattr(client.transport, close_name)), "close" + ) as close: + with client: + close.assert_not_called() + close.assert_called_once() + + +def test_client_ctx(): + transports = [ + "rest", + "grpc", + ] + for transport in transports: + client = JobsClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() + + +@pytest.mark.parametrize( + "client_class,transport_class", + [ + (JobsClient, transports.JobsGrpcTransport), + (JobsAsyncClient, transports.JobsGrpcAsyncIOTransport), + ], +) +def test_api_key_credentials(client_class, transport_class): + with mock.patch.object( + google.auth._default, "get_api_key_credentials", create=True + ) as get_api_key_credentials: + mock_cred = mock.Mock() + get_api_key_credentials.return_value = mock_cred + options = client_options.ClientOptions() + options.api_key = "api_key" + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=mock_cred, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) diff --git a/tests/unit/gapic/run_v2/test_revisions.py b/tests/unit/gapic/run_v2/test_revisions.py index c081633..da316d8 100644 --- a/tests/unit/gapic/run_v2/test_revisions.py +++ b/tests/unit/gapic/run_v2/test_revisions.py @@ -22,46 +22,47 @@ except ImportError: # pragma: NO COVER import mock -import grpc -from grpc.experimental import aio from collections.abc import Iterable -from google.protobuf import json_format import json import math -import pytest -from proto.marshal.rules.dates import DurationRule, TimestampRule -from proto.marshal.rules import wrappers -from requests import Response -from requests import Request, PreparedRequest -from requests.sessions import Session -from google.protobuf import json_format from google.api import launch_stage_pb2 # type: ignore +from google.api_core import ( + future, + gapic_v1, + grpc_helpers, + grpc_helpers_async, + operation, + operations_v1, + path_template, +) from google.api_core import client_options from google.api_core import exceptions as core_exceptions -from google.api_core import future -from google.api_core import gapic_v1 -from google.api_core import grpc_helpers -from google.api_core import grpc_helpers_async -from google.api_core import operation from google.api_core import operation_async # type: ignore -from google.api_core import operations_v1 -from google.api_core import path_template +import google.auth from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError -from google.cloud.run_v2.services.revisions import RevisionsAsyncClient -from google.cloud.run_v2.services.revisions import RevisionsClient -from google.cloud.run_v2.services.revisions import pagers -from google.cloud.run_v2.services.revisions import transports -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import k8s_min -from google.cloud.run_v2.types import revision -from google.cloud.run_v2.types import vendor_settings +from google.cloud.location import locations_pb2 from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore -import google.auth +import grpc +from grpc.experimental import aio +from proto.marshal.rules import wrappers +from proto.marshal.rules.dates import DurationRule, TimestampRule +import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session + +from google.cloud.run_v2.services.revisions import ( + RevisionsAsyncClient, + RevisionsClient, + pagers, + transports, +) +from google.cloud.run_v2.types import condition, k8s_min, revision, vendor_settings def client_cert_source_callback(): @@ -839,7 +840,7 @@ def test_get_revision_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = revision.GetRevisionRequest( - {"name": "projects/sample1/locations/sample2/sample3"} + **{"name": "projects/sample1/locations/sample2/sample3"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1034,7 +1035,7 @@ def test_list_revisions_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = revision.ListRevisionsRequest( - {"parent": "projects/sample1/locations/sample2/sample3"} + **{"parent": "projects/sample1/locations/sample2/sample3"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1410,7 +1411,7 @@ def test_delete_revision_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = revision.DeleteRevisionRequest( - {"name": "projects/sample1/locations/sample2/sample3"} + **{"name": "projects/sample1/locations/sample2/sample3"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1648,7 +1649,7 @@ def test_get_revision_rest_required_fields(request_type=revision.GetRevisionRequ response = client.get_revision(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -1922,7 +1923,7 @@ def test_list_revisions_rest_required_fields( response = client.list_revisions(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -2257,7 +2258,7 @@ def test_delete_revision_rest_required_fields( response = client.delete_revision(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -2565,6 +2566,9 @@ def test_revisions_base_transport(): "get_revision", "list_revisions", "delete_revision", + "get_operation", + "delete_operation", + "list_operations", ) for method in methods: with pytest.raises(NotImplementedError): @@ -3302,6 +3306,609 @@ async def test_transport_close_async(): close.assert_called_once() +def test_delete_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.DeleteOperationRequest +): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.DeleteOperationRequest, + dict, + ], +) +def test_delete_operation_rest(request_type): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_delete_operation(transport: str = "grpc"): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_operation_async(transport: str = "grpc"): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_operation_field_headers(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = None + + client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_operation_field_headers_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_delete_operation_from_dict(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_delete_operation_from_dict_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_get_operation(transport: str = "grpc"): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_field_headers(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_field_headers_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_list_operations(transport: str = "grpc"): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + response = client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +@pytest.mark.asyncio +async def test_list_operations_async(transport: str = "grpc"): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_list_operations_field_headers(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = operations_pb2.ListOperationsResponse() + + client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_operations_field_headers_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_list_operations_from_dict(): + client = RevisionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + + response = client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_list_operations_from_dict_async(): + client = RevisionsAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_transport_close(): transports = { "rest": "_session", diff --git a/tests/unit/gapic/run_v2/test_services.py b/tests/unit/gapic/run_v2/test_services.py index 910dae2..49477f4 100644 --- a/tests/unit/gapic/run_v2/test_services.py +++ b/tests/unit/gapic/run_v2/test_services.py @@ -22,44 +22,27 @@ except ImportError: # pragma: NO COVER import mock -import grpc -from grpc.experimental import aio from collections.abc import Iterable -from google.protobuf import json_format import json import math -import pytest -from proto.marshal.rules.dates import DurationRule, TimestampRule -from proto.marshal.rules import wrappers -from requests import Response -from requests import Request, PreparedRequest -from requests.sessions import Session -from google.protobuf import json_format from google.api import launch_stage_pb2 # type: ignore +from google.api_core import ( + future, + gapic_v1, + grpc_helpers, + grpc_helpers_async, + operation, + operations_v1, + path_template, +) from google.api_core import client_options from google.api_core import exceptions as core_exceptions -from google.api_core import future -from google.api_core import gapic_v1 -from google.api_core import grpc_helpers -from google.api_core import grpc_helpers_async -from google.api_core import operation from google.api_core import operation_async # type: ignore -from google.api_core import operations_v1 -from google.api_core import path_template +import google.auth from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError -from google.cloud.run_v2.services.services import ServicesAsyncClient -from google.cloud.run_v2.services.services import ServicesClient -from google.cloud.run_v2.services.services import pagers -from google.cloud.run_v2.services.services import transports -from google.cloud.run_v2.types import condition -from google.cloud.run_v2.types import k8s_min -from google.cloud.run_v2.types import revision_template -from google.cloud.run_v2.types import service -from google.cloud.run_v2.types import service as gcr_service -from google.cloud.run_v2.types import traffic_target -from google.cloud.run_v2.types import vendor_settings +from google.cloud.location import locations_pb2 from google.iam.v1 import iam_policy_pb2 # type: ignore from google.iam.v1 import options_pb2 # type: ignore from google.iam.v1 import policy_pb2 # type: ignore @@ -67,9 +50,27 @@ from google.oauth2 import service_account from google.protobuf import duration_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore from google.type import expr_pb2 # type: ignore -import google.auth +import grpc +from grpc.experimental import aio +from proto.marshal.rules import wrappers +from proto.marshal.rules.dates import DurationRule, TimestampRule +import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session + +from google.cloud.run_v2.services.services import ( + ServicesAsyncClient, + ServicesClient, + pagers, + transports, +) +from google.cloud.run_v2.types import condition, k8s_min, revision_template +from google.cloud.run_v2.types import service +from google.cloud.run_v2.types import service as gcr_service +from google.cloud.run_v2.types import traffic_target, vendor_settings def client_cert_source_callback(): @@ -779,7 +780,7 @@ def test_create_service_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = gcr_service.CreateServiceRequest( - {"parent": "projects/sample1/locations/sample2"} + **{"parent": "projects/sample1/locations/sample2"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1056,7 +1057,7 @@ def test_get_service_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = service.GetServiceRequest( - {"name": "projects/sample1/locations/sample2/sample3"} + **{"name": "projects/sample1/locations/sample2/sample3"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1251,7 +1252,7 @@ def test_list_services_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = service.ListServicesRequest( - {"parent": "projects/sample1/locations/sample2"} + **{"parent": "projects/sample1/locations/sample2"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1627,7 +1628,7 @@ def test_update_service_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = gcr_service.UpdateServiceRequest( - {"service": {"name": "projects/sample1/locations/sample2/sample3"}} + **{"service": {"name": "projects/sample1/locations/sample2/sample3"}} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1818,7 +1819,7 @@ def test_delete_service_routing_parameters(): # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. request = service.DeleteServiceRequest( - {"name": "projects/sample1/locations/sample2/sample3"} + **{"name": "projects/sample1/locations/sample2/sample3"} ) # Mock the actual call within the gRPC stub, and fake the request. @@ -2504,6 +2505,22 @@ def test_create_service_rest(request_type): "volume_mounts": [ {"name": "name_value", "mount_path": "mount_path_value"} ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, } ], "volumes": [ @@ -2674,6 +2691,7 @@ def test_create_service_rest_required_fields( "serviceId", "", ), + ("$alt", "json;enum-encoding=int"), ] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -2821,6 +2839,22 @@ def test_create_service_rest_bad_request( "volume_mounts": [ {"name": "name_value", "mount_path": "mount_path_value"} ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, } ], "volumes": [ @@ -3098,7 +3132,7 @@ def test_get_service_rest_required_fields(request_type=service.GetServiceRequest response = client.get_service(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -3365,7 +3399,7 @@ def test_list_services_rest_required_fields(request_type=service.ListServicesReq response = client.list_services(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -3650,6 +3684,22 @@ def test_update_service_rest(request_type): "volume_mounts": [ {"name": "name_value", "mount_path": "mount_path_value"} ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, } ], "volumes": [ @@ -3803,7 +3853,7 @@ def test_update_service_rest_required_fields( response = client.update_service(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -3946,6 +3996,22 @@ def test_update_service_rest_bad_request( "volume_mounts": [ {"name": "name_value", "mount_path": "mount_path_value"} ], + "working_dir": "working_dir_value", + "liveness_probe": { + "initial_delay_seconds": 2214, + "timeout_seconds": 1621, + "period_seconds": 1489, + "failure_threshold": 1812, + "http_get": { + "path": "path_value", + "http_headers": [ + {"name": "name_value", "value": "value_value"} + ], + }, + "tcp_socket": {"port": 453}, + "grpc": {"port": 453, "service": "service_value"}, + }, + "startup_probe": {}, } ], "volumes": [ @@ -4193,7 +4259,7 @@ def test_delete_service_rest_required_fields(request_type=service.DeleteServiceR response = client.delete_service(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -4469,7 +4535,7 @@ def test_get_iam_policy_rest_required_fields( response = client.get_iam_policy(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -4678,7 +4744,7 @@ def test_set_iam_policy_rest_required_fields( response = client.set_iam_policy(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -4897,7 +4963,7 @@ def test_test_iam_permissions_rest_required_fields( response = client.test_iam_permissions(request) - expected_params = [] + expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params @@ -5149,6 +5215,9 @@ def test_services_base_transport(): "get_iam_policy", "set_iam_policy", "test_iam_permissions", + "get_operation", + "delete_operation", + "list_operations", ) for method in methods: with pytest.raises(NotImplementedError): @@ -5901,6 +5970,609 @@ async def test_transport_close_async(): close.assert_called_once() +def test_delete_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.DeleteOperationRequest +): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.DeleteOperationRequest, + dict, + ], +) +def test_delete_operation_rest(request_type): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_delete_operation(transport: str = "grpc"): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_operation_async(transport: str = "grpc"): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_operation_field_headers(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = None + + client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_operation_field_headers_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_delete_operation_from_dict(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_delete_operation_from_dict_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_get_operation(transport: str = "grpc"): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_field_headers(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_field_headers_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_list_operations(transport: str = "grpc"): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + response = client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +@pytest.mark.asyncio +async def test_list_operations_async(transport: str = "grpc"): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_list_operations_field_headers(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = operations_pb2.ListOperationsResponse() + + client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_operations_field_headers_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_list_operations_from_dict(): + client = ServicesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + + response = client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_list_operations_from_dict_async(): + client = ServicesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_transport_close(): transports = { "rest": "_session", diff --git a/tests/unit/gapic/run_v2/test_tasks.py b/tests/unit/gapic/run_v2/test_tasks.py new file mode 100644 index 0000000..749895b --- /dev/null +++ b/tests/unit/gapic/run_v2/test_tasks.py @@ -0,0 +1,3524 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER + import mock + +from collections.abc import Iterable +import json +import math + +from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template +from google.api_core import client_options +from google.api_core import exceptions as core_exceptions +import google.auth +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.location import locations_pb2 +from google.longrunning import operations_pb2 +from google.oauth2 import service_account +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import json_format +from google.protobuf import timestamp_pb2 # type: ignore +import grpc +from grpc.experimental import aio +from proto.marshal.rules import wrappers +from proto.marshal.rules.dates import DurationRule, TimestampRule +import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session + +from google.cloud.run_v2.services.tasks import ( + TasksAsyncClient, + TasksClient, + pagers, + transports, +) +from google.cloud.run_v2.types import condition, k8s_min, task, vendor_settings + + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert TasksClient._get_default_mtls_endpoint(None) is None + assert TasksClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert ( + TasksClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint + ) + assert ( + TasksClient._get_default_mtls_endpoint(sandbox_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + TasksClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert TasksClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (TasksClient, "grpc"), + (TasksAsyncClient, "grpc_asyncio"), + (TasksClient, "rest"), + ], +) +def test_tasks_client_from_service_account_info(client_class, transport_name): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_info" + ) as factory: + factory.return_value = creds + info = {"valid": True} + client = client_class.from_service_account_info(info, transport=transport_name) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +@pytest.mark.parametrize( + "transport_class,transport_name", + [ + (transports.TasksGrpcTransport, "grpc"), + (transports.TasksGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.TasksRestTransport, "rest"), + ], +) +def test_tasks_client_service_account_always_use_jwt(transport_class, transport_name): + with mock.patch.object( + service_account.Credentials, "with_always_use_jwt_access", create=True + ) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=True) + use_jwt.assert_called_once_with(True) + + with mock.patch.object( + service_account.Credentials, "with_always_use_jwt_access", create=True + ) as use_jwt: + creds = service_account.Credentials(None, None, None) + transport = transport_class(credentials=creds, always_use_jwt_access=False) + use_jwt.assert_not_called() + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (TasksClient, "grpc"), + (TasksAsyncClient, "grpc_asyncio"), + (TasksClient, "rest"), + ], +) +def test_tasks_client_from_service_account_file(client_class, transport_name): + creds = ga_credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_file" + ) as factory: + factory.return_value = creds + client = client_class.from_service_account_file( + "dummy/file/path.json", transport=transport_name + ) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + client = client_class.from_service_account_json( + "dummy/file/path.json", transport=transport_name + ) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +def test_tasks_client_get_transport_class(): + transport = TasksClient.get_transport_class() + available_transports = [ + transports.TasksGrpcTransport, + transports.TasksRestTransport, + ] + assert transport in available_transports + + transport = TasksClient.get_transport_class("grpc") + assert transport == transports.TasksGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (TasksClient, transports.TasksGrpcTransport, "grpc"), + (TasksAsyncClient, transports.TasksGrpcAsyncIOTransport, "grpc_asyncio"), + (TasksClient, transports.TasksRestTransport, "rest"), + ], +) +@mock.patch.object( + TasksClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TasksClient) +) +@mock.patch.object( + TasksAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TasksAsyncClient) +) +def test_tasks_client_client_options(client_class, transport_class, transport_name): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(TasksClient, "get_transport_class") as gtc: + transport = transport_class(credentials=ga_credentials.AnonymousCredentials()) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(TasksClient, "get_transport_class") as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name, client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class(transport=transport_name) + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class(transport=transport_name) + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + # Check the case api_endpoint is provided + options = client_options.ClientOptions( + api_audience="https://language.googleapis.com" + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience="https://language.googleapis.com", + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (TasksClient, transports.TasksGrpcTransport, "grpc", "true"), + ( + TasksAsyncClient, + transports.TasksGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (TasksClient, transports.TasksGrpcTransport, "grpc", "false"), + ( + TasksAsyncClient, + transports.TasksGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + (TasksClient, transports.TasksRestTransport, "rest", "true"), + (TasksClient, transports.TasksRestTransport, "rest", "false"), + ], +) +@mock.patch.object( + TasksClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TasksClient) +) +@mock.patch.object( + TasksAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TasksAsyncClient) +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_tasks_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + options = client_options.ClientOptions( + client_cert_source=client_cert_source_callback + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class(transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize("client_class", [TasksClient, TasksAsyncClient]) +@mock.patch.object( + TasksClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TasksClient) +) +@mock.patch.object( + TasksAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TasksAsyncClient) +) +def test_tasks_client_get_mtls_endpoint_and_cert_source(client_class): + mock_client_cert_source = mock.Mock() + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source == mock_client_cert_source + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): + mock_client_cert_source = mock.Mock() + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=mock_client_cert_source, + ): + ( + api_endpoint, + cert_source, + ) = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source == mock_client_cert_source + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (TasksClient, transports.TasksGrpcTransport, "grpc"), + (TasksAsyncClient, transports.TasksGrpcAsyncIOTransport, "grpc_asyncio"), + (TasksClient, transports.TasksRestTransport, "rest"), + ], +) +def test_tasks_client_client_options_scopes( + client_class, transport_class, transport_name +): + # Check the case scopes are provided. + options = client_options.ClientOptions( + scopes=["1", "2"], + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,grpc_helpers", + [ + (TasksClient, transports.TasksGrpcTransport, "grpc", grpc_helpers), + ( + TasksAsyncClient, + transports.TasksGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + (TasksClient, transports.TasksRestTransport, "rest", None), + ], +) +def test_tasks_client_client_options_credentials_file( + client_class, transport_class, transport_name, grpc_helpers +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +def test_tasks_client_client_options_from_dict(): + with mock.patch( + "google.cloud.run_v2.services.tasks.transports.TasksGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = TasksClient(client_options={"api_endpoint": "squid.clam.whelk"}) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,grpc_helpers", + [ + (TasksClient, transports.TasksGrpcTransport, "grpc", grpc_helpers), + ( + TasksAsyncClient, + transports.TasksGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + ], +) +def test_tasks_client_create_channel_credentials_file( + client_class, transport_class, transport_name, grpc_helpers +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + ) + + # test that the credentials from file are saved and used as the credentials. + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel" + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + file_creds = ga_credentials.AnonymousCredentials() + load_creds.return_value = (file_creds, None) + adc.return_value = (creds, None) + client = client_class(client_options=options, transport=transport_name) + create_channel.assert_called_with( + "run.googleapis.com:443", + credentials=file_creds, + credentials_file=None, + quota_project_id=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=None, + default_host="run.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "request_type", + [ + task.GetTaskRequest, + dict, + ], +) +def test_get_task(request_type, transport: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = task.Task( + name="name_value", + uid="uid_value", + generation=1068, + job="job_value", + execution="execution_value", + max_retries=1187, + service_account="service_account_value", + execution_environment=vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1, + reconciling=True, + observed_generation=2021, + index=536, + retried=751, + encryption_key="encryption_key_value", + etag="etag_value", + ) + response = client.get_task(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == task.GetTaskRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, task.Task) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.job == "job_value" + assert response.execution == "execution_value" + assert response.max_retries == 1187 + assert response.service_account == "service_account_value" + assert ( + response.execution_environment + == vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1 + ) + assert response.reconciling is True + assert response.observed_generation == 2021 + assert response.index == 536 + assert response.retried == 751 + assert response.encryption_key == "encryption_key_value" + assert response.etag == "etag_value" + + +def test_get_task_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + client.get_task() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == task.GetTaskRequest() + + +@pytest.mark.asyncio +async def test_get_task_async( + transport: str = "grpc_asyncio", request_type=task.GetTaskRequest +): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + task.Task( + name="name_value", + uid="uid_value", + generation=1068, + job="job_value", + execution="execution_value", + max_retries=1187, + service_account="service_account_value", + execution_environment=vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1, + reconciling=True, + observed_generation=2021, + index=536, + retried=751, + encryption_key="encryption_key_value", + etag="etag_value", + ) + ) + response = await client.get_task(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == task.GetTaskRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, task.Task) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.job == "job_value" + assert response.execution == "execution_value" + assert response.max_retries == 1187 + assert response.service_account == "service_account_value" + assert ( + response.execution_environment + == vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1 + ) + assert response.reconciling is True + assert response.observed_generation == 2021 + assert response.index == 536 + assert response.retried == 751 + assert response.encryption_key == "encryption_key_value" + assert response.etag == "etag_value" + + +@pytest.mark.asyncio +async def test_get_task_async_from_dict(): + await test_get_task_async(request_type=dict) + + +def test_get_task_field_headers(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = task.GetTaskRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + call.return_value = task.Task() + client.get_task(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_task_field_headers_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = task.GetTaskRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(task.Task()) + await client.get_task(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_get_task_flattened(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = task.Task() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_task( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_get_task_flattened_error(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_task( + task.GetTaskRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_task_flattened_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_task), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = task.Task() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(task.Task()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_task( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_get_task_flattened_error_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_task( + task.GetTaskRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + task.ListTasksRequest, + dict, + ], +) +def test_list_tasks(request_type, transport: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = task.ListTasksResponse( + next_page_token="next_page_token_value", + ) + response = client.list_tasks(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == task.ListTasksRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTasksPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_tasks_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + client.list_tasks() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == task.ListTasksRequest() + + +@pytest.mark.asyncio +async def test_list_tasks_async( + transport: str = "grpc_asyncio", request_type=task.ListTasksRequest +): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + task.ListTasksResponse( + next_page_token="next_page_token_value", + ) + ) + response = await client.list_tasks(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == task.ListTasksRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTasksAsyncPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_tasks_async_from_dict(): + await test_list_tasks_async(request_type=dict) + + +def test_list_tasks_field_headers(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = task.ListTasksRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + call.return_value = task.ListTasksResponse() + client.list_tasks(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_tasks_field_headers_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = task.ListTasksRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + task.ListTasksResponse() + ) + await client.list_tasks(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "parent=parent_value", + ) in kw["metadata"] + + +def test_list_tasks_flattened(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = task.ListTasksResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_tasks( + parent="parent_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + + +def test_list_tasks_flattened_error(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_tasks( + task.ListTasksRequest(), + parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_tasks_flattened_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = task.ListTasksResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + task.ListTasksResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_tasks( + parent="parent_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_list_tasks_flattened_error_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_tasks( + task.ListTasksRequest(), + parent="parent_value", + ) + + +def test_list_tasks_pager(transport_name: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials, + transport=transport_name, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + task.Task(), + ], + next_page_token="abc", + ), + task.ListTasksResponse( + tasks=[], + next_page_token="def", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + ], + next_page_token="ghi", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_tasks(request={}) + + assert pager._metadata == metadata + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, task.Task) for i in results) + + +def test_list_tasks_pages(transport_name: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials, + transport=transport_name, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tasks), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + task.Task(), + ], + next_page_token="abc", + ), + task.ListTasksResponse( + tasks=[], + next_page_token="def", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + ], + next_page_token="ghi", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + ], + ), + RuntimeError, + ) + pages = list(client.list_tasks(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_tasks_async_pager(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_tasks), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + task.Task(), + ], + next_page_token="abc", + ), + task.ListTasksResponse( + tasks=[], + next_page_token="def", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + ], + next_page_token="ghi", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_tasks( + request={}, + ) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: # pragma: no branch + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, task.Task) for i in responses) + + +@pytest.mark.asyncio +async def test_list_tasks_async_pages(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_tasks), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + task.Task(), + ], + next_page_token="abc", + ), + task.ListTasksResponse( + tasks=[], + next_page_token="def", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + ], + next_page_token="ghi", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in ( + await client.list_tasks(request={}) + ).pages: # pragma: no branch + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + task.GetTaskRequest, + dict, + ], +) +def test_get_task_rest(request_type): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4/tasks/sample5" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = task.Task( + name="name_value", + uid="uid_value", + generation=1068, + job="job_value", + execution="execution_value", + max_retries=1187, + service_account="service_account_value", + execution_environment=vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1, + reconciling=True, + observed_generation=2021, + index=536, + retried=751, + encryption_key="encryption_key_value", + etag="etag_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = task.Task.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_task(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, task.Task) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.generation == 1068 + assert response.job == "job_value" + assert response.execution == "execution_value" + assert response.max_retries == 1187 + assert response.service_account == "service_account_value" + assert ( + response.execution_environment + == vendor_settings.ExecutionEnvironment.EXECUTION_ENVIRONMENT_GEN1 + ) + assert response.reconciling is True + assert response.observed_generation == 2021 + assert response.index == 536 + assert response.retried == 751 + assert response.encryption_key == "encryption_key_value" + assert response.etag == "etag_value" + + +def test_get_task_rest_required_fields(request_type=task.GetTaskRequest): + transport_class = transports.TasksRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_task._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_task._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = task.Task() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = task.Task.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_task(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_task_rest_unset_required_fields(): + transport = transports.TasksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_task._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_task_rest_interceptors(null_interceptor): + transport = transports.TasksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TasksRestInterceptor(), + ) + client = TasksClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.TasksRestInterceptor, "post_get_task" + ) as post, mock.patch.object( + transports.TasksRestInterceptor, "pre_get_task" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = task.GetTaskRequest.pb(task.GetTaskRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = task.Task.to_json(task.Task()) + + request = task.GetTaskRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = task.Task() + + client.get_task( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_task_rest_bad_request( + transport: str = "rest", request_type=task.GetTaskRequest +): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4/tasks/sample5" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_task(request) + + +def test_get_task_rest_flattened(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = task.Task() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4/tasks/sample5" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = task.Task.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_task(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/jobs/*/executions/*/tasks/*}" + % client.transport._host, + args[1], + ) + + +def test_get_task_rest_flattened_error(transport: str = "rest"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_task( + task.GetTaskRequest(), + name="name_value", + ) + + +def test_get_task_rest_error(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + task.ListTasksRequest, + dict, + ], +) +def test_list_tasks_rest(request_type): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = task.ListTasksResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = task.ListTasksResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_tasks(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTasksPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_tasks_rest_required_fields(request_type=task.ListTasksRequest): + transport_class = transports.TasksRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_tasks._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_tasks._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + "show_deleted", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = task.ListTasksResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = task.ListTasksResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_tasks(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_tasks_rest_unset_required_fields(): + transport = transports.TasksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_tasks._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + "showDeleted", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_tasks_rest_interceptors(null_interceptor): + transport = transports.TasksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TasksRestInterceptor(), + ) + client = TasksClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.TasksRestInterceptor, "post_list_tasks" + ) as post, mock.patch.object( + transports.TasksRestInterceptor, "pre_list_tasks" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = task.ListTasksRequest.pb(task.ListTasksRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = task.ListTasksResponse.to_json( + task.ListTasksResponse() + ) + + request = task.ListTasksRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = task.ListTasksResponse() + + client.list_tasks( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_tasks_rest_bad_request( + transport: str = "rest", request_type=task.ListTasksRequest +): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_tasks(request) + + +def test_list_tasks_rest_flattened(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = task.ListTasksResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = task.ListTasksResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_tasks(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/locations/*/jobs/*/executions/*}/tasks" + % client.transport._host, + args[1], + ) + + +def test_list_tasks_rest_flattened_error(transport: str = "rest"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_tasks( + task.ListTasksRequest(), + parent="parent_value", + ) + + +def test_list_tasks_rest_pager(transport: str = "rest"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + task.Task(), + ], + next_page_token="abc", + ), + task.ListTasksResponse( + tasks=[], + next_page_token="def", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + ], + next_page_token="ghi", + ), + task.ListTasksResponse( + tasks=[ + task.Task(), + task.Task(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(task.ListTasksResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = { + "parent": "projects/sample1/locations/sample2/jobs/sample3/executions/sample4" + } + + pager = client.list_tasks(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, task.Task) for i in results) + + pages = list(client.list_tasks(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TasksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TasksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TasksClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.TasksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = TasksClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = TasksClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TasksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TasksClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TasksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = TasksClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TasksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TasksGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TasksGrpcTransport, + transports.TasksGrpcAsyncIOTransport, + transports.TasksRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = TasksClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.TasksGrpcTransport, + ) + + +def test_tasks_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.TasksTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_tasks_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.run_v2.services.tasks.transports.TasksTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TasksTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "get_task", + "list_tasks", + "get_operation", + "delete_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_tasks_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.run_v2.services.tasks.transports.TasksTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TasksTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +def test_tasks_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.run_v2.services.tasks.transports.TasksTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TasksTransport() + adc.assert_called_once() + + +def test_tasks_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + TasksClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TasksGrpcTransport, + transports.TasksGrpcAsyncIOTransport, + ], +) +def test_tasks_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TasksGrpcTransport, + transports.TasksGrpcAsyncIOTransport, + transports.TasksRestTransport, + ], +) +def test_tasks_transport_auth_gdch_credentials(transport_class): + host = "https://language.com" + api_audience_tests = [None, "https://language2.com"] + api_audience_expect = [host, "https://language2.com"] + for t, e in zip(api_audience_tests, api_audience_expect): + with mock.patch.object(google.auth, "default", autospec=True) as adc: + gdch_mock = mock.MagicMock() + type(gdch_mock).with_gdch_audience = mock.PropertyMock( + return_value=gdch_mock + ) + adc.return_value = (gdch_mock, None) + transport_class(host=host, api_audience=t) + gdch_mock.with_gdch_audience.assert_called_once_with(e) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TasksGrpcTransport, grpc_helpers), + (transports.TasksGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +def test_tasks_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "run.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=["1", "2"], + default_host="run.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class", + [transports.TasksGrpcTransport, transports.TasksGrpcAsyncIOTransport], +) +def test_tasks_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = ga_credentials.AnonymousCredentials() + + # Check ssl_channel_credentials is used if provided. + with mock.patch.object(transport_class, "create_channel") as mock_create_channel: + mock_ssl_channel_creds = mock.Mock() + transport_class( + host="squid.clam.whelk", + credentials=cred, + ssl_channel_credentials=mock_ssl_channel_creds, + ) + mock_create_channel.assert_called_once_with( + "squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + +def test_tasks_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.TasksRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + "rest", + ], +) +def test_tasks_host_no_port(transport_name): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint="run.googleapis.com"), + transport=transport_name, + ) + assert client.transport._host == ( + "run.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + "rest", + ], +) +def test_tasks_host_with_port(transport_name): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="run.googleapis.com:8000" + ), + transport=transport_name, + ) + assert client.transport._host == ( + "run.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://run.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_tasks_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = TasksClient( + credentials=creds1, + transport=transport_name, + ) + client2 = TasksClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_task._session + session2 = client2.transport.get_task._session + assert session1 != session2 + session1 = client1.transport.list_tasks._session + session2 = client2.transport.list_tasks._session + assert session1 != session2 + + +def test_tasks_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TasksGrpcTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_tasks_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TasksGrpcAsyncIOTransport( + host="squid.clam.whelk", + channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.TasksGrpcTransport, transports.TasksGrpcAsyncIOTransport], +) +def test_tasks_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = ga_credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.TasksGrpcTransport, transports.TasksGrpcAsyncIOTransport], +) +def test_tasks_transport_channel_mtls_with_adc(transport_class): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=None, + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_connector_path(): + project = "squid" + location = "clam" + connector = "whelk" + expected = "projects/{project}/locations/{location}/connectors/{connector}".format( + project=project, + location=location, + connector=connector, + ) + actual = TasksClient.connector_path(project, location, connector) + assert expected == actual + + +def test_parse_connector_path(): + expected = { + "project": "octopus", + "location": "oyster", + "connector": "nudibranch", + } + path = TasksClient.connector_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_connector_path(path) + assert expected == actual + + +def test_crypto_key_path(): + project = "cuttlefish" + location = "mussel" + key_ring = "winkle" + crypto_key = "nautilus" + expected = "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + actual = TasksClient.crypto_key_path(project, location, key_ring, crypto_key) + assert expected == actual + + +def test_parse_crypto_key_path(): + expected = { + "project": "scallop", + "location": "abalone", + "key_ring": "squid", + "crypto_key": "clam", + } + path = TasksClient.crypto_key_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_crypto_key_path(path) + assert expected == actual + + +def test_execution_path(): + project = "whelk" + location = "octopus" + job = "oyster" + execution = "nudibranch" + expected = "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}".format( + project=project, + location=location, + job=job, + execution=execution, + ) + actual = TasksClient.execution_path(project, location, job, execution) + assert expected == actual + + +def test_parse_execution_path(): + expected = { + "project": "cuttlefish", + "location": "mussel", + "job": "winkle", + "execution": "nautilus", + } + path = TasksClient.execution_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_execution_path(path) + assert expected == actual + + +def test_job_path(): + project = "scallop" + location = "abalone" + job = "squid" + expected = "projects/{project}/locations/{location}/jobs/{job}".format( + project=project, + location=location, + job=job, + ) + actual = TasksClient.job_path(project, location, job) + assert expected == actual + + +def test_parse_job_path(): + expected = { + "project": "clam", + "location": "whelk", + "job": "octopus", + } + path = TasksClient.job_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_job_path(path) + assert expected == actual + + +def test_secret_path(): + project = "oyster" + secret = "nudibranch" + expected = "projects/{project}/secrets/{secret}".format( + project=project, + secret=secret, + ) + actual = TasksClient.secret_path(project, secret) + assert expected == actual + + +def test_parse_secret_path(): + expected = { + "project": "cuttlefish", + "secret": "mussel", + } + path = TasksClient.secret_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_secret_path(path) + assert expected == actual + + +def test_secret_version_path(): + project = "winkle" + secret = "nautilus" + version = "scallop" + expected = "projects/{project}/secrets/{secret}/versions/{version}".format( + project=project, + secret=secret, + version=version, + ) + actual = TasksClient.secret_version_path(project, secret, version) + assert expected == actual + + +def test_parse_secret_version_path(): + expected = { + "project": "abalone", + "secret": "squid", + "version": "clam", + } + path = TasksClient.secret_version_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_secret_version_path(path) + assert expected == actual + + +def test_task_path(): + project = "whelk" + location = "octopus" + job = "oyster" + execution = "nudibranch" + task = "cuttlefish" + expected = "projects/{project}/locations/{location}/jobs/{job}/executions/{execution}/tasks/{task}".format( + project=project, + location=location, + job=job, + execution=execution, + task=task, + ) + actual = TasksClient.task_path(project, location, job, execution, task) + assert expected == actual + + +def test_parse_task_path(): + expected = { + "project": "mussel", + "location": "winkle", + "job": "nautilus", + "execution": "scallop", + "task": "abalone", + } + path = TasksClient.task_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_task_path(path) + assert expected == actual + + +def test_common_billing_account_path(): + billing_account = "squid" + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = TasksClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = TasksClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "whelk" + expected = "folders/{folder}".format( + folder=folder, + ) + actual = TasksClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = TasksClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "oyster" + expected = "organizations/{organization}".format( + organization=organization, + ) + actual = TasksClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = TasksClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "cuttlefish" + expected = "projects/{project}".format( + project=project, + ) + actual = TasksClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = TasksClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "winkle" + location = "nautilus" + expected = "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + actual = TasksClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = TasksClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = TasksClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_with_default_client_info(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object(transports.TasksTransport, "_prep_wrapped_messages") as prep: + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object(transports.TasksTransport, "_prep_wrapped_messages") as prep: + transport_class = TasksClient.get_transport_class() + transport = transport_class( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + with mock.patch.object( + type(getattr(client.transport, "grpc_channel")), "close" + ) as close: + async with client: + close.assert_not_called() + close.assert_called_once() + + +def test_delete_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.DeleteOperationRequest +): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.DeleteOperationRequest, + dict, + ], +) +def test_delete_operation_rest(request_type): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2/operations/sample3"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2/operations/sample3"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_delete_operation(transport: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_operation_async(transport: str = "grpc"): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_operation_field_headers(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = None + + client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_operation_field_headers_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_delete_operation_from_dict(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_delete_operation_from_dict_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_get_operation(transport: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_field_headers(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_field_headers_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_list_operations(transport: str = "grpc"): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + response = client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +@pytest.mark.asyncio +async def test_list_operations_async(transport: str = "grpc"): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_list_operations_field_headers(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = operations_pb2.ListOperationsResponse() + + client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_operations_field_headers_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_list_operations_from_dict(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + + response = client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_list_operations_from_dict_async(): + client = TasksAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_transport_close(): + transports = { + "rest": "_session", + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + with mock.patch.object( + type(getattr(client.transport, close_name)), "close" + ) as close: + with client: + close.assert_not_called() + close.assert_called_once() + + +def test_client_ctx(): + transports = [ + "rest", + "grpc", + ] + for transport in transports: + client = TasksClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called() + + +@pytest.mark.parametrize( + "client_class,transport_class", + [ + (TasksClient, transports.TasksGrpcTransport), + (TasksAsyncClient, transports.TasksGrpcAsyncIOTransport), + ], +) +def test_api_key_credentials(client_class, transport_class): + with mock.patch.object( + google.auth._default, "get_api_key_credentials", create=True + ) as get_api_key_credentials: + mock_cred = mock.Mock() + get_api_key_credentials.return_value = mock_cred + options = client_options.ClientOptions() + options.api_key = "api_key" + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=mock_cred, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience=None, + )